@terrazzo/token-tools 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/dist/color.d.ts +1 -9
  2. package/dist/color.js.map +1 -1
  3. package/dist/css/boolean.d.ts +6 -0
  4. package/dist/css/boolean.js +12 -0
  5. package/dist/css/boolean.js.map +1 -0
  6. package/dist/css/border.d.ts +13 -0
  7. package/dist/css/border.js +30 -0
  8. package/dist/css/border.js.map +1 -0
  9. package/dist/css/color.d.ts +13 -0
  10. package/dist/css/color.js +72 -0
  11. package/dist/css/color.js.map +1 -0
  12. package/dist/css/cubic-bezier.d.ts +8 -0
  13. package/dist/css/cubic-bezier.js +11 -0
  14. package/dist/css/cubic-bezier.js.map +1 -0
  15. package/dist/css/dimension.d.ts +6 -0
  16. package/dist/css/dimension.js +12 -0
  17. package/dist/css/dimension.js.map +1 -0
  18. package/dist/css/duration.d.ts +6 -0
  19. package/dist/css/duration.js +12 -0
  20. package/dist/css/duration.js.map +1 -0
  21. package/dist/css/font-family.d.ts +7 -0
  22. package/dist/css/font-family.js +22 -0
  23. package/dist/css/font-family.js.map +1 -0
  24. package/dist/css/font-weight.d.ts +6 -0
  25. package/dist/css/font-weight.js +9 -0
  26. package/dist/css/font-weight.js.map +1 -0
  27. package/dist/css/gradient.d.ts +9 -0
  28. package/dist/css/gradient.js +24 -0
  29. package/dist/css/gradient.js.map +1 -0
  30. package/dist/css/index.d.ts +25 -162
  31. package/dist/css/index.js +93 -315
  32. package/dist/css/index.js.map +1 -1
  33. package/dist/css/lib.d.ts +24 -0
  34. package/dist/css/lib.js +36 -0
  35. package/dist/css/lib.js.map +1 -0
  36. package/dist/css/link.d.ts +6 -0
  37. package/dist/css/link.js +9 -0
  38. package/dist/css/link.js.map +1 -0
  39. package/dist/css/number.d.ts +6 -0
  40. package/dist/css/number.js +6 -0
  41. package/dist/css/number.js.map +1 -0
  42. package/dist/css/shadow.d.ts +14 -0
  43. package/dist/css/shadow.js +42 -0
  44. package/dist/css/shadow.js.map +1 -0
  45. package/dist/css/string.d.ts +6 -0
  46. package/dist/css/string.js +8 -0
  47. package/dist/css/string.js.map +1 -0
  48. package/dist/css/stroke-style.d.ts +7 -0
  49. package/dist/css/stroke-style.js +9 -0
  50. package/dist/css/stroke-style.js.map +1 -0
  51. package/dist/css/transition.d.ts +14 -0
  52. package/dist/css/transition.js +21 -0
  53. package/dist/css/transition.js.map +1 -0
  54. package/dist/css/typography.d.ts +7 -0
  55. package/dist/css/typography.js +38 -0
  56. package/dist/css/typography.js.map +1 -0
  57. package/dist/index.d.ts +2 -0
  58. package/dist/index.js +2 -0
  59. package/dist/index.js.map +1 -1
  60. package/dist/js/index.d.ts +12 -0
  61. package/dist/js/index.js +16 -0
  62. package/dist/js/index.js.map +1 -0
  63. package/dist/transform.d.ts +6 -0
  64. package/dist/transform.js +17 -0
  65. package/dist/transform.js.map +1 -0
  66. package/dist/types.d.ts +384 -0
  67. package/dist/types.js +2 -0
  68. package/dist/types.js.map +1 -0
  69. package/package.json +7 -5
  70. package/src/color.ts +1 -27
  71. package/src/css/boolean.ts +15 -0
  72. package/src/css/border.ts +46 -0
  73. package/src/css/color.ts +80 -0
  74. package/src/css/cubic-bezier.ts +23 -0
  75. package/src/css/dimension.ts +15 -0
  76. package/src/css/duration.ts +15 -0
  77. package/src/css/font-family.ts +32 -0
  78. package/src/css/font-weight.ts +12 -0
  79. package/src/css/gradient.ts +42 -0
  80. package/src/css/index.ts +105 -539
  81. package/src/css/lib.ts +54 -0
  82. package/src/css/link.ts +12 -0
  83. package/src/css/number.ts +9 -0
  84. package/src/css/shadow.ts +75 -0
  85. package/src/css/string.ts +11 -0
  86. package/src/css/stroke-style.ts +13 -0
  87. package/src/css/transition.ts +41 -0
  88. package/src/css/typography.ts +44 -0
  89. package/src/index.ts +2 -0
  90. package/src/js/index.ts +31 -0
  91. package/src/transform.ts +23 -0
  92. package/src/types.ts +524 -0
