style-dictionary 5.3.2 → 5.4.0

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 (33) hide show
  1. package/examples/advanced/assets-base64-embed/package.json +1 -1
  2. package/examples/advanced/create-react-app/package.json +1 -1
  3. package/examples/advanced/create-react-native-app/package.json +1 -1
  4. package/examples/advanced/custom-parser/package.json +1 -1
  5. package/examples/advanced/custom-transforms/package.json +1 -1
  6. package/examples/advanced/font-face-rules/package.json +1 -1
  7. package/examples/advanced/format-helpers/package.json +1 -1
  8. package/examples/advanced/matching-build-files/package.json +1 -1
  9. package/examples/advanced/multi-brand-multi-platform/package.json +1 -1
  10. package/examples/advanced/node-modules-as-config-and-properties/package.json +1 -1
  11. package/examples/advanced/npm-module/package.json +1 -1
  12. package/examples/advanced/referencing_aliasing/package.json +1 -1
  13. package/examples/advanced/s3/package.json +1 -1
  14. package/examples/advanced/tailwind-preset/package.json +1 -1
  15. package/examples/advanced/tokens-deprecation/package.json +1 -1
  16. package/examples/advanced/transitive-transforms/package.json +1 -1
  17. package/examples/advanced/variables-in-outputs/package.json +1 -1
  18. package/examples/advanced/yaml-tokens/package.json +1 -1
  19. package/lib/StyleDictionary.js +1 -1
  20. package/lib/common/formatHelpers/getTypeScriptType.js +3 -1
  21. package/lib/common/transformGroups.d.ts +1 -1
  22. package/lib/common/transformGroups.js +2 -2
  23. package/lib/common/transforms.d.ts +69 -30
  24. package/lib/common/transforms.js +252 -114
  25. package/lib/enums/index.d.ts +1 -0
  26. package/lib/enums/index.js +1 -0
  27. package/lib/enums/tokenTypes.d.ts +4 -0
  28. package/lib/enums/tokenTypes.js +9 -0
  29. package/lib/enums/transforms.d.ts +1 -0
  30. package/lib/enums/transforms.js +1 -0
  31. package/package.json +8 -12
  32. package/types/TokenTypes.d.ts +6 -0
  33. package/types/index.d.ts +1 -0
@@ -12,6 +12,6 @@
12
12
  "author": "",
13
13
  "license": "Apache-2.0",
14
14
  "devDependencies": {
15
- "style-dictionary": "^5.3.2"
15
+ "style-dictionary": "^5.4.0"
16
16
  }
17
17
  }
@@ -12,7 +12,7 @@
12
12
  },
13
13
  "devDependencies": {
14
14
  "eslint-config-react-app": "^7.0.1",
15
- "style-dictionary": "^5.3.2"
15
+ "style-dictionary": "^5.4.0"
16
16
  },
17
17
  "resolutions": {
18
18
  "immer": "8.0.1",
@@ -29,7 +29,7 @@
29
29
  "eslint-config-react-app": "^7.0.1",
30
30
  "jest": "~25.2.6",
31
31
  "react-test-renderer": "~16.13.1",
32
- "style-dictionary": "^5.3.2"
32
+ "style-dictionary": "^5.4.0"
33
33
  },
34
34
  "jest": {
35
35
  "preset": "react-native"
@@ -10,6 +10,6 @@
10
10
  "author": "",
11
11
  "license": "Apache-2.0",
12
12
  "devDependencies": {
13
- "style-dictionary": "^5.3.2"
13
+ "style-dictionary": "^5.4.0"
14
14
  }
15
15
  }
@@ -16,6 +16,6 @@
16
16
  "author": "",
17
17
  "license": "Apache-2.0",
18
18
  "devDependencies": {
19
- "style-dictionary": "^5.3.2"
19
+ "style-dictionary": "^5.4.0"
20
20
  }
21
21
  }
@@ -9,6 +9,6 @@
9
9
  },
10
10
  "license": "Apache-2.0",
11
11
  "devDependencies": {
12
- "style-dictionary": "^5.3.2"
12
+ "style-dictionary": "^5.4.0"
13
13
  }
14
14
  }
@@ -11,6 +11,6 @@
11
11
  "author": "",
12
12
  "license": "Apache-2.0",
13
13
  "devDependencies": {
14
- "style-dictionary": "^5.3.2"
14
+ "style-dictionary": "^5.4.0"
15
15
  }
16
16
  }
@@ -17,6 +17,6 @@
17
17
  "author": "Kelly Harrop <kn.harrop@gmail.com>",
18
18
  "license": "Apache-2.0",
19
19
  "devDependencies": {
20
- "style-dictionary": "^5.3.2"
20
+ "style-dictionary": "^5.4.0"
21
21
  }
22
22
  }
@@ -16,6 +16,6 @@
16
16
  "author": "",
17
17
  "license": "Apache-2.0",
18
18
  "devDependencies": {
19
- "style-dictionary": "^5.3.2"
19
+ "style-dictionary": "^5.4.0"
20
20
  }
21
21
  }
@@ -20,7 +20,7 @@
20
20
  },
21
21
  "homepage": "https://github.com/dbanksdesign/style-dictionary-node#readme",
22
22
  "devDependencies": {
23
- "style-dictionary": "^5.3.2",
23
+ "style-dictionary": "^5.4.0",
24
24
  "tinycolor2": "^1.4.1"
25
25
  }
26
26
  }
@@ -17,6 +17,6 @@
17
17
  "author": "",
18
18
  "license": "Apache-2.0",
19
19
  "devDependencies": {
20
- "style-dictionary": "^5.3.2"
20
+ "style-dictionary": "^5.4.0"
21
21
  }
22
22
  }
@@ -16,6 +16,6 @@
16
16
  "author": "",
17
17
  "license": "Apache-2.0",
18
18
  "devDependencies": {
19
- "style-dictionary": "^5.3.2"
19
+ "style-dictionary": "^5.4.0"
20
20
  }
21
21
  }
@@ -16,6 +16,6 @@
16
16
  "devDependencies": {
17
17
  "aws-sdk": "^2.7.21",
18
18
  "fs-extra": "^1.0.0",
19
- "style-dictionary": "^5.3.2"
19
+ "style-dictionary": "^5.4.0"
20
20
  }
21
21
  }
@@ -10,7 +10,7 @@
10
10
  },
11
11
  "license": "Apache-2.0",
12
12
  "devDependencies": {
13
- "style-dictionary": "^5.3.2",
13
+ "style-dictionary": "^5.4.0",
14
14
  "tailwindcss": "^3.4.15",
15
15
  "mocha": "^10.2.0",
16
16
  "chai": "^5.1.1"
@@ -16,6 +16,6 @@
16
16
  "author": "",
17
17
  "license": "Apache-2.0",
18
18
  "devDependencies": {
19
- "style-dictionary": "^5.3.2"
19
+ "style-dictionary": "^5.4.0"
20
20
  }
21
21
  }
@@ -12,6 +12,6 @@
12
12
  "license": "ISC",
13
13
  "devDependencies": {
14
14
  "colorjs.io": "^0.5.2",
15
- "style-dictionary": "^5.3.2"
15
+ "style-dictionary": "^5.4.0"
16
16
  }
17
17
  }
@@ -11,6 +11,6 @@
11
11
  "author": "",
12
12
  "license": "MIT",
13
13
  "devDependencies": {
14
- "style-dictionary": "^5.3.2"
14
+ "style-dictionary": "^5.4.0"
15
15
  }
16
16
  }
@@ -10,7 +10,7 @@
10
10
  "author": "",
11
11
  "license": "Apache-2.0",
12
12
  "devDependencies": {
13
- "style-dictionary": "^5.3.2",
13
+ "style-dictionary": "^5.4.0",
14
14
  "yaml": "^1.10.0"
15
15
  }
