@esri/calcite-design-tokens 1.0.0 → 1.1.0-next.1

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 (111) hide show
  1. package/.eslintrc.cjs +85 -0
  2. package/.turbo/turbo-build.log +64 -0
  3. package/.turbo/turbo-test.log +14 -0
  4. package/CHANGELOG.md +17 -4
  5. package/CONTRIBUTING.md +41 -0
  6. package/LICENSE.md +13 -0
  7. package/README.md +9 -11
  8. package/dist/css/brand-light.css +1 -1
  9. package/dist/css/calcite-dark.css +1 -1
  10. package/dist/css/calcite-headless.css +2 -1
  11. package/dist/css/calcite-light.css +1 -1
  12. package/dist/scss/brand-light.scss +1 -1
  13. package/dist/scss/calcite-dark.scss +1 -1
  14. package/dist/scss/calcite-headless.scss +3 -1
  15. package/dist/scss/calcite-light.scss +1 -1
  16. package/jest.config.json +16 -0
  17. package/package.json +11 -72
  18. package/src/$metadata.json +76 -0
  19. package/src/$themes.json +2360 -0
  20. package/src/brand/dark.json +1 -0
  21. package/src/brand/global.json +1 -0
  22. package/src/brand/light.json +20 -0
  23. package/src/calcite/dark.json +2488 -0
  24. package/src/calcite/light.json +2508 -0
  25. package/src/component/accordion-item.json +172 -0
  26. package/src/component/accordion.json +192 -0
  27. package/src/component/action-bar-grid.json +66 -0
  28. package/src/component/action-bar.json +66 -0
  29. package/src/component/action-pad-grid.json +80 -0
  30. package/src/component/action-pad.json +80 -0
  31. package/src/component/action.json +156 -0
  32. package/src/component/alert.json +258 -0
  33. package/src/component/avatar.json +140 -0
  34. package/src/component/block-section.json +124 -0
  35. package/src/component/block.json +198 -0
  36. package/src/component/button.json +650 -0
  37. package/src/component/card.json +116 -0
  38. package/src/component/checkbox.json +110 -0
  39. package/src/component/chip.json +382 -0
  40. package/src/component/color-picker.json +148 -0
  41. package/src/component/combobox.json +152 -0
  42. package/src/component/date-picker.json +354 -0
  43. package/src/component/dropdown-item.json +384 -0
  44. package/src/component/dropdown.json +58 -0
  45. package/src/component/fab.json +490 -0
  46. package/src/component/filter.json +174 -0
  47. package/src/component/input-date-picker.json +224 -0
  48. package/src/component/input-datetime-local.json +230 -0
  49. package/src/component/input-email.json +244 -0
  50. package/src/component/input-file.json +244 -0
  51. package/src/component/input-message.json +72 -0
  52. package/src/component/input-month.json +244 -0
  53. package/src/component/input-number.json +244 -0
  54. package/src/component/input-password.json +244 -0
  55. package/src/component/input-search.json +244 -0
  56. package/src/component/input-telephone.json +244 -0
  57. package/src/component/input-text.json +244 -0
  58. package/src/component/input-time.json +1 -0
  59. package/src/component/input-week.json +244 -0
  60. package/src/component/label.json +26 -0
  61. package/src/component/link.json +44 -0
  62. package/src/component/loader.json +130 -0
  63. package/src/component/modal.json +278 -0
  64. package/src/component/notice.json +280 -0
  65. package/src/component/pagination.json +152 -0
  66. package/src/component/panel-header.json +88 -0
  67. package/src/component/popover.json +170 -0
  68. package/src/component/radio.json +124 -0
  69. package/src/component/rating.json +243 -0
  70. package/src/component/scrim.json +18 -0
  71. package/src/component/segmented-control.json +154 -0
  72. package/src/component/slider-histogram-range.json +284 -0
  73. package/src/component/slider-histogram.json +280 -0
  74. package/src/component/slider-range.json +226 -0
  75. package/src/component/slider.json +226 -0
  76. package/src/component/split-button.json +830 -0
  77. package/src/component/stepper-item.json +372 -0
  78. package/src/component/stepper.json +152 -0
  79. package/src/component/switch.json +178 -0
  80. package/src/component/tab-title.json +228 -0
  81. package/src/component/tabs.json +242 -0
  82. package/src/component/textarea.json +200 -0
  83. package/src/component/time-picker.json +138 -0
  84. package/src/component/tip-manager.json +118 -0
  85. package/src/component/tip.json +114 -0
  86. package/src/component/tooltip.json +66 -0
  87. package/src/component/tree-item.json +176 -0
  88. package/src/core.json +1709 -0
  89. package/src/semantic.json +1709 -0
  90. package/support/run.ts +16 -0
  91. package/support/token-transformer/format/scss.ts +81 -0
  92. package/support/token-transformer/getThemes.ts +41 -0
  93. package/support/token-transformer/parse/expandComposites.test.ts +144 -0
  94. package/support/token-transformer/parse/expandComposites.ts +72 -0
  95. package/support/token-transformer/sd-run.ts +147 -0
  96. package/support/token-transformer/transform/nameCamelCase.test.ts +36 -0
  97. package/support/token-transformer/transform/nameCamelCase.ts +15 -0
  98. package/support/token-transformer/transform/nameKebabCase.test.ts +36 -0
  99. package/support/token-transformer/transform/nameKebabCase.ts +26 -0
  100. package/support/token-transformer/utils/compositeTokens.test.ts +133 -0
  101. package/support/token-transformer/utils/compositeTokens.ts +103 -0
  102. package/support/token-transformer/utils/convertTokenToStyleDictionaryFormat.ts +20 -0
  103. package/support/token-transformer/utils/matchList.ts +11 -0
  104. package/support/token-transformer/utils/parseName.ts +18 -0
  105. package/support/token-transformer/utils/parseTokenPath.ts +19 -0
  106. package/support/token-transformer/utils/regex.ts +9 -0
  107. package/support/token-transformer/utils/sortAllTokens.ts +12 -0
  108. package/support/token-transformer/utils/transformOptions.ts +31 -0
  109. package/tsconfig-base.json +17 -0
  110. package/tsconfig-eslint.json +4 -0
  111. package/tsconfig.json +4 -0