package/src/css/lib.ts ADDED
@@ -0,0 +1,54 @@
1
+ import { kebabCase } from 'scule';
2
+
3
+ /** Function that generates a var(…) statement */
4
+ export type IDGenerator = (id: string) => string;
5
+
6
+ export const defaultAliasTransform = (id: string) => `var(${makeCSSVar(id)})`;
7
+
8
+ /** Generate shorthand CSS for select token types */
9
+ export function generateShorthand({ $type, localID }: { $type: string; localID: string }): string | undefined {
10
+ switch ($type) {
11
+ case 'transition': {
12
+ return ['duration', 'delay', 'timing-function']
13
+ .map((p) => makeCSSVar(`${localID}-${p}`, { wrapVar: true }))
14
+ .join(' ');
15
+ }
16
+ // note: "typography" is not set in shorthand because it can often unset values unintentionally.
17
+ // @see https://developer.mozilla.org/en-US/docs/Web/CSS/font
18
+ }
19
+ }
20
+
21
+ /** Build object of alias values */
22
+ export function transformCompositeAlias<T extends {}>(
23
+ value: T,
24
+ { aliasOf, transformAlias = defaultAliasTransform }: { aliasOf: string; transformAlias?: IDGenerator },
25
+ ): Record<string, string> {
26
+ const output: Record<string, string> = {};
27
+ for (const key in value) {
28
+ output[kebabCase(key)] = transformAlias(`${aliasOf}-${key}`);
29
+ }
30
+ return output as Record<keyof T, string>;
31
+ }
32
+
33
+ const CSS_VAR_RE =
34
+ /(?:(\p{Uppercase_Letter}?\p{Lowercase_Letter}+|\p{Uppercase_Letter}+|\p{Number}+|[\u{80}-\u{10FFFF}]+|_)|.)/u;
35
+
36
+ export interface MakeCSSVarOptions {
37
+ /** Prefix with string */
38
+ prefix?: string;
39
+ /** Wrap with `var(…)` (default: false) */
40
+ wrapVar?: boolean;
41
+ }
42
+
43
+ /**
44
+ * Generate a valid CSS variable from any string
45
+ * Code by @dfrankland
46
+ */
47
+ export function makeCSSVar(name: string, { prefix, wrapVar = false }: MakeCSSVarOptions = {}): string {
48
+ let property = name.split(CSS_VAR_RE).filter(Boolean).join('-');
49
+ if (prefix && !property.startsWith(`${prefix}-`)) {
50
+ property = `${prefix}-${property}`;
51
+ }
52
+ const finalProperty = `--${property}`.toLocaleLowerCase();
53
+ return wrapVar ? `var(${finalProperty})` : finalProperty;
54
+ }
@@ -0,0 +1,12 @@
1
+ import { type IDGenerator, defaultAliasTransform } from './lib.js';
2
+
3
+ /** Convert link value to CSS */
4
+ export function transformLinkValue(
5
+ value: string,
6
+ { aliasOf, transformAlias = defaultAliasTransform }: { aliasOf?: string; transformAlias?: IDGenerator } = {},
7
+ ): string {
8
+ if (aliasOf) {
9
+ return transformAlias(aliasOf);
10
+ }
11
+ return `url("${value}")`;
12
+ }
@@ -0,0 +1,9 @@
1
+ import { type IDGenerator, defaultAliasTransform } from './lib.js';
2
+
3
+ /** Convert number value to CSS */
4
+ export function transformNumberValue(
5
+ value: number,
6
+ { aliasOf, transformAlias = defaultAliasTransform }: { aliasOf?: string; transformAlias?: IDGenerator } = {},
7
+ ): string {
8
+ return aliasOf ? transformAlias(aliasOf) : String(value);
9
+ }
@@ -0,0 +1,75 @@
1
+ import type { ShadowTokenNormalized, ShadowValueNormalized } from '../types';
2
+ import { transformColorValue } from './color.js';
3
+ import { transformDimensionValue } from './dimension.js';
4
+ import { type IDGenerator, defaultAliasTransform } from './lib.js';
5
+
6
+ /** Convert shadow subvalue to CSS */
7
+ export function transformShadowLayer(
8
+ value: ShadowValueNormalized,
9
+ {
10
+ color,
11
+ partialAliasOf,
12
+ transformAlias = defaultAliasTransform,
13
+ }: {
14
+ color: string;
15
+ partialAliasOf?: Partial<Record<keyof ShadowValueNormalized, string>>;
16
+ transformAlias?: IDGenerator;
17
+ },
18
+ ): string | Record<string, string> {
19
+ const offsetX = partialAliasOf?.offsetX
20
+ ? transformAlias(partialAliasOf.offsetX)
21
+ : transformDimensionValue(value.offsetX, { transformAlias });
22
+ const offsetY = partialAliasOf?.offsetY
23
+ ? transformAlias(partialAliasOf.offsetY)
24
+ : transformDimensionValue(value.offsetY, { transformAlias });
25
+ const blur = partialAliasOf?.blur
26
+ ? transformAlias(partialAliasOf.blur)
27
+ : transformDimensionValue(value.blur, { transformAlias });
28
+ const spread = partialAliasOf?.spread
29
+ ? transformAlias(partialAliasOf.spread)
30
+ : transformDimensionValue(value.spread, { transformAlias });
31
+
32
+ return [offsetX, offsetY, blur, spread, color].join(' ');
33
+ }
34
+
35
+ /** Convert shadow value to CSS */
36
+ export function transformShadowValue(
37
+ value: ShadowTokenNormalized['$value'],
38
+ {
39
+ aliasOf,
40
+ partialAliasOf,
41
+ transformAlias = defaultAliasTransform,
42
+ }: {
43
+ aliasOf?: string;
44
+ partialAliasOf?: Partial<Record<keyof ShadowValueNormalized, string>>[];
45
+ transformAlias?: IDGenerator;
46
+ } = {},
47
+ ): string | Record<string, string> {
48
+ if (aliasOf) {
49
+ return transformAlias(aliasOf);
50
+ }
51
+ const colors = value.map(({ color }, i) =>
52
+ partialAliasOf?.[i]?.color
53
+ ? transformAlias(partialAliasOf[i]!.color!)
54
+ : transformColorValue(color, { transformAlias }),
55
+ );
56
+ const isHDR = colors.some((c) => typeof c === 'object');
57
+
58
+ const formatShadow = (colorKey: string) =>
59
+ value
60
+ .map((v, i) =>
61
+ transformShadowLayer(v, {
62
+ color:
63
+ typeof colors[i] === 'string'
64
+ ? (colors[i] as string)
65
+ : colors[i]![colorKey as keyof (typeof colors)[number]]!,
66
+ partialAliasOf: partialAliasOf?.[i],
67
+ transformAlias,
68
+ }),
69
+ )
70
+ .join(', ');
71
+
72
+ return !isHDR
73
+ ? formatShadow('.')
74
+ : { '.': formatShadow('.'), srgb: formatShadow('srgb'), p3: formatShadow('p3'), rec2020: formatShadow('rec2020') };
75
+ }
@@ -0,0 +1,11 @@
1
+ import { type IDGenerator, defaultAliasTransform } from './lib.js';
2
+
3
+ /** Convert string value to CSS */
4
+ export function transformStringValue(
5
+ value: string | number | boolean,
6
+ { aliasOf, transformAlias = defaultAliasTransform }: { aliasOf?: string; transformAlias?: IDGenerator } = {},
7
+ ): string {
8
+ // this seems like a useless function—because it is—but this is a placeholder
9
+ // that can handle unexpected values in the future should any arise
10
+ return aliasOf ? transformAlias(aliasOf) : String(value);
11
+ }
@@ -0,0 +1,13 @@
1
+ import type { StrokeStyleValue } from '../types.js';
2
+ import { type IDGenerator, defaultAliasTransform } from './lib.js';
3
+
4
+ /** Convert strokeStyle value to CSS */
5
+ export function transformStrokeStyleValue(
6
+ value: string | StrokeStyleValue,
7
+ { aliasOf, transformAlias = defaultAliasTransform }: { aliasOf?: string; transformAlias?: IDGenerator } = {},
8
+ ): string {
9
+ if (aliasOf) {
10
+ return transformAlias(aliasOf);
11
+ }
12
+ return typeof value === 'string' ? value : 'dashed'; // CSS doesn’t have `dash-array`; it’s just "dashed"
13
+ }
@@ -0,0 +1,41 @@
1
+ import type { TransitionValueNormalized } from '../types.js';
2
+ import { transformCubicBezierValue } from './cubic-bezier.js';
3
+ import { transformDurationValue } from './duration.js';
4
+ import { type IDGenerator, defaultAliasTransform, transformCompositeAlias } from './lib.js';
5
+
6
+ /** Convert transition value to multiple CSS values */
7
+ export function transformTransitionValue(
8
+ value: TransitionValueNormalized,
9
+ {
10
+ aliasOf,
11
+ partialAliasOf,
12
+ transformAlias = defaultAliasTransform,
13
+ }: {
14
+ aliasOf?: string;
15
+ partialAliasOf?: Partial<Record<keyof typeof value, string>>;
16
+ transformAlias?: IDGenerator;
17
+ } = {},
18
+ ): {
19
+ duration: ReturnType<typeof transformDurationValue>;
20
+ delay: ReturnType<typeof transformDurationValue>;
21
+ 'timing-function': ReturnType<typeof transformCubicBezierValue>;
22
+ } {
23
+ if (aliasOf) {
24
+ return transformCompositeAlias(value, { aliasOf, transformAlias }) as {
25
+ duration: ReturnType<typeof transformDurationValue>;
26
+ delay: ReturnType<typeof transformDurationValue>;
27
+ 'timing-function': ReturnType<typeof transformCubicBezierValue>;
28
+ };
29
+ }
30
+ return {
31
+ duration: partialAliasOf?.duration
32
+ ? transformAlias(partialAliasOf.duration)
33
+ : transformDurationValue(value.duration, { transformAlias }),
34
+ delay: partialAliasOf?.delay
35
+ ? transformAlias(partialAliasOf.delay)
36
+ : transformDurationValue(value.delay, { transformAlias }),
37
+ 'timing-function': partialAliasOf?.timingFunction
38
+ ? transformAlias(partialAliasOf.timingFunction)
39
+ : transformCubicBezierValue(value.timingFunction, { transformAlias }),
40
+ };
41
+ }
@@ -0,0 +1,44 @@
1
+ import { kebabCase } from 'scule';
2
+ import { transformFontFamilyValue } from './font-family.js';
3
+ import { transformFontWeightValue } from './font-weight.js';
4
+ import { type IDGenerator, defaultAliasTransform, transformCompositeAlias } from './lib.js';
5
+ import { transformStringValue } from './string.js';
6
+
7
+ /** Convert typography value to multiple CSS values */
8
+ export function transformTypographyValue(
9
+ value: Record<string, string | string[]>,
10
+ {
11
+ aliasOf,
12
+ partialAliasOf,
13
+ transformAlias = defaultAliasTransform,
14
+ }: { aliasOf?: string; partialAliasOf?: Record<keyof typeof value, string>; transformAlias?: IDGenerator } = {},
15
+ ): Record<string, string> {
16
+ const output: Record<string, string> = {};
17
+ if (aliasOf) {
18
+ return transformCompositeAlias(value, { aliasOf, transformAlias });
19
+ }
20
+ for (const [property, subvalue] of Object.entries(value)) {
21
+ let transformedValue: string;
22
+ if (partialAliasOf?.[property]) {
23
+ transformedValue = transformAlias(partialAliasOf[property]!);
24
+ } else {
25
+ switch (property) {
26
+ case 'fontFamily': {
27
+ transformedValue = transformFontFamilyValue(subvalue as string[], { transformAlias });
28
+ break;
29
+ }
30
+ case 'fontSize':
31
+ case 'fontWeight': {
32
+ transformedValue = transformFontWeightValue(subvalue as string, { transformAlias });
33
+ break;
34
+ }
35
+ default: {
36
+ transformedValue = transformStringValue(subvalue as string, { transformAlias });
37
+ break;
38
+ }
39
+ }
40
+ }
41
+ output[kebabCase(property)] = transformedValue;
42
+ }
43
+ return output;
44
+ }
package/src/index.ts CHANGED
@@ -1,3 +1,5 @@
1
1
  export * from './color.js';