16
16
  }
@@ -67,7 +67,7 @@ export default class StyleDictionary extends Register {
67
67
  // Placeholder is transformed on prepublish -> see scripts/inject-version.js
68
68
  // Another option might be import pkg from './package.json' with { "type": "json" } which would work in both browser and node, but support is not there yet.
69
69
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#browser_compatibility
70
- static VERSION = '5.3.2';
70
+ static VERSION = '5.4.0';
71
71
 
72
72
  /** @returns {Config} */
73
73
  get options() {
@@ -61,7 +61,9 @@ function getArrayType(arr) {
61
61
  if (arr.length > 0) {
62
62
  const firstValueType = getTypeScriptType(arr[0]);
63
63
  if (arr.every((v) => getTypeScriptType(v) === firstValueType)) {
64
- return firstValueType + '[]';
64
+ // generate a strict tuple with the values of the same type
65
+ // for example: [number, number, number, number]
66
+ return `[${Array.from(arr, () => firstValueType).join(',')}]`;
65
67
  } else {
66
68
  return `(${Array.from(
67
69
  new Set(
@@ -131,7 +131,7 @@ declare const _default: {
131
131
  *
132
132
  * @memberof TransformGroups
133
133
  */
134
- ios: ("attribute/cti" | "name/pascal" | "color/UIColor" | "size/remToPt" | "content/objC/literal" | "asset/objC/literal")[];
134
+ ios: ("attribute/cti" | "name/pascal" | "color/UIColor" | "size/remToFloat" | "content/objC/literal" | "asset/objC/literal")[];
135
135
  /**
136
136
  * Transforms:
137
137
  *
@@ -19,7 +19,7 @@ const {
19
19
  sizeRemToDp,
20
20
  sizePx,
21
21
  sizeRem,
22
- sizeRemToPt,
22
+ sizeRemToFloat,
23
23
  sizeComposeRemToSp,
24
24
  sizeComposeRemToDp,
25
25
  sizeComposeEm,
@@ -250,7 +250,7 @@ export default {
250
250
  colorUIColor,
251
251
  contentObjCLiteral,
252
252
  assetObjCLiteral,
253
- sizeRemToPt,
253
+ sizeRemToFloat,
254
254
  ],
255
255
  /**
256
256
  * Transforms:
@@ -31,6 +31,23 @@ export function getColorJS(val: DTCGColorValue | string): ColorJS;
31
31
  * @returns {boolean}
32
32
  */
33
33
  export function isColor(token: Token, options: Config): boolean;
34
+ /**
35
+ * Parse and normalize the value of a dimension Token
36
+ * as DTCG dimension value -> { value: 15, unit: 'em' }
37
+ *
38
+ * Note: the result could contain a unitless dimension
39
+ * Historically in Style Dictionary, number tokens were defined as unitless dimension tokens
40
+ * We can `deprecated` this and remove that in a breaking change, forcing users to change them to number tokens
41
+ * @param {Token['value']} val
42
+ *
43
+ * unit can be undefined for this utility method as well to support old dimension token values
44
+ * which can be defined as unitless dimension tokens or numbers
45
+ * @returns {{ value: number; unit: TokenTypeDimensionUnit | undefined }}
46
+ */
47
+ export function getTokenDimensionValue(val: Token["value"]): {
48
+ value: number;
49
+ unit: TokenTypeDimensionUnit | undefined;
50
+ };
34
51
  declare const _default: {
35
52
  /**
36
53
  * Adds: category, type, item, subitem, and state on the attributes object based on the location in the style dictionary.
@@ -459,7 +476,7 @@ declare const _default: {
459
476
  * ```js
460
477
  * // Matches: token.type === 'fontSize'
461
478
  * // Returns:
462
- * "10.0sp"
479
+ * "10.00sp"
463
480
  * ```
464
481
  *
465
482
  * @memberof Transforms
@@ -475,7 +492,7 @@ declare const _default: {
475
492
  * ```js
476
493
  * // Matches: token.type === 'dimension'
477
494
  * // Returns:
478
- * "10.0dp"
495
+ * "10.00dp"
479
496
  * ```
480
497
  *
481
498
  * @memberof Transforms
@@ -517,7 +534,7 @@ declare const _default: {
517
534
  * ```js
518
535
  * // Matches: token.type === 'fontSize'
519
536
  * // Returns:
520
- * "16.0sp"
537
+ * "16.00sp"
521
538
  * ```
522
539
  *
523
540
  * @memberof Transforms
@@ -528,12 +545,13 @@ declare const _default: {
528
545
  transform: (token: import("../../types/DesignToken.d.ts").TransformedToken, config: import("../../types/Config.d.ts").PlatformConfig, options: import("../../types/Config.d.ts").Config) => string;
529
546
  };
530
547
  /**
531
- * Transforms the value from a REM size on web into a density-independent pixel (dp) value for non font-sizes on Android. It WILL scale the number by a factor of 16 (or the value of 'basePxFontSize' on the platform in your config).
548
+ * Transforms the value from a REM size on web into a density-independent pixel (dp) value for non font-sizes on Android.
549
+ * It WILL scale the number by a factor of 16 (or the value of 'basePxFontSize' on the platform in your config).
532
550
  *
533
551
  * ```js
534
552
  * // Matches: token.type === 'dimension'
535
553
  * // Returns:
536
- * "16.0dp"
554
+ * "16.00dp"
537
555
  * ```
538
556
  *
539
557
  * @memberof Transforms
@@ -573,15 +591,31 @@ declare const _default: {
573
591
  "size/rem": {
574
592
  type: "value";
575
593
  filter: (token: import("../../types/DesignToken.d.ts").TransformedToken, options: import("../../types/Config.d.ts").Config) => boolean;
576
- transform: (token: import("../../types/DesignToken.d.ts").TransformedToken, _: import("../../types/Config.d.ts").PlatformConfig, options: import("../../types/Config.d.ts").Config) => any;
594
+ transform: (token: import("../../types/DesignToken.d.ts").TransformedToken, _: import("../../types/Config.d.ts").PlatformConfig, options: import("../../types/Config.d.ts").Config) => string | 0;
577
595
  };
578
596
  /**
579
- * Scales the number by 16 (or the value of 'basePxFontSize' on the platform in your config) and adds 'pt' to the end.
597
+ * Scales the number by 16 (or the value of 'basePxFontSize' on the platform in your config) and adds 'f' to the end.
580
598
  *
581
599
  * ```js
582
600
  * // Matches: token.type === 'dimension'
583
601
  * // Returns:
584
- * "16pt"
602
+ * "16.00f"
603
+ * ```
604
+ *
605
+ * @memberof Transforms
606
+ */
607
+ "size/remToFloat": {
608
+ type: "value";
609
+ filter: (token: import("../../types/DesignToken.d.ts").TransformedToken, options: import("../../types/Config.d.ts").Config) => boolean;
610
+ transform: (token: import("../../types/DesignToken.d.ts").TransformedToken, config: import("../../types/Config.d.ts").PlatformConfig, options: import("../../types/Config.d.ts").Config) => string;
611
+ };
612
+ /**
613
+ * Scales the number by 16 (or the value of 'basePxFontSize' on the platform in your config) and adds 'f' to the end.
614
+ *
615
+ * ```js
616
+ * // Matches: token.type === 'dimension'
617
+ * // Returns:
618
+ * "16.00pt"
585
619
  * ```
586
620
  *
587
621
  * @memberof Transforms
@@ -592,12 +626,13 @@ declare const _default: {
592
626
  transform: (token: import("../../types/DesignToken.d.ts").TransformedToken, config: import("../../types/Config.d.ts").PlatformConfig, options: import("../../types/Config.d.ts").Config) => string;
593
627
  };
594
628
  /**
595
- * Transforms the value from a REM size on web into a scale-independent pixel (sp) value for font sizes in Compose. It WILL scale the number by a factor of 16 (or the value of 'basePxFontSize' on the platform in your config).
629
+ * Transforms the value from a REM size on web into a scale-independent pixel (sp) value for font sizes in Compose.
630
+ * It WILL scale the number by a factor of 16 (or the value of 'basePxFontSize' on the platform in your config).
596
631
  *
597
632
  * ```kotlin
598
633
  * // Matches: token.type === 'fontSize'
599
634
  * // Returns:
600
- * "16.0.sp"
635
+ * "16.00.sp"
601
636
  * ```
602
637
  *
603
638
  * @memberof Transforms
@@ -613,7 +648,7 @@ declare const _default: {
613
648
  * ```kotlin
614
649
  * // Matches: token.type === 'dimension'
615
650
  * // Returns:
616
- * "16.0.dp"
651
+ * "16.00.dp"
617
652
  * ```
618
653
  *
619
654
  * @memberof Transforms
@@ -629,7 +664,7 @@ declare const _default: {
629
664
  * ```kotlin
630
665
  * // Matches: token.type === 'fontSize'
631
666
  * // Returns:
632
- * "16.0em"
667
+ * "16.em"
633
668
  * ```
634
669
  *
635
670
  * @memberof Transforms
@@ -645,7 +680,7 @@ declare const _default: {
645
680
  * ```kotlin
646
681
  * // Matches: token.type === 'fontSize'
647
682
  * // Returns:
648
- * "16.0.sp"
683
+ * "16.00.sp"
649
684
  * ```
650
685
  *
651
686
  * @memberof Transforms
@@ -661,7 +696,7 @@ declare const _default: {
661
696
  * ```kotlin
662
697
  * // Matches: token.type === 'dimension'
663
698
  * // Returns:
664
- * "16.0.dp"
699
+ * "16.00.dp"
665
700
  * ```
666
701
  *
667
702
  * @memberof Transforms
@@ -703,11 +738,13 @@ declare const _default: {
703
738
  transform: (token: import("../../types/DesignToken.d.ts").TransformedToken, config: import("../../types/Config.d.ts").PlatformConfig, options: import("../../types/Config.d.ts").Config) => string;
704
739
  };
705
740
  /**
706
- * Scales non-zero numbers to rem, and adds 'rem' to the end. If you define a "basePxFontSize" on the platform in your config, it will be used to scale the value, otherwise 16 (default web font size) will be used.
741
+ * Scales non-zero numbers to rem, and adds 'rem' to the end. If you define a "basePxFontSize" on the platform in your config,
742
+ * it will be used to scale the value, otherwise 16 (default web font size) will be used.
707
743
  *
708
744
  * ```js
709
745
  * // Matches: token.type === 'dimension'
710
746
  * // Returns:
747
+ * 0
711
748
  * "0"
712
749
  * "1rem"
713
750
  * ```
@@ -715,6 +752,21 @@ declare const _default: {
715
752
  * @memberof Transforms
716
753
  */
717
754
  "size/pxToRem": {
755
+ type: "value";
756
+ filter: (token: import("../../types/DesignToken.d.ts").TransformedToken, options: import("../../types/Config.d.ts").Config) => boolean;
757
+ transform: (token: import("../../types/DesignToken.d.ts").TransformedToken, config: import("../../types/Config.d.ts").PlatformConfig, options: import("../../types/Config.d.ts").Config) => string | 0;
758
+ };
759
+ /**
760
+ * Scales the number by 16 (or the value of 'basePxFontSize' on the platform in your config) to get to points for Flutter
761
+ *
762
+ * ```dart
763
+ * // Matches: token.type === 'dimension'
764
+ * // Returns: 16.00
765
+ * ```
766
+ *
767
+ * @memberof Transforms
768
+ */
769
+ "size/flutter/remToDouble": {
718
770
  type: "value";
719
771
  filter: (token: import("../../types/DesignToken.d.ts").TransformedToken, options: import("../../types/Config.d.ts").Config) => boolean;
720
772
  transform: (token: import("../../types/DesignToken.d.ts").TransformedToken, config: import("../../types/Config.d.ts").PlatformConfig, options: import("../../types/Config.d.ts").Config) => string;
@@ -1055,21 +1107,6 @@ declare const _default: {
1055
1107
  filter: typeof isAsset;
1056
1108
  transform: (token: import("../../types/DesignToken.d.ts").TransformedToken, _: import("../../types/Config.d.ts").PlatformConfig, options: import("../../types/Config.d.ts").Config) => string;
1057
1109
  };
1058
- /**
1059
- * Scales the number by 16 (or the value of 'basePxFontSize' on the platform in your config) to get to points for Flutter
1060
- *
1061
- * ```dart
1062
- * // Matches: token.type === 'dimension'
1063
- * // Returns: 16.00
1064
- * ```
1065
- *
1066
- * @memberof Transforms
1067
- */
1068
- "size/flutter/remToDouble": {
1069
- type: "value";
1070
- filter: (token: import("../../types/DesignToken.d.ts").TransformedToken, options: import("../../types/Config.d.ts").Config) => boolean;
1071
- transform: (token: import("../../types/DesignToken.d.ts").TransformedToken, config: import("../../types/Config.d.ts").PlatformConfig, options: import("../../types/Config.d.ts").Config) => string;
1072
- };
1073
1110
  };
1074
1111
  export default _default;
1075
1112
  export type Transform = import("../../types/Transform.d.ts").Transform;
@@ -1078,6 +1115,8 @@ export type DTCGColorValue = import("../../types/DesignToken.d.ts").DTCGColorVal
1078
1115
  export type DTCGColorSpace = import("../../types/DesignToken.d.ts").DTCGColorSpace;
1079
1116
  export type PlatformConfig = import("../../types/Config.d.ts").PlatformConfig;
1080
1117
  export type Config = import("../../types/Config.d.ts").Config;
1118
+ export type TokenTypeDimension = import("../../types/TokenTypes.d.ts").TokenTypeDimension;
1119
+ export type TokenTypeDimensionUnit = import("../../types/TokenTypes.d.ts").TokenTypeDimensionUnit;
1081
1120
  import Color from 'tinycolor2';
1082
1121
  import ColorJS from 'colorjs.io';
1083
1122
  /**
@@ -1,10 +1,10 @@
1
1
  import Color from 'tinycolor2';
2
2
  import ColorJS from 'colorjs.io';
3
+ import { camelCase, kebabCase, snakeCase } from 'change-case';
3
4
  import { join } from 'path-unified/posix';
4
- import { snakeCase, kebabCase, camelCase } from 'change-case';
5
+ import { transformTypes, transforms } from '../enums/index.js';
5
6
  import convertToBase64 from '../utils/convertToBase64.js';
6
7
  import GroupMessages from '../utils/groupMessages.js';
7
- import { transforms, transformTypes } from '../enums/index.js';
8
8
 
9
9
  /**
10
10
  * @typedef {import('../../types/Transform.d.ts').Transform} Transform
@@ -13,6 +13,9 @@ import { transforms, transformTypes } from '../enums/index.js';
13
13
  * @typedef {import('../../types/DesignToken.d.ts').DTCGColorSpace} DTCGColorSpace
14
14
  * @typedef {import('../../types/Config.d.ts').PlatformConfig} PlatformConfig
15
15
  * @typedef {import('../../types/Config.d.ts').Config} Config
16
+ * @typedef {import('../../types/TokenTypes.d.ts').TokenTypeDimension} TokenTypeDimension
17
+ * @typedef {import('../../types/TokenTypes.d.ts').TokenTypeDimensionUnit} TokenTypeDimensionUnit
18
+ *
16
19
  */
17
20
 
18
21
  const UNKNOWN_CSS_FONT_PROPS_WARNINGS = GroupMessages.GROUP.UnknownCSSFontProperties;
@@ -371,6 +374,52 @@ function transformCubicBezierCSS(token, options) {
371
374
  return transformEasing(val);
372
375
  }
373
376
 
377
+ /**
378
+ * Parse and normalize the value of a dimension Token
379
+ * as DTCG dimension value -> { value: 15, unit: 'em' }
380
+ *
381
+ * Note: the result could contain a unitless dimension
382
+ * Historically in Style Dictionary, number tokens were defined as unitless dimension tokens
383
+ * We can `deprecated` this and remove that in a breaking change, forcing users to change them to number tokens
384
+ * @param {Token['value']} val
385
+ *
386
+ * unit can be undefined for this utility method as well to support old dimension token values
387
+ * which can be defined as unitless dimension tokens or numbers
388
+ * @returns {{ value: number; unit: TokenTypeDimensionUnit | undefined }}
389
+ */
390
+ export function getTokenDimensionValue(val) {
391
+ /** @type {TokenTypeDimensionUnit | undefined} */
392
+ let unit;
393
+ const valueObj = typeof val === 'object' && !Array.isArray(val) && val !== null;
394
+
395
+ // old string dimension value
396
+ if (!valueObj) {
397
+ // if it contains a unit -> split it into unit and val
398
+ const unitMatch = `${val}`.match(/[^0-9.-]+$/);
399
+ if (unitMatch) {
400
+ unit = /** @type {TokenTypeDimensionUnit} */ (unitMatch[0]);
401
+ val = parseFloat(val.replace(/([^0-9]+$)/, ''));
402
+ }
403
+ val = parseFloat(val);
404
+ }
405
+
406
+ return valueObj
407
+ ? { value: val.value, unit: val.unit }
408
+ : { value: val, unit: unit ? unit : undefined };
409
+ }
410
+
411
+ /**
412
+ * @param {string | undefined} prop
413
+ * @returns
414
+ */
415
+ function normalizeDimensionProp(prop) {
416
+ if (prop !== undefined) {
417
+ const { value, unit } = getTokenDimensionValue(prop);
418
+ return `${value}${unit ?? ''}`;
419
+ }
420
+ return prop;
421
+ }
422
+
374
423
  /**
375
424
  * @namespace Transforms
376
425
  * @type {Record<string, Omit<Transform, 'name'>>}
@@ -975,7 +1024,7 @@ export default {
975
1024
  * ```js
976
1025
  * // Matches: token.type === 'fontSize'
977
1026
  * // Returns:
978
- * "10.0sp"
1027
+ * "10.00sp"
979
1028
  * ```
980
1029
  *
981
1030
  * @memberof Transforms
@@ -984,10 +1033,13 @@ export default {
984
1033
  type: value,
985
1034
  filter: isFontSize,
986
1035
  transform: function (token, _, options) {
987
- const nonParsedVal = options.usesDtcg ? token.$value : token.value;
988
- const val = parseFloat(nonParsedVal);
989
- if (isNaN(val)) throwSizeError(token.name, nonParsedVal, 'sp');
990
- return val.toFixed(2) + 'sp';
1036
+ const tokenVal = options.usesDtcg ? token.$value : token.value;
1037
+ const nonParsed = getTokenDimensionValue(tokenVal);
1038
+ const val = parseFloat(`${nonParsed.value}`);
1039
+ if (isNaN(val))
1040
+ throwSizeError(token.name, options.usesDtcg ? token.$value : token.value, 'sp');
1041
+
1042
+ return `${val.toFixed(2)}sp`;
991
1043
  },
992
1044
  },
993
1045
 
@@ -997,7 +1049,7 @@ export default {
997
1049
  * ```js
998
1050
  * // Matches: token.type === 'dimension'
999
1051
  * // Returns:
1000
- * "10.0dp"
1052
+ * "10.00dp"
1001
1053
  * ```
1002
1054
  *
1003
1055
  * @memberof Transforms
@@ -1006,10 +1058,13 @@ export default {
1006
1058
  type: value,
1007
1059
  filter: isDimension,
1008
1060
  transform: function (token, _, options) {
1009
- const nonParsedVal = options.usesDtcg ? token.$value : token.value;
1010
- const val = parseFloat(nonParsedVal);
1011
- if (isNaN(val)) throwSizeError(token.name, nonParsedVal, 'dp');
1012
- return val.toFixed(2) + 'dp';
1061
+ const tokenVal = options.usesDtcg ? token.$value : token.value;
1062
+ const nonParsed = getTokenDimensionValue(tokenVal);
1063
+ const val = parseFloat(`${nonParsed.value}`);
1064
+ if (isNaN(val))
1065
+ throwSizeError(token.name, options.usesDtcg ? token.$value : token.value, 'dp');
1066
+
1067
+ return `${val.toFixed(2)}dp`;
1013
1068
  },
1014
1069
  },
1015
1070
 
@@ -1033,12 +1088,14 @@ export default {
1033
1088
  type: value,
1034
1089
  filter: (token, options) => isDimension(token, options) || isFontSize(token, options),
1035
1090
  transform: function (token, config, options) {
1036
- const value = options.usesDtcg ? token.$value : token.value;
1037
- const parsedVal = parseFloat(value);
1038
- if (isNaN(parsedVal)) throwSizeError(token.name, value, 'object');
1091
+ const tokenVal = options.usesDtcg ? token.$value : token.value;
1092
+ const nonParsed = getTokenDimensionValue(tokenVal);
1093
+ const parsedVal = parseFloat(`${nonParsed.value}`);
1094
+ if (isNaN(parsedVal))
1095
+ throwSizeError(token.name, options.usesDtcg ? token.$value : token.value, 'object');
1039
1096
 
1040
1097
  return {
1041
- original: value,
1098
+ original: options.usesDtcg ? token.$value : token.value,
1042
1099
  number: parsedVal,
1043
1100
  decimal: parsedVal / 100,
1044
1101
  scale: parsedVal * getBasePxFontSize(config),
@@ -1052,7 +1109,7 @@ export default {
1052
1109
  * ```js
1053
1110
  * // Matches: token.type === 'fontSize'
1054
1111
  * // Returns:
1055
- * "16.0sp"
1112
+ * "16.00sp"
1056
1113
  * ```
1057
1114
  *
1058
1115
  * @memberof Transforms
@@ -1061,21 +1118,25 @@ export default {
1061
1118
  type: value,
1062
1119
  filter: isFontSize,
1063
1120
  transform: function (token, config, options) {
1064
- const value = options.usesDtcg ? token.$value : token.value;
1065
- const parsedVal = parseFloat(value);
1121
+ const tokenVal = options.usesDtcg ? token.$value : token.value;
1122
+ const nonParsed = getTokenDimensionValue(tokenVal);
1123
+ const parsedVal = parseFloat(`${nonParsed.value}`);
1066
1124
  const baseFont = getBasePxFontSize(config);
1067
- if (isNaN(parsedVal)) throwSizeError(token.name, value, 'sp');
1068
- return (parsedVal * baseFont).toFixed(2) + 'sp';
1125
+ if (isNaN(parsedVal))
1126
+ throwSizeError(token.name, options.usesDtcg ? token.$value : token.value, 'sp');
1127
+
1128
+ return `${(parsedVal * baseFont).toFixed(2)}sp`;
1069
1129
  },
1070
1130
  },
1071
1131
 
1072
1132
  /**
1073
- * Transforms the value from a REM size on web into a density-independent pixel (dp) value for non font-sizes on Android. It WILL scale the number by a factor of 16 (or the value of 'basePxFontSize' on the platform in your config).
1133
+ * Transforms the value from a REM size on web into a density-independent pixel (dp) value for non font-sizes on Android.
1134
+ * It WILL scale the number by a factor of 16 (or the value of 'basePxFontSize' on the platform in your config).
1074
1135
  *
1075
1136
  * ```js
1076
1137
  * // Matches: token.type === 'dimension'
1077
1138
  * // Returns:
1078
- * "16.0dp"
1139
+ * "16.00dp"
1079
1140
  * ```
1080
1141
  *
1081
1142
  * @memberof Transforms
@@ -1084,11 +1145,14 @@ export default {
1084
1145
  type: value,
1085
1146
  filter: isDimension,
1086
1147
  transform: function (token, config, options) {
1087
- const value = options.usesDtcg ? token.$value : token.value;
1088
- const parsedVal = parseFloat(value);
1148
+ const tokenVal = options.usesDtcg ? token.$value : token.value;
1149
+ const nonParsed = getTokenDimensionValue(tokenVal);
1150
+ const parsedVal = parseFloat(`${nonParsed.value}`);
1089
1151
  const baseFont = getBasePxFontSize(config);
1090
- if (isNaN(parsedVal)) throwSizeError(token.name, value, 'dp');
1091
- return (parsedVal * baseFont).toFixed(2) + 'dp';
1152
+ if (isNaN(parsedVal))
1153
+ throwSizeError(token.name, options.usesDtcg ? token.$value : token.value, 'dp');
1154
+
1155
+ return `${(parsedVal * baseFont).toFixed(2)}dp`;
1092
1156
  },
1093
1157
  },
1094
1158
 
@@ -1107,10 +1171,13 @@ export default {
1107
1171
  type: value,
1108
1172
  filter: (token, options) => isDimension(token, options) || isFontSize(token, options),
1109
1173
  transform: function (token, _, options) {
1110
- const value = options.usesDtcg ? token.$value : token.value;
1111
- const parsedVal = parseFloat(value);
1112
- if (isNaN(parsedVal)) throwSizeError(token.name, value, 'px');
1113
- return parsedVal + 'px';
1174
+ const tokenVal = options.usesDtcg ? token.$value : token.value;
1175
+ const nonParsed = getTokenDimensionValue(tokenVal);
1176
+ const parsedVal = parseFloat(`${nonParsed.value}`);
1177
+ if (isNaN(parsedVal))
1178
+ throwSizeError(token.name, options.usesDtcg ? token.$value : token.value, 'px');
1179
+
1180
+ return `${parsedVal}px`;
1114
1181
  },
1115
1182
  },
1116
1183
 
@@ -1129,29 +1196,53 @@ export default {
1129
1196
  type: value,
1130
1197
  filter: (token, options) => isDimension(token, options) || isFontSize(token, options),
1131
1198
  transform: function (token, _, options) {
1132
- const nonParsed = options.usesDtcg ? token.$value : token.value;
1133
- const parsedVal = parseFloat(nonParsed);
1134
-
1135
- if (isNaN(parsedVal)) throwSizeError(token.name, nonParsed, 'rem');
1136
-
1137
- // if the dimension already has a unit (non-digit / . period character or any arbitrary character)
1138
- if (`${nonParsed}`.match(/[^0-9.-]+$/)) {
1139
- return nonParsed;
1199
+ const tokenVal = options.usesDtcg ? token.$value : token.value;
1200
+ const nonParsed = getTokenDimensionValue(tokenVal);
1201
+ const parsedVal = parseFloat(`${nonParsed.value}`);
1202
+ if (isNaN(parsedVal))
1203
+ throwSizeError(token.name, options.usesDtcg ? token.$value : token.value, 'rem');
1204
+ if (parsedVal === 0) return 0;
1205
+ if (nonParsed.unit !== undefined) {
1206
+ return `${nonParsed.value}${nonParsed.unit}`;
1140
1207
  }
1141
1208
 
1142
- if (parsedVal === 0) return Number.isInteger(nonParsed) ? 0 : '0';
1209
+ return `${parsedVal}rem`;
1210
+ },
1211
+ },
1143
1212
 
1144
- return parsedVal + 'rem';
1213
+ /**
1214
+ * Scales the number by 16 (or the value of 'basePxFontSize' on the platform in your config) and adds 'f' to the end.
1215
+ *
1216
+ * ```js
1217
+ * // Matches: token.type === 'dimension'
1218
+ * // Returns:
1219
+ * "16.00f"
1220
+ * ```
1221
+ *
1222
+ * @memberof Transforms
1223
+ */
1224
+ [transforms.sizeRemToFloat]: {
1225
+ type: value,
1226
+ filter: (token, options) => isDimension(token, options) || isFontSize(token, options),
1227
+ transform: function (token, config, options) {
1228
+ const tokenVal = options.usesDtcg ? token.$value : token.value;
1229
+ const nonParsed = getTokenDimensionValue(tokenVal);
1230
+ const parsedVal = parseFloat(`${nonParsed.value}`);
1231
+ const baseFont = getBasePxFontSize(config);
1232
+
1233
+ if (isNaN(parsedVal))
1234
+ throwSizeError(token.name, options.usesDtcg ? token.$value : token.value, 'f');
1235
+ return `${(parsedVal * baseFont).toFixed(2)}f`;
1145
1236
  },
1146
1237
  },
1147
1238
 
1148
1239
  /**
1149
- * Scales the number by 16 (or the value of 'basePxFontSize' on the platform in your config) and adds 'pt' to the end.
1240
+ * Scales the number by 16 (or the value of 'basePxFontSize' on the platform in your config) and adds 'f' to the end.
1150
1241
  *
1151
1242
  * ```js
1152
1243
  * // Matches: token.type === 'dimension'
1153
1244
  * // Returns:
1154
- * "16pt"
1245
+ * "16.00pt"
1155
1246
  * ```
1156
1247
  *
1157
1248
  * @memberof Transforms
@@ -1160,21 +1251,25 @@ export default {
1160
1251
  type: value,
1161
1252
  filter: (token, options) => isDimension(token, options) || isFontSize(token, options),
1162
1253
  transform: function (token, config, options) {
1163
- const value = options.usesDtcg ? token.$value : token.value;
1164
- const parsedVal = parseFloat(value);
1254
+ const tokenVal = options.usesDtcg ? token.$value : token.value;
1255
+ const nonParsed = getTokenDimensionValue(tokenVal);
1256
+ const parsedVal = parseFloat(`${nonParsed.value}`);
1165
1257
  const baseFont = getBasePxFontSize(config);
1166
- if (isNaN(parsedVal)) throwSizeError(token.name, value, 'pt');
1167
- return (parsedVal * baseFont).toFixed(2) + 'f';
1258
+
1259
+ if (isNaN(parsedVal))
1260
+ throwSizeError(token.name, options.usesDtcg ? token.$value : token.value, 'pt');
1261
+ return `${(parsedVal * baseFont).toFixed(2)}pt`;
1168
1262
  },
1169
1263
  },
1170
1264
 
1171
1265
  /**
1172
- * Transforms the value from a REM size on web into a scale-independent pixel (sp) value for font sizes in Compose. It WILL scale the number by a factor of 16 (or the value of 'basePxFontSize' on the platform in your config).
1266
+ * Transforms the value from a REM size on web into a scale-independent pixel (sp) value for font sizes in Compose.
1267
+ * It WILL scale the number by a factor of 16 (or the value of 'basePxFontSize' on the platform in your config).
1173
1268
  *
1174
1269
  * ```kotlin
1175
1270
  * // Matches: token.type === 'fontSize'
1176
1271
  * // Returns:
1177
- * "16.0.sp"
1272
+ * "16.00.sp"
1178
1273
  * ```
1179
1274
  *
1180
1275
  * @memberof Transforms
@@ -1183,11 +1278,14 @@ export default {
1183
1278
  type: value,
1184
1279
  filter: isFontSize,
1185
1280
  transform: function (token, config, options) {
1186
- const value = options.usesDtcg ? token.$value : token.value;
1187
- const parsedVal = parseFloat(value);
1281
+ const tokenVal = options.usesDtcg ? token.$value : token.value;
1282
+ const nonParsed = getTokenDimensionValue(tokenVal);
1283
+ const parsedVal = parseFloat(`${nonParsed.value}`);
1188
1284
  const baseFont = getBasePxFontSize(config);
1189
- if (isNaN(parsedVal)) throwSizeError(token.name, value, 'sp');
1190
- return (parsedVal * baseFont).toFixed(2) + '.sp';
1285
+ if (isNaN(parsedVal))
1286
+ throwSizeError(token.name, options.usesDtcg ? token.$value : token.value, 'sp');
1287
+
1288
+ return `${(parsedVal * baseFont).toFixed(2)}.sp`;
1191
1289
  },
1192
1290
  },
1193
1291
 
@@ -1197,7 +1295,7 @@ export default {
1197
1295
  * ```kotlin
1198
1296
  * // Matches: token.type === 'dimension'
1199
1297
  * // Returns:
1200
- * "16.0.dp"
1298
+ * "16.00.dp"
1201
1299
  * ```
1202
1300
  *
1203
1301
  * @memberof Transforms
@@ -1206,11 +1304,14 @@ export default {
1206
1304
  type: value,
1207
1305
  filter: isDimension,
1208
1306
  transform: function (token, config, options) {
1209
- const value = options.usesDtcg ? token.$value : token.value;
1210
- const parsedVal = parseFloat(value);
1307
+ const tokenVal = options.usesDtcg ? token.$value : token.value;
1308
+ const nonParsed = getTokenDimensionValue(tokenVal);
1309
+ const parsedVal = parseFloat(`${nonParsed.value}`);
1211
1310
  const baseFont = getBasePxFontSize(config);
1212
- if (isNaN(parsedVal)) throwSizeError(token.name, value, 'dp');
1213
- return (parsedVal * baseFont).toFixed(2) + '.dp';
1311
+ if (isNaN(parsedVal))
1312
+ throwSizeError(token.name, options.usesDtcg ? token.$value : token.value, 'dp');
1313
+
1314
+ return `${(parsedVal * baseFont).toFixed(2)}.dp`;
1214
1315
  },
1215
1316
  },
1216
1317
 
@@ -1220,7 +1321,7 @@ export default {
1220
1321
  * ```kotlin
1221
1322
  * // Matches: token.type === 'fontSize'
1222
1323
  * // Returns:
1223
- * "16.0em"
1324
+ * "16.em"
1224
1325
  * ```
1225
1326
  *
1226
1327
  * @memberof Transforms
@@ -1229,10 +1330,13 @@ export default {
1229
1330
  type: value,
1230
1331
  filter: isFontSize,
1231
1332
  transform: function (token, _, options) {
1232
- const value = options.usesDtcg ? token.$value : token.value;
1233
- const parsedVal = parseFloat(value);
1234
- if (isNaN(parsedVal)) throwSizeError(token.name, value, 'em');
1235
- return parsedVal + '.em';
1333
+ const tokenVal = options.usesDtcg ? token.$value : token.value;
1334
+ const nonParsed = getTokenDimensionValue(tokenVal);
1335
+ const parsedVal = parseFloat(`${nonParsed.value}`);
1336
+ if (isNaN(parsedVal))
1337
+ throwSizeError(token.name, options.usesDtcg ? token.$value : token.value, 'em');
1338
+
1339
+ return `${parsedVal}.em`;
1236
1340
  },
1237
1341
  },
1238
1342
 
@@ -1242,7 +1346,7 @@ export default {
1242
1346
  * ```kotlin
1243
1347
  * // Matches: token.type === 'fontSize'
1244
1348
  * // Returns:
1245
- * "16.0.sp"
1349
+ * "16.00.sp"
1246
1350
  * ```
1247
1351
  *
1248
1352
  * @memberof Transforms
@@ -1251,10 +1355,13 @@ export default {
1251
1355
  type: value,
1252
1356
  filter: isFontSize,
1253
1357
  transform: function (token, _, options) {
1254
- const nonParsedVal = options.usesDtcg ? token.$value : token.value;
1255
- const val = parseFloat(nonParsedVal);
1256
- if (isNaN(val)) throwSizeError(token.name, nonParsedVal, 'sp');
1257
- return val.toFixed(2) + '.sp';
1358
+ const tokenVal = options.usesDtcg ? token.$value : token.value;
1359
+ const nonParsed = getTokenDimensionValue(tokenVal);
1360
+ const val = parseFloat(`${nonParsed.value}`);
1361
+ if (isNaN(val))
1362
+ throwSizeError(token.name, options.usesDtcg ? token.$value : token.value, 'sp');
1363
+
1364
+ return `${val.toFixed(2)}.sp`;
1258
1365
  },
1259
1366
  },
1260
1367
 
@@ -1264,7 +1371,7 @@ export default {
1264
1371
  * ```kotlin
1265
1372
  * // Matches: token.type === 'dimension'
1266
1373
  * // Returns:
1267
- * "16.0.dp"
1374
+ * "16.00.dp"
1268
1375
  * ```
1269
1376
  *
1270
1377
  * @memberof Transforms
@@ -1273,10 +1380,13 @@ export default {
1273
1380
  type: value,
1274
1381
  filter: isDimension,
1275
1382
  transform: function (token, _, options) {
1276
- const nonParsedVal = options.usesDtcg ? token.$value : token.value;
1277
- const val = parseFloat(nonParsedVal);
1278
- if (isNaN(val)) throwSizeError(token.name, nonParsedVal, 'dp');
1279
- return val.toFixed(2) + '.dp';
1383
+ const tokenVal = options.usesDtcg ? token.$value : token.value;
1384
+ const nonParsed = getTokenDimensionValue(tokenVal);
1385
+ const val = parseFloat(`${nonParsed.value}`);
1386
+ if (isNaN(val))
1387
+ throwSizeError(token.name, options.usesDtcg ? token.$value : token.value, 'dp');
1388
+
1389
+ return `${val.toFixed(2)}.dp`;
1280
1390
  },
1281
1391
  },
1282
1392
 
@@ -1294,10 +1404,13 @@ export default {
1294
1404
  type: value,
1295
1405
  filter: (token, options) => isDimension(token, options) || isFontSize(token, options),
1296
1406
  transform: function (token, config, options) {
1297
- const value = options.usesDtcg ? token.$value : token.value;
1298
- const parsedVal = parseFloat(value);
1407
+ const tokenVal = options.usesDtcg ? token.$value : token.value;
1408
+ const nonParsed = getTokenDimensionValue(tokenVal);
1409
+ const parsedVal = parseFloat(`${nonParsed.value}`);
1299
1410
  const baseFont = getBasePxFontSize(config);
1300
- if (isNaN(parsedVal)) throwSizeError(token.name, value, 'CGFloat');
1411
+ if (isNaN(parsedVal))
1412
+ throwSizeError(token.name, options.usesDtcg ? token.$value : token.value, 'CGFloat');
1413
+
1301
1414
  return `CGFloat(${(parsedVal * baseFont).toFixed(2)})`;
1302
1415
  },
1303
1416
  },
@@ -1317,20 +1430,25 @@ export default {
1317
1430
  type: value,
1318
1431
  filter: (token, options) => isDimension(token, options) || isFontSize(token, options),
1319
1432
  transform: function (token, config, options) {
1320
- const value = options.usesDtcg ? token.$value : token.value;
1321
- const parsedVal = parseFloat(value);
1433
+ const tokenVal = options.usesDtcg ? token.$value : token.value;
1434
+ const nonParsed = getTokenDimensionValue(tokenVal);
1435
+ const parsedVal = parseFloat(`${nonParsed.value}`);
1322
1436
  const baseFont = getBasePxFontSize(config);
1323
- if (isNaN(parsedVal)) throwSizeError(token.name, value, 'px');
1324
- return (parsedVal * baseFont).toFixed(0) + 'px';
1437
+ if (isNaN(parsedVal))
1438
+ throwSizeError(token.name, options.usesDtcg ? token.$value : token.value, 'px');
1439
+
1440
+ return `${(parsedVal * baseFont).toFixed(0)}px`;
1325
1441
  },
1326
1442
  },
1327
1443
 
1328
1444
  /**
1329
- * Scales non-zero numbers to rem, and adds 'rem' to the end. If you define a "basePxFontSize" on the platform in your config, it will be used to scale the value, otherwise 16 (default web font size) will be used.
1445
+ * Scales non-zero numbers to rem, and adds 'rem' to the end. If you define a "basePxFontSize" on the platform in your config,
1446
+ * it will be used to scale the value, otherwise 16 (default web font size) will be used.
1330
1447
  *
1331
1448
  * ```js
1332
1449
  * // Matches: token.type === 'dimension'
1333
1450
  * // Returns:
1451
+ * 0
1334
1452
  * "0"
1335
1453
  * "1rem"
1336
1454
  * ```
@@ -1341,19 +1459,40 @@ export default {
1341
1459
  type: value,
1342
1460
  filter: (token, options) => isDimension(token, options) || isFontSize(token, options),
1343
1461
  transform: (token, config, options) => {
1344
- const value = options.usesDtcg ? token.$value : token.value;
1345
- const parsedVal = parseFloat(value);
1462
+ const tokenVal = options.usesDtcg ? token.$value : token.value;
1463
+ const nonParsed = getTokenDimensionValue(tokenVal);
1464
+ const parsedVal = parseFloat(`${nonParsed.value}`);
1346
1465
  const baseFont = getBasePxFontSize(config);
1466
+ if (isNaN(parsedVal))
1467
+ throwSizeError(token.name, options.usesDtcg ? token.$value : token.value, 'rem');
1468
+ if (parsedVal === 0) return 0;
1347
1469
 
1348
- if (isNaN(parsedVal)) {
1349
- throwSizeError(token.name, value, 'rem');
1350
- }
1470
+ return `${parsedVal / baseFont}rem`;
1471
+ },
1472
+ },
1351
1473
 
1352
- if (parsedVal === 0) {
1353
- return '0';
1354
- }
1474
+ /**
1475
+ * Scales the number by 16 (or the value of 'basePxFontSize' on the platform in your config) to get to points for Flutter
1476
+ *
1477
+ * ```dart
1478
+ * // Matches: token.type === 'dimension'
1479
+ * // Returns: 16.00
1480
+ * ```
1481
+ *
1482
+ * @memberof Transforms
1483
+ */
1484
+ [transforms.sizeFlutterRemToDouble]: {
1485
+ type: value,
1486
+ filter: (token, options) => isDimension(token, options) || isFontSize(token, options),
1487
+ transform: function (token, config, options) {
1488
+ const tokenVal = options.usesDtcg ? token.$value : token.value;
1489
+ const nonParsed = getTokenDimensionValue(tokenVal);
1490
+ const baseFont = getBasePxFontSize(config);
1491
+ const parsedVal = parseFloat(`${nonParsed.value}`);
1492
+ if (isNaN(parsedVal))
1493
+ throwSizeError(token.name, options.usesDtcg ? token.$value : token.value, 'Number');
1355
1494
 
1356
- return `${parsedVal / baseFont}rem`;
1495
+ return (parsedVal * baseFont).toFixed(2);
1357
1496
  },
1358
1497
  },
1359
1498
 
@@ -1377,9 +1516,9 @@ export default {
1377
1516
  return (options.usesDtcg ? token.$value : token.value).replace(
1378
1517
  UNICODE_PATTERN,
1379
1518
  /**
1380
- * @param {string} match
1519
+ * @param {string} _
1381
1520
  * @param {string} variable */
1382
- function (match, variable) {
1521
+ function (_, variable) {
1383
1522
  return "'\\" + variable + "'";
1384
1523
  },
1385
1524
  );
@@ -1566,11 +1705,15 @@ export default {
1566
1705
  return val;
1567
1706
  }
1568
1707
  const colorStr = getColorStringFromTokenObjectValue(val);
1569
- const { width } = val;
1708
+ let { width } = val;
1709
+
1710
+ // normalize for DTCG dimension object values
1711
+ width = normalizeDimensionProp(width);
1570
1712
 
1571
1713
  // use fallback for style object value, since CSS does not allow
1572
1714
  // detailed control of the dash pattern or line caps on dashed borders
1573
1715
  // https://design-tokens.github.io/community-group/format/#example-fallback-for-object-stroke-style
1716
+ // this means we also don't have to take care of dashArray containing dimension object values
1574
1717
  let { style } = val;
1575
1718
  if (typeof style === 'object') {
1576
1719
  style = 'dashed';
@@ -1608,7 +1751,12 @@ export default {
1608
1751
  return val;
1609
1752
  }
1610
1753
  let { fontFamily } = val;
1611
- const { fontWeight, fontVariant, fontWidth, fontSize, fontStyle, lineHeight } = val;
1754
+ let { fontSize, lineHeight } = val;
1755
+ const { fontWeight, fontVariant, fontWidth, fontStyle } = val;
1756
+
1757
+ // normalize for DTCG dimension object values
1758
+ fontSize = normalizeDimensionProp(fontSize);
1759
+ lineHeight = normalizeDimensionProp(lineHeight);
1612
1760
 
1613
1761
  const CSSShorthandProps = [
1614
1762
  'fontStyle',
@@ -1663,6 +1811,7 @@ export default {
1663
1811
  // already transformed to string
1664
1812
  return val;
1665
1813
  }
1814
+ // TODO: add support for DTCG duration object value type
1666
1815
  const { duration, delay, timingFunction } = val;
1667
1816
 
1668
1817
  return `${duration} ${timingFunction} ${delay}`;
@@ -1699,7 +1848,15 @@ export default {
1699
1848
  if (typeof val !== 'object') {
1700
1849
  return val;
1701
1850
  }
1702
- const { inset, type, offsetX, offsetY, blur, spread } = val;
1851
+ const { inset, type } = val;
1852
+ let { offsetX, offsetY, blur, spread } = val;
1853
+
1854
+ // normalize for DTCG dimension object values
1855
+ offsetX = normalizeDimensionProp(offsetX);
1856
+ offsetY = normalizeDimensionProp(offsetY);
1857
+ blur = normalizeDimensionProp(blur);
1858
+ spread = normalizeDimensionProp(spread);
1859
+
1703
1860
  const colorStr = getColorStringFromTokenObjectValue(val);
1704
1861
  // `type` property will be deprecated (Tokens Studio compat) in the future and removed in v6
1705
1862
  return `${inset || type === 'inset' ? 'inset ' : ''}${offsetX ?? 0} ${offsetY ?? 0} ${blur ?? 0} ${
@@ -1855,23 +2012,4 @@ export default {
1855
2012
  filter: isAsset,
1856
2013
  transform: (token, _, options) => wrapValueWithDoubleQuote(token, options),
1857
2014
  },
1858
-
1859
- /**
1860
- * Scales the number by 16 (or the value of 'basePxFontSize' on the platform in your config) to get to points for Flutter
1861
- *
1862
- * ```dart
1863
- * // Matches: token.type === 'dimension'
1864
- * // Returns: 16.00
1865
- * ```
1866
- *
1867
- * @memberof Transforms
1868
- */
1869
- [transforms.sizeFlutterRemToDouble]: {
1870
- type: value,
1871
- filter: (token, options) => isDimension(token, options) || isFontSize(token, options),
1872
- transform: function (token, config, options) {
1873
- const baseFont = getBasePxFontSize(config);
1874
- return (parseFloat(options.usesDtcg ? token.$value : token.value) * baseFont).toFixed(2);
1875
- },
1876
- },
1877
2015
  };
@@ -8,6 +8,7 @@ export { logVerbosityLevels } from "./logVerbosityLevels.js";
8
8
  export { logWarningLevels } from "./logWarningLevels.js";
9
9
  export { propertyFormatNames } from "./propertyFormatNames.js";
10
10
  export { builtInSorts } from "./sorts.js";
11
+ export { dimensionUnit } from "./tokenTypes.js";
11
12
  export { transformGroups } from "./transformGroups.js";
12
13
  export { transforms } from "./transforms.js";
13
14
  export { transformTypes } from "./transformTypes.js";
@@ -8,6 +8,7 @@ export { logVerbosityLevels } from './logVerbosityLevels.js';
8
8
  export { logWarningLevels } from './logWarningLevels.js';
9
9
  export { propertyFormatNames } from './propertyFormatNames.js';
10
10
  export { builtInSorts } from './sorts.js';
11
+ export { dimensionUnit } from './tokenTypes.js';
11
12
  export { transformGroups } from './transformGroups.js';
12
13
  export { transforms } from './transforms.js';
13
14
  export { transformTypes } from './transformTypes.js';
@@ -0,0 +1,4 @@
1
+ export namespace dimensionUnit {
2
+ let px: "px";
3
+ let rem: "rem";
4
+ }
@@ -0,0 +1,9 @@
1
+ // TODO: add enum for token types
2
+ // TODO: add enums for token type -> values
3
+
4
+ // So far DTCG spec supports these units,
5
+ // although in Style Dictionary we allow more than these two.
6
+ export const dimensionUnit = {
7
+ px: /** @type {'px'} */ ('px'),
8
+ rem: /** @type {'rem'} */ ('rem'),
9
+ };
@@ -25,6 +25,7 @@ export namespace transforms {
25
25
  let sizeRemToDp: "size/remToDp";
26
26
  let sizePx: "size/px";
27
27
  let sizeRem: "size/rem";
28
+ let sizeRemToFloat: "size/remToFloat";
28
29
  let sizeRemToPt: "size/remToPt";
29
30
  let sizeComposeRemToSp: "size/compose/remToSp";
30
31
  let sizeComposeRemToDp: "size/compose/remToDp";
@@ -25,6 +25,7 @@ export const transforms = {
25
25
  sizeRemToDp: /** @type {'size/remToDp'} */ ('size/remToDp'),
26
26
  sizePx: /** @type {'size/px'} */ ('size/px'),
27
27
  sizeRem: /** @type {'size/rem'} */ ('size/rem'),
28
+ sizeRemToFloat: /** @type {'size/remToFloat'} */ ('size/remToFloat'),
28
29
  sizeRemToPt: /** @type {'size/remToPt'} */ ('size/remToPt'),
29
30
  sizeComposeRemToSp: /** @type {'size/compose/remToSp'} */ ('size/compose/remToSp'),
30
31
  sizeComposeRemToDp: /** @type {'size/compose/remToDp'} */ ('size/compose/remToDp'),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "style-dictionary",
3
- "version": "5.3.2",
3
+ "version": "5.4.0",
4
4
  "description": "Style once, use everywhere. A build system for creating cross-platform styles.",
5
5
  "keywords": [
6
6
  "style dictionary",
@@ -58,8 +58,8 @@
58
58
  "test:watch": "web-test-runner --watch",
59
59
  "test:coverage": "cd coverage/lcov-report && npx http-server -o -c-1",
60
60
  "test:update-snapshots": "web-test-runner --update-snapshots",
61
- "test:node": "mocha -r mocha-hooks.mjs './__integration__/**/*.test.js' './__tests__/**/*.test.js' './__node_tests__/**/*.test.js'",
62
- "test:perf": "mocha -r mocha-hooks.mjs './__perf_tests__/**/*.test.js'",
61
+ "test:node": "mocha -r mocha-hooks.mjs \"./__integration__/**/*.test.js\" \"./__tests__/**/*.test.js\" \"./__node_tests__/**/*.test.js\"",
62
+ "test:perf": "mocha -r mocha-hooks.mjs \"./__perf_tests__/**/*.test.js\"",
63
63
  "test:perf:debug": "web-test-runner --config wtr-perf.config.mjs --watch",
64
64
  "test:strip-types": "node --experimental-strip-types __tests__/strip-types-test.js",
65
65
  "install-cli": "npm install -g $(npm pack)",
@@ -117,7 +117,7 @@
117
117
  },
118
118
  "dependencies": {
119
119
  "@bundled-es-modules/deepmerge": "^4.3.1",
120
- "@bundled-es-modules/glob": "^13.0.3",
120
+ "@bundled-es-modules/glob": "^13.0.6",
121
121
  "@bundled-es-modules/memfs": "^4.17.0",
122
122
  "@zip.js/zip.js": "^2.7.44",
123
123
  "chalk": "^5.3.0",
@@ -150,7 +150,7 @@
150
150
  "@web/test-runner-playwright": "^0.11.0",
151
151
  "acorn": "^8.11.3",
152
152
  "astro": "^5.13.2",
153
- "chai": "^5.0.0-alpha.2",
153
+ "chai": "^6.2.2",
154
154
  "eslint": "^9.19.0",
155
155
  "eslint-plugin-mocha": "^10.5.0",
156
156
  "eslint-plugin-react": "^7.37.4",
@@ -158,23 +158,19 @@
158
158
  "fs-extra": "^10.0.0",
159
159
  "hanbi": "^1.0.1",
160
160
  "husky": "^8.0.3",
161
- "jsdoc-escape-at": "^1.0.1",
162
- "jsdoc-to-markdown": "^8.0.0",
163
- "jsdoc-tsimport-plugin": "^1.0.5",
164
161
  "less": "^4.1.2",
165
162
  "lint-staged": "^12.3.1",
166
163
  "lit": "^3.1.2",
167
164
  "mdast": "^3.0.0",
168
- "mermaid": "^10.9.5",
169
- "mocha": "^10.2.0",
165
+ "mermaid": "^11.12.3",
166
+ "mocha": "^12.0.0-beta-10",
170
167
  "monaco-editor": "^0.47.0",
171
168
  "npm-run-all": "^4.1.5",
172
- "patch-package": "^8.0.0",
169
+ "patch-package": "^8.0.1",
173
170
  "sass": "^1.69.5",
174
171
  "semver": "^7.6.3",
175
172
  "sharp": "^0.32.5",
176
173
  "starlight-links-validator": "^0.16.0",
177
- "stylus": "^0.56.0",
178
174
  "typescript": "^5.7.2",
179
175
  "unist-util-visit": "^5.0.0",
180
176
  "uuid": "^9.0.1",
@@ -0,0 +1,6 @@
1
+ import { dimensionUnit } from '../lib/enums/index.js';
2
+ export type TokenTypeDimensionUnit = (typeof dimensionUnit)[keyof typeof dimensionUnit];
3
+ export interface TokenTypeDimension {
4
+ value: number;
5
+ unit: TokenTypeDimensionUnit;
6
+ }
package/types/index.d.ts CHANGED
@@ -7,5 +7,6 @@ export type { Format, FormatFnArguments, FormatFn, OutputReferences } from './Fo
7
7
  export type { SortOption, SortFn, BuiltInSorts } from './Sort.js';
8
8
  export type { Parser, ParserOptions } from './Parser.js';
9
9
  export type { Preprocessor } from './Preprocessor.js';
10
+ export type { TokenTypeDimension, TokenTypeDimensionUnit } from './TokenTypes.js';
10
11
  export type { Transform, NameTransform, AttributeTransform, ValueTransform } from './Transform.js';
11
12
  export type { Volume } from './Volume.js';