@@ -0,0 +1,133 @@
1
+ import { expandToken, shouldExpand } from "./compositeTokens";
2
+
3
+ const mockHandleValue = jest.fn((val) => val);
4
+
5
+ describe("expand composite token", () => {
6
+ it("should expand a non-shadow token", () => {
7
+ const mockTypographyToken = {
8
+ value: {
9
+ fontFamily: "$core.font.font-family.primary",
10
+ fontWeight: "$core.font.font-weight.light",
11
+ lineHeight: "$core.font.line-height.fixed.0",
12
+ fontSize: "$core.font.font-size.0",
13
+ letterSpacing: "$core.font.letter-spacing.normal",
14
+ paragraphSpacing: "$core.font.paragraph-spacing.normal",
15
+ textDecoration: "$core.font.text-decoration.none",
16
+ textCase: "$core.font.text-case.none",
17
+ },
18
+ type: "typography",
19
+ };
20
+ const mockExpandedTypographyToken = {
21
+ "font-family": {
22
+ value: "$core.font.font-family.primary",
23
+ type: "font-family",
24
+ },
25
+ "font-weight": {
26
+ value: "$core.font.font-weight.light",
27
+ type: "font-weights",
28
+ },
29
+ "line-height": {
30
+ value: "$core.font.line-height.fixed.0",
31
+ type: "line-heights",
32
+ },
33
+ "font-size": {
34
+ value: "$core.font.font-size.0",
35
+ type: "font-size",
36
+ },
37
+ "letter-spacing": {
38
+ value: "$core.font.letter-spacing.normal",
39
+ type: "letter-spacing",
40
+ },
41
+ "paragraph-spacing": {
42
+ value: "$core.font.paragraph-spacing.normal",
43
+ type: "paragraph-spacing",
44
+ },
45
+ "text-decoration": {
46
+ value: "$core.font.text-decoration.none",
47
+ type: "font-style",
48
+ },
49
+ "text-case": {
50
+ value: "$core.font.text-case.none",
51
+ type: "text-case",
52
+ },
53
+ };
54
+ const testExpandToken = expandToken(mockTypographyToken, false, mockHandleValue);
55
+ expect(testExpandToken).toMatchObject(mockExpandedTypographyToken);
56
+ });
57
+ it("should expand a shadow token", () => {
58
+ const mockShadowToken = {
59
+ value: [
60
+ {
61
+ x: "0",
62
+ y: "2",
63
+ blur: "8",
64
+ spread: "0",
65
+ color: "rgba($core.color.neutral.blk-240, $core.opacity.4)",
66
+ type: "dropShadow",
67
+ },
68
+ {
69
+ x: "0",
70
+ y: "4",
71
+ blur: "16",
72
+ spread: "0",
73
+ color: "rgba($core.color.neutral.blk-240, $core.opacity.8)",
74
+ type: "dropShadow",
75
+ },
76
+ ],
77
+ type: "boxShadow",
78
+ };
79
+ const mockExpandedShadowToken = {
80
+ "1": {
81
+ x: {
82
+ type: "dimension",
83
+ value: "0",
84
+ },
85
+ y: {
86
+ type: "dimension",
87
+ value: "2",
88
+ },
89
+ blur: {
90
+ type: "dimension",
91
+ value: "8",
92
+ },
93
+ spread: {
94
+ type: "dimension",
95
+ value: "0",
96
+ },
97
+ color: {
98
+ type: "color",
99
+ value: "rgba($core.color.neutral.blk-240, $core.opacity.4)",
100
+ },
101
+ },
102
+ };
103
+ const testExpandToken = expandToken(mockShadowToken, true, mockHandleValue);
104
+ expect(testExpandToken).toMatchObject(mockExpandedShadowToken);
105
+ });
106
+ });
107
+
108
+ describe("shouldExpand", () => {
109
+ const filePath = "./mockFile.json";
110
+ const mockToken = {
111
+ name: "testToken",
112
+ type: "fontFamilies",
113
+ value: "san-serif",
114
+ };
115
+
116
+ it("should return true", () => {
117
+ // @ts-expect-error - type is fine here.
118
+ const testExpand = shouldExpand(mockToken, true, filePath);
119
+ expect(testExpand).toBe(true);
120
+ });
121
+ it("should return false", () => {
122
+ // @ts-expect-error - type is fine here.
123
+ const testExpand = shouldExpand(mockToken, false, filePath);
124
+ expect(testExpand).toBe(false);
125
+ });
126
+ it("should use condition function", () => {
127
+ const mockExpandFunction = jest.fn(() => true);
128
+ // @ts-expect-error - type is fine here.
129
+ const testExpand = shouldExpand(mockToken, mockExpandFunction, filePath);
130
+ expect(testExpand).toBe(true);
131
+ expect(mockExpandFunction).toHaveBeenCalled();
132
+ });
133
+ });
@@ -0,0 +1,103 @@
1
+ import { ExpandFilter } from "../utils/transformOptions";
2
+ import { matchPlaceholderElement } from "./regex.js";
3
+ import { DesignToken } from "style-dictionary/types/DesignToken";
4
+ import { SingleToken } from "@tokens-studio/types";
5
+ import { paramCase } from "change-case";
6
+
7
+ // A customized type map based off Token Studio.
8
+ // This determines the applied "type" associated with each Style Dictionary token value
9
+ const typeMaps = {
10
+ boxShadow: {
11
+ x: "dimension",
12
+ y: "dimension",
13
+ blur: "dimension",
14
+ spread: "dimension",
15
+ type: "other",
16
+ color: "color",
17
+ },
18
+ border: {
19
+ width: "border-width",
20
+ style: "other",
21
+ },
22
+ composition: {
23
+ typography: "font-size",
24
+ fontWeight: "font-weight",
25
+ },
26
+ typography: {
27
+ fontFamily: "font-family",
28
+ fontWeight: "font-weights",
29
+ lineHeight: "line-heights",
30
+ fontSize: "font-size",
31
+ letterSpacing: "letter-spacing",
32
+ paragraphSpacing: "paragraph-spacing",
33
+ textDecoration: "font-style",
34
+ textCase: "text-case",
35
+ },
36
+ };
37
+
38
+ /**
39
+ * Get type from type map
40
+ *
41
+ * @param {string} key type
42
+ * @param {DesignToken} compositeToken a Style Dictionary token
43
+ * @returns {string} approved token type
44
+ */
45
+ export const getType = (key: string, compositeToken: DesignToken): string => typeMaps[compositeToken.type][key] ?? key;
46
+
47
+ /**
48
+ * This is a recursive function to dig into composite tokens and lift up the token values in a Style Dictionary format.
49
+ *
50
+ * @param {DesignToken} compositeToken the composite token object
51
+ * @param {boolean} isShadow is a drop shadow?
52
+ * @param {Function} handleValue a function to determine how the final token value string should be passed to Style Dictionary
53
+ * @returns {DesignToken} a single Style Dictionary token object
54
+ */
55
+ export function expandToken(compositeToken: DesignToken, isShadow = false, handleValue = (v) => v): DesignToken {
56
+ const expandedObj = {} as DesignToken;
57
+
58
+ if (isShadow && Array.isArray(compositeToken.value)) {
59
+ compositeToken.value.forEach((shadow, index) => {
60
+ expandedObj[index + 1] = {};
61
+ Object.entries(shadow).forEach(([key, value]) => {
62
+ if (matchPlaceholderElement.test(`${value}`) || key === "type") {
63
+ return;
64
+ }
65
+ expandedObj[index + 1][key] = {
66
+ value: `${handleValue(value)}`,
67
+ type: getType(key, compositeToken),
68
+ };
69
+ });
70
+ });
71
+ } else {
72
+ Object.entries(compositeToken.value).forEach(([key, value]) => {
73
+ const newKey = paramCase(key);
74
+ if (matchPlaceholderElement.test(`${value}`)) {
75
+ return;
76
+ }
77
+ expandedObj[newKey] = {
78
+ value: `${handleValue(value)}`,
79
+ type: getType(key, compositeToken),
80
+ };
81
+ });
82
+ }
83
+
84
+ return expandedObj;
85
+ }
86
+
87
+ /**
88
+ *
89
+ * @param {DesignToken} token Style Dictionary token object
90
+ * @param {boolean | ExpandFilter<SingleToken>} condition check if the token should be expanded or not
91
+ * @param {string} filePath the file path where the token came from
92
+ * @returns {boolean} if the token should be expanded
93
+ */
94
+ export function shouldExpand<T extends SingleToken>(
95
+ token: T,
96
+ condition: boolean | ExpandFilter<T>,
97
+ filePath: string
98
+ ): boolean {
99
+ if (typeof condition === "function") {
100
+ return condition(token, filePath);
101
+ }
102
+ return condition;
103
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Some tokens defined in Figma Token Studio do not used the common { [variable.name] } for token references.
3
+ * This function loops over each value, finds custom token references and converts them to the expected Style Dictionary format.
4
+ *
5
+ * @param {RegExp} customReferenceTokenIndicator a regex to find the token references
6
+ * @returns {Function} to convert the token to the reference format expected by Style Dictionary "{ [variable.name] }"
7
+ */
8
+ export function convertTokenToStyleDictionaryFormat(
9
+ customReferenceTokenIndicator: RegExp
10
+ ): (value: string | number) => string {
11
+ return (value: string | number): string => {
12
+ let newValue = `${value}`;
13
+ const matchesArr = [...newValue.matchAll(customReferenceTokenIndicator)];
14
+ matchesArr.forEach((match) => {
15
+ const figmaVariable = match[0];
16
+ newValue = newValue.replace(figmaVariable, `{${figmaVariable.slice(1)}}`);
17
+ });
18
+ return newValue;
19
+ };
20
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Find the string in a list
3
+ *
4
+ * @param {string} str the string to find in the list
5
+ * @param {string[]} list the list of strings to match with the provided string
6
+ * @param {RegExp} regexExclude a regular expression defining strings that should always be excluded
7
+ * @returns {boolean} does the string match the items in the list
8
+ */
9
+ export const matchList = (str: string, list: string[], regexExclude: RegExp): boolean => {
10
+ return list.some((value) => str.includes(value) && !regexExclude.test(str));
11
+ };
@@ -0,0 +1,18 @@
1
+ import { paramCase } from "change-case";
2
+
3
+ /**
4
+ * Used to set the file name for the generated theme file.
5
+ *
6
+ * @param {string} name the file name passed from the themes object
7
+ * @param {string} prefix an optional prefix for each file name
8
+ * @returns {string} a kebab-case file name from the passed name, optionally starting with a prefix
9
+ */
10
+ export function parseName(name: string, prefix?: string): string {
11
+ const regexWord = /^\w+$/;
12
+ const themeName = `${prefix || ""} ${name}`
13
+ .split(" ")
14
+ .filter((word) => regexWord.test(word))
15
+ .join(" ");
16
+
17
+ return paramCase(themeName);
18
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Replaces the word "color" with "ui" when it is the first value in the path and removes the word "default" from the final token names.
3
+ * This puts generated tokens in alignment with the theme variable names in Calcite-Colors
4
+ *
5
+ * @param {string[]} path the path to each token value in the Style Dictionary token object
6
+ * @returns {string[]} an updated token path
7
+ */
8
+ export const parseTokenPath = (path: string[]): string[] =>
9
+ path.reduce((acc, p, idx) => {
10
+ if (idx === 0 && p === "color") {
11
+ acc.push("ui");
12
+ } else if (p === "default") {
13
+ return acc;
14
+ } else {
15
+ acc.push(p);
16
+ }
17
+
18
+ return acc;
19
+ }, []);
@@ -0,0 +1,9 @@
1
+ // Match files and tokens which include "[" or "]"
2
+ export const matchPlaceholderElement = new RegExp(/[\[\]]/, "g");
3
+
4
+ // Match custom variable indicator created by Designers in Token Studio.
5
+ // Using the ${token.name} format in Token Studio makes it much easier for Designers to search for token references while doing their work.
6
+ export const tokenStudioCustomVariableIndicator = new RegExp(/\$[.\w-]+/, "g");
7
+
8
+ // Match files and tokens which include "backup", "[", "]", or file extensions
9
+ export const matchExclusions = /(backup|\[|\])(?=\.\w+$)/;
@@ -0,0 +1,12 @@
1
+ import { Dictionary } from "style-dictionary/types/Dictionary";
2
+ import { default as StyleDictionary } from "style-dictionary";
3
+ import { TransformedToken } from "style-dictionary/types/TransformedToken";
4
+
5
+ export function sortAllTokens(dictionary: Dictionary, outputReferences: boolean): TransformedToken[] {
6
+ let tokens = dictionary.allTokens;
7
+ if (outputReferences) {
8
+ tokens = [...dictionary.allTokens].sort(StyleDictionary.formatHelpers["sortByReference"](dictionary));
9
+ }
10
+
11
+ return tokens;
12
+ }
@@ -0,0 +1,31 @@
1
+ import {
2
+ SingleBorderToken,
3
+ SingleBoxShadowToken,
4
+ SingleCompositionToken,
5
+ SingleToken,
6
+ SingleTypographyToken,
7
+ } from "@tokens-studio/types";
8
+
9
+ /**
10
+ * Copied from https://github.com/tokens-studio/sd-transforms/blob/main/src/TransformOptions.ts
11
+ * This is needed for correct type setting and is not exported by Token Studio SD Transforms.
12
+ */
13
+
14
+ export type Expandables = SingleCompositionToken | SingleTypographyToken | SingleBorderToken | SingleBoxShadowToken;
15
+
16
+ export const expandablesAsStringsArr = ["composition", "typography", "border", "boxShadow"];
17
+ export type ExpandablesAsStrings = (typeof expandablesAsStringsArr)[number];
18
+
19
+ export type ExpandFilter<T extends SingleToken> = (token: T, filePath: string) => boolean;
20
+
21
+ export interface ExpandOptions {
22
+ typography?: boolean | ExpandFilter<SingleTypographyToken>;
23
+ border?: boolean | ExpandFilter<SingleBorderToken>;
24
+ shadow?: boolean | ExpandFilter<SingleBoxShadowToken>;
25
+ composition?: boolean | ExpandFilter<SingleCompositionToken>;
26
+ }
27
+
28
+ export interface TransformOptions {
29
+ expand?: ExpandOptions | false;
30
+ excludeParentKeys?: boolean;
31
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "compilerOptions": {
3
+ "allowSyntheticDefaultImports": true,
4
+ "allowUnreachableCode": false,
5
+ "declaration": false,
6
+ "esModuleInterop": true,
7
+ "experimentalDecorators": true,
8
+ "lib": ["dom", "dom.iterable", "ES2021"],
9
+ "module": "esnext",
10
+ "moduleResolution": "node",
11
+ "noUnusedLocals": true,
12
+ "noUnusedParameters": true,
13
+ "resolveJsonModule": true,
14
+ "target": "ES2021"
15
+ },
16
+ "exclude": ["node_modules", "dist"]
17
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "extends": "./tsconfig-base.json",
3
+ "include": ["./**/*"]
4
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,4 @@
1
+ {
2
+ "extends": "./tsconfig-base",
3
+ "include": ["support", "src"]
4
+ }