Skip to content

Commit ae1988e

Browse files
committed
fix: apply token and script fixes to sync with design
- update outputs of sync script - add stricter checks - separate concerns (FigmaVariable should not know about style-dictionary) - updates to token values to sync with design - add properly named background-util-informational tokens - add missing background-util-warning tokens - generate tokens in output files
1 parent c04326d commit ae1988e

File tree

13 files changed

+431
-111
lines changed

13 files changed

+431
-111
lines changed

.storybook/components/Docs/Guidelines/Theming.mdx

+3
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,11 @@ Example:
174174
npx eds-import-from-figma file <file_id> --token <personal_access_token>
175175
```
176176

177+
**NOTE**: when using this method, it requires both the figma file ID (e.g., `figma.com/design/<file_id>/`), and an API token. Instrustions from Figma [are here][figma-access-token-docs].
178+
177179
[figma-enterprise]: https://www.figma.com/enterprise/
178180
[figma-api-docs]: https://www.figma.com/developers/api
181+
[figma-access-token-docs]: https://help.figma.com/hc/en-us/articles/8085703771159-Manage-personal-access-tokens
179182

180183
## Custom Theming and Tailwind
181184

.storybook/data/tokens.json

+31
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,8 @@
155155
"eds-theme-border-radius-objects-sm": "2",
156156
"eds-theme-border-radius-objects-xs": "0",
157157
"eds-theme-border-radius-tab-underline": "50",
158+
"eds-theme-border-radius-tab-underline-default": "9999",
159+
"eds-theme-border-radius-tab-underline-sticky": "9999",
158160
"eds-theme-border-width": "1",
159161
"eds-theme-box-button-border-radius": "4",
160162
"eds-theme-box-focus-ring-outline-width": "1",
@@ -242,9 +244,15 @@
242244
"eds-theme-color-background-utility-warning-low-emphasis": "#FDF3D3",
243245
"eds-theme-color-background-utility-warning-low-emphasis-hover": "#FBE8AB",
244246
"eds-theme-color-background-utility-warning-low-emphasis-active": "#F9DA78",
247+
"eds-theme-color-background-utility-warning-high-emphasis": "#FDF3D3",
248+
"eds-theme-color-background-utility-warning-high-emphasis-hover": "#FBE8AB",
249+
"eds-theme-color-background-utility-warning-high-emphasis-active": "#F9DA78",
245250
"eds-theme-color-background-utility-information-low-emphasis": "#EAF4FF",
246251
"eds-theme-color-background-utility-information-low-emphasis-hover": "#CEE6FF",
247252
"eds-theme-color-background-utility-information-low-emphasis-active": "#B5DAFF",
253+
"eds-theme-color-background-utility-informational-low-emphasis": "#EAF4FF",
254+
"eds-theme-color-background-utility-informational-low-emphasis-hover": "#CEE6FF",
255+
"eds-theme-color-background-utility-informational-low-emphasis-active": "#B5DAFF",
248256
"eds-theme-color-background-utility-disabled-no-emphasis": "transparent",
249257
"eds-theme-color-background-utility-disabled-low-emphasis": "#EEE7E4",
250258
"eds-theme-color-background-utility-disabled-medium-emphasis": "#CFC9C7",
@@ -519,6 +527,7 @@
519527
"eds-theme-color-icon-utility-disabled-secondary": "#CFC9C7",
520528
"eds-theme-color-icon-utility-inverse": "rgb(var(--eds-color-white) / 1)",
521529
"eds-theme-color-icon-utility-inverse-disabled": "rgb(var(--eds-color-white) / 0.5)",
530+
"eds-theme-color-icon-utility-inverse-interactive-visited": "rgb(var(--eds-color-white) / 1)",
522531
"eds-theme-color-icon-utility-placeholder": "#6C6967",
523532
"eds-theme-color-icon-utility-success": "#00A56A",
524533
"eds-theme-color-icon-utility-success-hover": "#008656",
@@ -820,6 +829,28 @@
820829
"eds-size-quarter": "2",
821830
"eds-size-1-and-half": "12",
822831
"eds-size-2-and-half": "20",
832+
"eds-spacing-size-1": "8",
833+
"eds-spacing-size-2": "16",
834+
"eds-spacing-size-3": "24",
835+
"eds-spacing-size-4": "32",
836+
"eds-spacing-size-5": "40",
837+
"eds-spacing-size-6": "48",
838+
"eds-spacing-size-7": "56",
839+
"eds-spacing-size-8": "64",
840+
"eds-spacing-size-9": "72",
841+
"eds-spacing-size-10": "80",
842+
"eds-spacing-size-11": "88",
843+
"eds-spacing-size-12": "96",
844+
"eds-spacing-size-20": "160",
845+
"eds-spacing-size-24": "192",
846+
"eds-spacing-size-32": "256",
847+
"eds-spacing-size-34": "272",
848+
"eds-spacing-size-40": "320",
849+
"eds-spacing-size-base-unit": "8",
850+
"eds-spacing-size-half": "4",
851+
"eds-spacing-size-quarter": "2",
852+
"eds-spacing-size-1-and-half": "12",
853+
"eds-spacing-size-2-and-half": "20",
823854
"eds-z-index-0": "0",
824855
"eds-z-index-100": "100",
825856
"eds-z-index-200": "200",

bin/_util.js

+50-33
Original file line numberDiff line numberDiff line change
@@ -344,14 +344,18 @@ module.exports = {
344344
* @returns Variable
345345
*/
346346
retrieveVariable(variableId) {
347-
return Object.values(this._jsonData.variables).find((variable) => {
348-
return variable.id === variableId;
349-
});
347+
const retrieved = Object.values(this._jsonData.variables).find(
348+
(variable) => {
349+
return variable.id === variableId;
350+
},
351+
);
352+
return retrieved;
350353
}
351354
},
352355

353356
FigmaVariable: class {
354-
static TIER_1_PREFIX = 'Render/';
357+
static TIER_1_PREFIX = 'render/';
358+
static VARIABLE_ALIAS = 'VARIABLE_ALIAS';
355359

356360
constructor(json, mode, lookupDelegate) {
357361
// TODO: throw if any private members are invalid
@@ -415,8 +419,27 @@ module.exports = {
415419
}
416420
}
417421

422+
/**
423+
* Determine whether a variable is marked as orphaned (e.g., deleted from the var.s but still used in a component)
424+
* @returns {boolean}
425+
*/
426+
isOrphaned() {
427+
return !!this._figmaVariableData.deletedButReferenced;
428+
}
429+
430+
/**
431+
* @static
432+
*
433+
* Returns whether the value of a given figma variable and mode is a reference or not
434+
* @param {FigmaVariable} figmaVariable API JSON data representing a figma variable instance
435+
* @param {string} mode the collection that the variable has a value in
436+
* @returns {boolean} whether the value for the variable is a literal or references another figma variable
437+
*/
418438
static isAliased(figmaVariable, mode) {
419-
return figmaVariable.valuesByMode[mode]?.type === 'VARIABLE_ALIAS';
439+
return (
440+
figmaVariable.valuesByMode[mode]?.type ===
441+
module.exports.FigmaVariable.VARIABLE_ALIAS
442+
);
420443
}
421444

422445
/**
@@ -499,55 +522,49 @@ module.exports = {
499522
}
500523
}
501524

525+
/**
526+
* @property
527+
* Unformatted (figma) name for the current figma variable
528+
*/
502529
get name() {
503530
return this._figmaVariableData.name;
504531
}
505532

533+
/**
534+
* @property
535+
* Resolved and parsed value for the given variable. Performs lookup if value is aliased, using delegate.
536+
*/
506537
get value() {
507538
return this.parseResolvedValue(this.getResovledValue());
508539
}
509540

541+
/**
542+
* @property
543+
* Resolved and parsed value reference (path) for the given variable. Performs lookup if value is aliased, using delegate.
544+
*/
510545
get valueRef() {
511546
switch (this._figmaVariableData.resolvedType) {
512547
case 'COLOR':
513-
// TODO: (in source) transparent exists as a tier 1 token but should not
514-
if (this.getResovledName() === 'Render/Transparent') {
515-
return 'transparent';
516-
}
548+
// TODO-AH: BUG: we assume all lookups resolve to a tier 1 value
549+
// the one that errors is b/c it doesn't eventually reference a tier 1 (icon/util/inverse-disabled)
550+
// how to properly use .getTokenPath here?
517551
return module.exports.FigmaVariable.isAliased(
518552
this._figmaVariableData,
519553
this._mode,
520554
)
521-
? `{${this._tokenNameToPath(
522-
this.getResovledName()
523-
.replace(
524-
module.exports.FigmaVariable.TIER_1_PREFIX,
525-
'eds.color.',
526-
)
527-
// TODO: (in source) remove duplicate color from structures
528-
.replace('Neutral/Neutral', 'Neutral')
529-
.replace('Red/Red', 'Red')
530-
.replace('Orange/Orange', 'Orange')
531-
.replace('Yellow/Yellow', 'Yellow')
532-
.replace('Green/Green', 'Green')
533-
.replace('Blue/Blue', 'Blue')
534-
.replace('Purple/Purple', 'Purple')
535-
.replace('Pink/Pink', 'Pink')
536-
// TODO: (in source) lower case the names of the tier 1 color tokens
537-
.toLowerCase(),
538-
)}}`
555+
? `${this._tokenNameToPath(
556+
this.getResovledName().replace(
557+
module.exports.FigmaVariable.TIER_1_PREFIX,
558+
'eds.color.',
559+
),
560+
)}`
539561
: this.value;
540562
case 'FLOAT':
541563
return module.exports.FigmaVariable.isAliased(
542564
this._figmaVariableData,
543565
this._mode,
544566
)
545-
? `{${this._tokenNameToPath(
546-
'eds.' +
547-
this.getResovledName()
548-
// TODO: (in source) lower case the names of the tier 1 color tokens
549-
.toLowerCase(),
550-
)}}`
567+
? `${this._tokenNameToPath('eds.' + this.getResovledName())}`
551568
: this.value;
552569
default:
553570
throw new TypeError(

bin/_util.test.js

+6-3
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ describe('utils', function () {
365365
variables: {
366366
'VariableID:6348:6248': {
367367
id: 'VariableID:6348:6248',
368-
name: 'Render/Neutral/Neutral-050',
368+
name: 'render/neutral-050',
369369
remote: false,
370370
key: '176ccd26264f7e048ae441ac585726a51fa6a819',
371371
variableCollectionId: 'VariableCollectionId:6181:1797',
@@ -405,7 +405,7 @@ describe('utils', function () {
405405
},
406406
'VariableID:6195:914': {
407407
id: 'VariableID:6195:914',
408-
name: 'Render/Neutral/White',
408+
name: 'render/neutral/white',
409409
remote: false,
410410
key: 'b2ed72ac00bfa71fbe0c0039404b125f7f5193e2',
411411
variableCollectionId: 'VariableCollectionId:6181:1797',
@@ -546,6 +546,9 @@ describe('utils', function () {
546546
});
547547

548548
describe('FigmaVariable', function () {
549+
// TODO-AH: add test for lookup when the matching token is not tier 1
550+
// TODO-AH: add test for orphaned token
551+
549552
it('allows retrieval of token path from a variable', () => {
550553
const variable = new utils.FigmaVariable(
551554
{
@@ -638,7 +641,7 @@ describe('utils', function () {
638641
new utils.FigmaAPIReader(mockData),
639642
);
640643

641-
expect(variable.valueRef).toEqual('{eds.color.neutral.white}');
644+
expect(variable.valueRef).toEqual('eds.color.neutral.white');
642645
});
643646

644647
it('allows retrieval of float value ref from a variable', () => {

bin/eds-import-from-figma-api.js

+34-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#!/usr/bin/env node
22

3+
const { identity } = require('lodash');
4+
35
// Script shell
46
(async function () {
57
const jsonfile = require('jsonfile');
@@ -118,22 +120,34 @@
118120
response.modeId,
119121
figmaApiReader,
120122
);
121-
let writePath = variable.getTokenPath();
123+
124+
// If we have a zombie entry in the variable list, skip it (flag for design)
125+
if (variable.isOrphaned()) {
126+
stats.skipped.push(variable);
127+
spinner.warn(
128+
chalk.bold(variable.name) +
129+
': Skipped with warning (orphaned): please remove usage in figma',
130+
);
131+
132+
return;
133+
}
122134

123135
// mesh the token path to a matching path in the local theme file
124-
const found = at(localTheme, writePath).filter(
136+
let writePath = variable.getTokenPath();
137+
const locationInLocal = at(localTheme, writePath).filter(
125138
(entries) => typeof entries !== 'undefined',
126139
);
127140

128-
if (found.length) {
141+
// Update the write path to conform to the format used in style-dictionary
142+
if (locationInLocal.length) {
129143
// handle case where we should look for @ in the file, then pluck the value object properly
130-
if (found[0]['@']?.value) {
144+
if (locationInLocal[0]['@']?.value) {
131145
// update the write path to mark the @ and value
132146
writePath = writePath + '[email protected]';
133147
}
134148

135149
// handle case where it's just value
136-
if (found[0]?.value) {
150+
if (locationInLocal[0]?.value) {
137151
// update the write path to mark the value
138152
writePath = writePath + '.value';
139153
}
@@ -143,17 +157,28 @@
143157
try {
144158
// error when path suffix is invalid (all should end with .value)
145159
if (!writePath.endsWith('value')) {
160+
isVerbose && console.error(variable);
161+
throw new Error(
162+
`Name format violation. JSON path missing in local theme: ${writePath} (${figmaVariable.resolvedType})`,
163+
);
164+
}
165+
166+
if (
167+
FigmaVariable.isAliased(figmaVariable, response.modeId) &&
168+
!at(localTheme, variable.valueRef).some(identity)
169+
) {
146170
throw new Error(
147-
`Name format violation. Name missing in local theme: ${writePath} (${figmaVariable.resolvedType})`,
171+
`Value violation. Trying to write a reference value path not in local theme: ${writePath} => {${variable.valueRef}}`,
148172
);
149173
}
150174

175+
// Write the defined value to the specified location by json path
151176
canWrite &&
152177
args.local &&
153-
set(localTheme, writePath, variable.valueRef);
178+
set(localTheme, writePath, `{${variable.valueRef}}`);
154179
canWrite && !args.local && set(localTheme, writePath, variable.value);
155180

156-
// write the value using the calculated path and parsed value
181+
// log if in a loggable mode (verbose / dry-run)
157182
if (isVerbose || !canWrite) {
158183
spinner.succeed(
159184
`Write: ${
@@ -166,7 +191,7 @@
166191
stats.updated.push(variable);
167192
} catch (e) {
168193
// We couldn't parse the resolved value, so skip and add to errors
169-
spinner.fail(chalk.bold(variable.name) + ': Error (' + e + ')');
194+
spinner.fail(chalk.bold(variable.name) + ': ' + e);
170195
stats.errored.push(variable);
171196
}
172197
} else {

src/components/Card/Card.module.css

+4-4
Original file line numberDiff line numberDiff line change
@@ -63,16 +63,16 @@
6363
}
6464

