Skip to content

Commit

Permalink
add @propery support
Browse files Browse the repository at this point in the history
  • Loading branch information
z4o4z committed May 16, 2023
1 parent c842fde commit 81e8540
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 4 deletions.
1 change: 1 addition & 0 deletions packages/css/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ export * from './style';
export * from './vars';
export { createContainer } from './container';
export * from './layer';
export * from './properties';
46 changes: 46 additions & 0 deletions packages/css/src/properties.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import type { AtRule } from 'csstype';

import { appendCss } from './adapter';
import { PropertySyntax } from './types';
import { getFileScope } from './fileScope';
import { generateIdentifier } from './identifier';
import cssesc from 'cssesc';
import {assertVarName} from './vars'

type PropertyOptions = {
syntax: PropertySyntax | Array<PropertySyntax>;
inherits: boolean;
initialValue?: string
};

const buildPropertyRule = ({ syntax, inherits, initialValue }: PropertyOptions): AtRule.Property => ({
syntax: `"${Array.isArray(syntax) ? syntax.join(' | ') : syntax}"`,
inherits: inherits ? 'true' : 'false',
initialValue,
})

export function createProperty(options: PropertyOptions, debugId?: string): string {
const cssPropertyName = cssesc(
generateIdentifier({
debugId,
debugFileName: false,
}),
{ isIdentifier: true },
);

appendCss({ type: 'property', name: `--${cssPropertyName}`, rule: buildPropertyRule(options) }, getFileScope());

return `var(--${cssPropertyName})`;
}

export function createGlobalProperty(name: string, options: PropertyOptions): string {
appendCss({ type: 'property', name: `--${name}`, rule: buildPropertyRule(options) }, getFileScope());

return `var(--${name})`;
}

export function property(varName: string): string {
assertVarName(varName);

return varName.replace(/^var\((--.*)\)$/, '$1');
}
15 changes: 15 additions & 0 deletions packages/css/src/transformCss.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type {
CSSSelectorBlock,
Composition,
WithQueries,
CSSPropertyBlock,
} from './types';
import { markCompositionUsed } from './adapter';
import { forEach, omit, mapKeys } from './utils';
Expand Down Expand Up @@ -119,6 +120,7 @@ class Stylesheet {
localClassNamesSearch: AhoCorasick;
composedClassLists: Array<{ identifier: string; regex: RegExp }>;
layers: Map<string, Array<string>>;
propertyRules: Array<CSSPropertyBlock>;

constructor(
localClassNames: Array<string>,
Expand All @@ -128,6 +130,7 @@ class Stylesheet {
this.conditionalRulesets = [new ConditionalRuleset()];
this.fontFaceRules = [];
this.keyframesRules = [];
this.propertyRules = [];
this.localClassNamesMap = new Map(
localClassNames.map((localClassName) => [localClassName, localClassName]),
);
Expand All @@ -150,6 +153,13 @@ class Stylesheet {

return;
}

if (root.type === 'property') {
this.propertyRules.push(root)

return;
}

if (root.type === 'keyframes') {
root.rule = Object.fromEntries(
Object.entries(root.rule).map(([keyframe, rule]) => {
Expand Down Expand Up @@ -573,6 +583,11 @@ class Stylesheet {
css.push(renderCss({ '@font-face': fontFaceRule }));
}

// Render property rules
for (const property of this.propertyRules) {
css.push(renderCss({ [`@property ${property.name}`]: property.rule }));
}

// Render keyframes
for (const keyframe of this.keyframesRules) {
css.push(renderCss({ [`@keyframes ${keyframe.name}`]: keyframe.rule }));
Expand Down
28 changes: 27 additions & 1 deletion packages/css/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,19 @@ export type CSSLayerDeclaration = {
name: string;
};

export type CSSPropertyBlock = {
type: 'property';
name: string;
rule: AtRule.Property
};

export type CSS =
| CSSStyleBlock
| CSSFontFaceBlock
| CSSKeyframesBlock
| CSSSelectorBlock
| CSSLayerDeclaration;
| CSSLayerDeclaration
| CSSPropertyBlock;

export type FileScope = {
packageName?: string;
Expand Down Expand Up @@ -147,3 +154,22 @@ export type ThemeVars<ThemeContract extends NullableTokens> = MapLeafNodes<
export type ClassNames = string | Array<ClassNames>;

export type ComplexStyleRule = StyleRule | Array<StyleRule | ClassNames>;

export type PropertySyntax =
| '<length>'
| '<number>'
| '<percentage>'
| '<length-percentage>'
| '<color>'
| '<image>'
| '<url>'
| '<integer>'
| '<angle>'
| '<time>'
| '<resolution>'
| '<transform-function>'
| '<custom-ident>'
| '<transform-list>'
| '*'
// needs this to make TS suggestions work
| (string & Record<never, never>);
10 changes: 7 additions & 3 deletions packages/css/src/vars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ export function createVar(debugId?: string): CSSVarFunction {
return `var(--${cssVarName})` as const;
}

export function assertVarName(value: unknown): asserts value is `var(--${string})` {
if (typeof value !== 'string' || !/^var\(--.*\)$/.test(value)) {
throw new Error(`Invalid variable name: ${value}`);
}
}

export function fallbackVar(
...values: [string, ...Array<string>]
): CSSVarFunction {
Expand All @@ -32,9 +38,7 @@ export function fallbackVar(
if (finalValue === '') {
finalValue = String(value);
} else {
if (typeof value !== 'string' || !/^var\(--.*\)$/.test(value)) {
throw new Error(`Invalid variable name: ${value}`);
}
assertVarName(value)

finalValue = value.replace(/\)$/, `, ${finalValue})`);
}
Expand Down

0 comments on commit 81e8540

Please sign in to comment.