diff --git a/eslint.config.js b/eslint.config.js index 4766bd6..6cbd470 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -113,9 +113,12 @@ export default defineConfig([ 'unicorn/prevent-abbreviations': [ 'warn', { - allowList: { - args: true, - }, + ignore: [ + 'args', + /attrs/i, + /props/i, + // + ], }, ], }, diff --git a/etc/vicinage.api.md b/etc/vicinage.api.md index 407c74e..a0bcd62 100644 --- a/etc/vicinage.api.md +++ b/etc/vicinage.api.md @@ -24,6 +24,11 @@ export const sheet: (...styledeck: T) => T; // @public (undocumented) export type StyleDeck = StyleDeck[] | ~StyleCard | readonly [~StyleCard, InlineStyles] | Theme> | ~NonApplicableThemeProperties | ~NonApplicableObjectProperties | ~NonApplicableSymbolProperties | undefined; +// @internal (undocumented) +export function ~attrs(this: unknown, ...styles: any[]): ReturnType<(typeof stylex)['attrs']> extends infer T ? { + [Key in keyof T]: T[Key] | undefined; +} : never; + // @internal (undocumented) export type ~CommonProperties = Properties & Omit; diff --git a/package.json b/package.json index 23cf545..f08c01d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vicinage", - "version": "0.7.21", + "version": "0.7.22", "description": "Type-safe and zero-runtime UI styling, right in the markup.", "license": "MIT", "repository": { diff --git a/src/index.spec.ts b/src/index.spec.ts index ef21f61..4f6d5df 100644 --- a/src/index.spec.ts +++ b/src/index.spec.ts @@ -19,7 +19,7 @@ describe('mergeClassAttribute', () => { }) describe('mergeClassProperty', () => { - it('merges class attribute', () => { + it('merges class property', () => { expect( mergeClassProperty('foo bar', { className: 'quux', @@ -42,6 +42,20 @@ describe('mergeClassProperty', () => { }) }) +describe('attrs', () => { + it('returns attrs', () => { + expect( + attrs({ + '--fooBar': 'initial', + MozAnimation: 'auto', + }), + ).toStrictEqual({ + style: '--fooBar:initial;-moz-animation:auto', + }) + }) +}) + +import { '~attrs' as attrs } from './index.ts' import { describe } from 'vitest' import { expect } from 'vitest' import { it } from 'vitest' diff --git a/src/index.ts b/src/index.ts index 43aad09..164560f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,6 +2,7 @@ export { apply } export { sheet } export type { StyleDeck } +export { attrs as '~attrs' } export type { CommonProperties as '~CommonProperties' } export type { CompiledProperties as '~CompiledProperties' } export type { CompiledValue as '~CompiledValue' } @@ -28,6 +29,19 @@ export type { StylexProperties as '~StylexProperties' } /* eslint-disable @typescript-eslint/no-empty-object-type */ +/** + * @public + */ +type StyleDeck = + | StyleDeck[] + | StyleCard + | readonly [StyleCard, InlineStyles] + | Theme> + | NonApplicableThemeProperties + | NonApplicableObjectProperties + | NonApplicableSymbolProperties + | undefined + /** * @internal */ @@ -71,17 +85,53 @@ function mergeClassProperty( } /** - * @public + * @internal */ -type StyleDeck = - | StyleDeck[] - | StyleCard - | readonly [StyleCard, InlineStyles] - | Theme> - | NonApplicableThemeProperties - | NonApplicableObjectProperties - | NonApplicableSymbolProperties - | undefined +function attrs( + this: unknown, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ...styles: any[] +): ReturnType<(typeof stylex)['attrs']> extends infer T + ? { [Key in keyof T]: T[Key] | undefined } + : never { + const { + className, + style, + 'data-style-src': styleSource, + } = props.apply(this, styles) + + return { + ...(className == null + ? {} + : { + class: className, + }), + + ...(style == null + ? {} + : { + style: Object.entries(style) + .map(([key, value]) => { + if (key.startsWith('--')) { + return `${key}:${value.toString()}` + } + + return `${toKebabCase(key)}:${value.toString()}` + }) + .join(';'), + }), + + ...(styleSource == null + ? {} + : { + ['data-style-src']: styleSource, + }), + } +} + +function toKebabCase(text: string): string { + return text.replaceAll(/([A-Z])/g, '-$1').toLowerCase() +} /** * Apply styles as props `{ className, style }`, or attrs `{ class, style }`. @@ -364,6 +414,7 @@ import type { StyleXClassNameFor as ClassNameFor } from '@stylexjs/stylex' import type { CSSPropertiesWithExtras } from '@stylexjs/stylex/lib/types/StyleXTypes' import type { InlineStyles } from '@stylexjs/stylex' import type { Properties } from 'csstype' +import { props } from '@stylexjs/stylex' import type { Pseudos } from 'csstype' import type * as stylex from '@stylexjs/stylex' import type { StyleXVar } from '@stylexjs/stylex'