6565
.card--container-color-call-out {
66-
background-color: var(--eds-theme-color-background-utility-information-low-emphasis);
66+
background-color: var(--eds-theme-color-background-utility-informational-low-emphasis);
6767
border-color: var(--eds-theme-color-border-utility-informational);
6868

6969
&.card--is-interactive {
7070
&:hover {
71-
background-color: var(--eds-theme-color-background-utility-information-low-emphasis-hover);
71+
background-color: var(--eds-theme-color-background-utility-informational-low-emphasis-hover);
7272
}
7373

7474
&:active {
75-
background-color: var(--eds-theme-color-background-utility-information-low-emphasis-active);
75+
background-color: var(--eds-theme-color-background-utility-informational-low-emphasis-active);
7676
}
7777
}
7878
}
@@ -87,7 +87,7 @@
8787
& .header__eyebrow {
8888
margin-bottom: calc(var(--eds-size-1) / 16 * 1rem);
8989
}
90-
90+
9191
&.header--size-sm {
9292
gap: calc(var(--eds-size-1) / 16 * 1rem)
9393
}

src/components/InlineNotification/InlineNotification.module.css

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
/* NOTE: by specifying no default color for borders, they inherit from color below */
2323
&.inline-notification--status-informational {
2424
color: var(--eds-theme-color-text-utility-informational);
25-
background-color: var(--eds-theme-color-background-utility-information-low-emphasis);
25+
background-color: var(--eds-theme-color-background-utility-informational-low-emphasis);
2626
}
2727

2828
&.inline-notification--status-critical {
@@ -47,4 +47,4 @@
4747

4848
.inline-notification__body {
4949
flex-grow: 2;
50-
}
50+
}

0 commit comments

Comments
 (0)