2
2
  export * from './id.js';
3
3
  export * from './string.js';
4
+ export * from './transform.js';
5
+ export * from './types.js';
@@ -0,0 +1,31 @@
1
+ import type { TokenNormalized } from '../types.js';
2
+
3
+ export interface TransformJSValueOptions {
4
+ mode: string;
5
+ /** indent space count */
6
+ indent?: number;
7
+ /** initial indent level */
8
+ startingIndent?: number;
9
+ }
10
+
11
+ /**
12
+ * Convert token value to a JS string via acorn/astring.
13
+ */
14
+ export function transformJSValue<T extends TokenNormalized>(
15
+ token: T,
16
+ { mode, indent = 2, startingIndent = 0 }: TransformJSValueOptions,
17
+ ) {
18
+ if (!(mode in token.mode)) {
19
+ return;
20
+ }
21
+ const indentStart = startingIndent > 0 ? ' '.repeat(startingIndent ?? 2) : '';
22
+
23
+ // note: since tokens are JSON-serializable to begin with, using
24
+ // JSON.stringify generates the same output as an AST parser/generator would
25
+ // but faster and without the added overhead (even acorn/astring leave object
26
+ // keys quoted).
27
+
28
+ // TODO: use @biomejs/js-api when it’s stable for pretty formatting
29
+
30
+ return JSON.stringify(token.mode[mode]!.$value, undefined, indent).replace(/\n/g, `\n${indentStart}`);
31
+ }
@@ -0,0 +1,23 @@
1
+ export interface CustomTransformOptions {
2
+ /** Token $type */
3
+ $type: string;
4
+ }
5
+
6
+ /** Give a user pertinent feedback if they override a transform incorrectly */
7
+ export function validateCustomTransform(value: unknown, { $type }: CustomTransformOptions) {
8
+ if (value) {
9
+ if ((typeof value !== 'string' && typeof value !== 'object') || Array.isArray(value)) {
10
+ throw new Error(
11
+ `transform(): expected string or Object of strings, received ${Array.isArray(value) ? 'Array' : typeof value}`,
12
+ );
13
+ }
14
+ switch ($type) {
15
+ case 'typography': {
16
+ if (typeof value !== 'object') {
17
+ throw new Error('transform(): typography tokens must be an object of keys');
18
+ }
19
+ break;
20
+ }
21
+ }
22
+ }
23
+ }