diff --git a/apps/nextjs-example/app/Card.tsx b/apps/nextjs-example/app/Card.tsx index 57aa3ce2..642528a1 100644 --- a/apps/nextjs-example/app/Card.tsx +++ b/apps/nextjs-example/app/Card.tsx @@ -8,8 +8,8 @@ import stylex from '@stylexjs/stylex'; import { globalTokens as $, spacing, text } from './globalTokens.stylex'; -import '@stylexjs/open-props/lib/colors.stylex'; import { colors } from '@stylexjs/open-props/lib/colors.stylex'; +import { tokens } from './CardTokens.stylex'; type Props = Readonly<{ title: string; @@ -20,15 +20,15 @@ type Props = Readonly<{ export default function Card({ title, body, href }: Props) { return ( -

- {title} +

+ {title}

-

{body}

+

{body}

); } @@ -65,12 +65,12 @@ const styles = stylex.create({ padding: spacing.sm, transitionProperty: 'background-color, border-color', transitionDuration: '400ms', - transform: { - default: 'translateX(0)', - ':hover span': 'translateX(4px)', - }, textAlign: 'center', textDecoration: 'none', + [tokens.arrowTransform]: { + default: 'translateX(0)', + ':hover': 'translateX(4px)', + }, }, h2: { color: colors.blue3, @@ -84,6 +84,7 @@ const styles = stylex.create({ span: { display: 'inline-block', transitionProperty: 'transform', + transform: tokens.arrowTransform, transitionDuration: { default: '200ms', [REDUCE_MOTION]: '0s', diff --git a/apps/nextjs-example/app/CardTokens.stylex.ts b/apps/nextjs-example/app/CardTokens.stylex.ts new file mode 100644 index 00000000..d07e3294 --- /dev/null +++ b/apps/nextjs-example/app/CardTokens.stylex.ts @@ -0,0 +1,5 @@ +import * as stylex from '@stylexjs/stylex'; + +export const tokens = stylex.defineVars({ + arrowTransform: 'translateX(0)', +}); diff --git a/apps/nextjs-example/typetests/theming1.tsx b/apps/nextjs-example/typetests/theming1.tsx index bda31c1d..dcd51134 100644 --- a/apps/nextjs-example/typetests/theming1.tsx +++ b/apps/nextjs-example/typetests/theming1.tsx @@ -21,10 +21,7 @@ import type { const DARK = '@media (prefers-color-scheme: dark)'; const buttonTokens = stylex.defineVars({ - bgColor: { - default: 'cyan', - [DARK]: 'navy', - }, + bgColor: 'cyan', textColor: { default: 'black', [DARK]: 'white', @@ -74,7 +71,11 @@ type TokensType = TokensFromVarGroup; }) satisfies TokensType; const correctTheme = stylex.createTheme(buttonTokens, { - bgColor: 'red', + bgColor: { + default: 'pink', + [DARK]: 'navy', + '@media (max-width: 700px)': 'red', + }, textColor: 'white', cornerRadius: '4px', paddingBlock: '4px', diff --git a/packages/eslint-plugin/src/stylex-valid-styles.js b/packages/eslint-plugin/src/stylex-valid-styles.js index 5a2d6c71..9e310391 100644 --- a/packages/eslint-plugin/src/stylex-valid-styles.js +++ b/packages/eslint-plugin/src/stylex-valid-styles.js @@ -2360,12 +2360,24 @@ const stylexValidStyles = { ); } const key = style.key; + if (key.type === 'PrivateIdentifier') { + return context.report( + ({ + node: key, + loc: key.loc, + message: 'Private properties are not allowed in stylex', + }: Rule.ReportDescriptor), + ); + } const keyName = key.type === 'Literal' ? key.value : key.type === 'Identifier' && !style.computed ? key.name : null; + if (isStylexDefineVarsToken(key, stylexDefineVarsTokenImports)) { + return undefined; + } if ( typeof keyName !== 'string' || (key.type !== 'Literal' && key.type !== 'Identifier') diff --git a/packages/shared/src/preprocess-rules/flatten-raw-style-obj.js b/packages/shared/src/preprocess-rules/flatten-raw-style-obj.js index e7f74f38..643b8273 100644 --- a/packages/shared/src/preprocess-rules/flatten-raw-style-obj.js +++ b/packages/shared/src/preprocess-rules/flatten-raw-style-obj.js @@ -36,8 +36,11 @@ export function _flattenRawStyleObject( const flattened: Array< $ReadOnly<[string, AnyPreRule | PreIncludedStylesRule]>, > = []; - for (const key in style) { - const value = style[key]; + for (const _key in style) { + const value = style[_key]; + const key: string = _key.match(/var\(--[a-z0-9]+\)/) + ? _key.slice(4, -1) + : _key; // Included Styles if (typeof value === 'object' && value instanceof IncludedStyles) { diff --git a/packages/stylex/src/StyleXTypes.d.ts b/packages/stylex/src/StyleXTypes.d.ts index 62589397..84288370 100644 --- a/packages/stylex/src/StyleXTypes.d.ts +++ b/packages/stylex/src/StyleXTypes.d.ts @@ -22,14 +22,12 @@ export type StyleXClassName = StyleXClassNameFor; export type StyleXArray = T | ReadonlyArray>; declare const StyleXVarTag: unique symbol; -declare class StyleXVar extends String { +declare class _StyleXVar { private _opaque: typeof StyleXVarTag; private _value: Val; } +export type StyleXVar = _StyleXVar & string; -// Strings that don't start with a dollar sign. -// So that we can `&` with {$$css: true} without type errors. -type string = `${NonDollarChars}${string}`; type PseudoClassStr = `:${string}`; type AtRuleStr = `@${string}`; @@ -82,10 +80,10 @@ export type StyleXSingleStyle = false | (null | undefined | NestedCSSPropTypes); export type Keyframes = Readonly<{ [name: string]: CSSProperties }>; export type LegacyThemeStyles = Readonly<{ [constantName: string]: string }>; -type ComplexStyleValueType = T extends string | number | null - ? T - : T extends StyleXVar +type ComplexStyleValueType = T extends StyleXVar ? U + : T extends string | number | null + ? T : T extends ReadonlyArray ? U : T extends Readonly<{ default: infer A; [cond: CondStr]: infer B }> @@ -165,16 +163,16 @@ export type VarGroup< [Key in keyof Tokens]: StyleXVar; }> & Readonly<{ - $opaqueId: ID; - $tokens: Tokens; + __opaqueId: ID; + __tokens: Tokens; }> & typeof StyleXVarGroupTag; export type TokensFromVarGroup> = - T['$tokens']; + T['__tokens']; export type IDFromVarGroup> = - T['$opaqueId']; + T['__opaqueId']; type TTokens = Readonly<{ [key: string]: string | { [key: string]: string };