Skip to content

Commit b63631a

Browse files
jawinnpfulton
andauthored
refactor(icon)!: tokens migration (#2347)
BREAKING CHANGE: migrate Icon from DNA tokens to Spectrum tokens. Additionally: * refactor(icon): migrate css to spectrum tokens Migrates Icon CSS from using DNA/vars tokens to Spectrum tokens. Refactors UI Icons to be a little cleaner and not need placeholders. Icons now change the value of the property "--spectrum-icon-size" to set their width and height. They also have three additional mods available for setting the size (both width and height) or the individual width and height. * refactor(icon): remove legacy xvar css and plugin for combined icons - Remove 'xvar' and 'x--' code within UI icon CSS, along with the build plugins that were used only for this. This was only only needed previously when the build did not allow 'var()' and '--property' here. - Simplify and better document code used for combined UI icons and the medium/large platform scale. Remove old browser support here that is no longer needed with the browsers and features that are currently supported by the library. The old fallback to set display inline was pre Firefox version 56 [2017]. * refactor(icon): remove gripper icon classes Removing the gripper icon classes as they were incorrect and not used, and there are no tokens defined yet to set the actual classes to. The gripper icon classes used previously were wrong in several ways. For one, they were using '100' size naming in the classes which are not currently used or displayed. These icons are without the number size. The old alias values being applied to them also looked incorrect when looking at the widths, and the CSS was swapping width for height. That there is no size applied to these icons was obfuscated by the fact that the attribute width="10" is being applied to icons in Storybook. Note: SWC is currently showing these icons with workflow sizing. These gripper icons do not have size tokens defined yet, but they may be added in the future "as they are needed"; when these icons start being used. * docs(icon): storybook - add kitchen sink style story for chromatic Cover the various types of icons in a Chromatic only story. Covers different icon sets, sizes, and color in the VRTs. * feat(icon): adjust icon sizing custom properties Make sure we always have custom properties that contains the width and height, that we can rely upon for CSS calculations. Regardless of whether the individual dimensions are specified or just the size is specified (that applies to both dimensions). * fix(icon): storybook - remove inline width attribute The icons in Storybook were adding an inline "width" attribute set to 10, which was previously obfuscating issues with sizing. Removes this attribute and leaves sizing up to CSS. * feat(icon): support for xs workflow icon size Added extra small workflow icon size. This has a token, is defined on some of the design redlines (Action Button), and is currently used in the Contextual Help component, as seen in the VRT run. * feat(icon): remove theme files without content Recent updates to main make it no longer necessary to include empty theme files for the build to work. * feat(icon): storybook - use ui icon size numbers Disables the size control for UI icons and adds each size number to the list of available UI icon names in Storybook. UI icons have specific sizing and don't use the t-shirt sizing that Workflow icons do. They have more size numbers than there are t-shirt sizes, so they can't be directly mapped to each other. The different UI icons have different size numbers, so the size numbers can't use a single control. * feat(icon): storybook - show all ui icons in chromatic template Show all UI icons, including number sizing, in the Chromatic template. Condenses and improves some of the template logic. * fix(icon): wrong workflow icons appearing for arrow and chevron Fix bug where the wrong icon was being rendered for workflow arrow and chevron. These are both icons with names that exist in both icon sets. There was logic being applied to the workflow icons that should have only have been applied to the UI icon. * chore(icon): manual version bump for beta release * feat(icon): add xxs size for migration and use renamed xxl property Add XXS size to support existing SWC size. Uses the values from --spectrum-global-dimension-size-150, as used in SWC's custom icon CSS. Included comments to note that xxs and xxl are planned to be deprecated in Spectrum 2, as they are not a part of the design spec. * chore(icon): set current beta versions already released * build(icon): minimum tokens version with xxl and xxs sizing Update required tokens version with a minimum of the latest release that includes the new custom-vars for the xxl and xxs workflow icon sizes. --------- Co-authored-by: Patrick Fulton <pfulton@adobe.com>
1 parent 4d5e662 commit b63631a

File tree

20 files changed

+382
-562
lines changed

20 files changed

+382
-562
lines changed

components/icon/gulpfile.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
module.exports = require("@spectrum-css/component-builder");
1+
module.exports = require("@spectrum-css/component-builder-simple");

components/icon/icons.css

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,28 @@ governing permissions and limitations under the License.
1212

1313
.spectrum-Icon,
1414
.spectrum-UIIcon {
15+
--spectrum-icon-inline-size: var(--mod-icon-inline-size, var(--mod-icon-size, var(--spectrum-icon-size)));
16+
--spectrum-icon-block-size: var(--mod-icon-block-size, var(--mod-icon-size, var(--spectrum-icon-size)));
17+
1518
display: inline-block;
19+
inline-size: var(--spectrum-icon-inline-size);
20+
block-size: var(--spectrum-icon-block-size);
1621

17-
/* Use custom pass through or inherit the text color */
22+
/* Use custom pass through or inherit the text color. */
1823
color: var(--mod-icon-color, inherit);
1924

20-
/* Fill should match the current text color */
25+
/* Fill should match the current text color. */
2126
fill: currentColor;
2227

23-
/* Hide the svg overflow in IE. */
28+
/* Hide the SVG overflow in IE. */
2429
&:not(:root) {
2530
overflow: hidden;
2631
}
2732

28-
/* Don't catch clicks or hover, otherwise they may not escape the SVG */
33+
/* Don't catch clicks or hover, otherwise they may not escape the SVG. */
2934
pointer-events: none;
3035
}
36+
3137
@media (forced-colors: active) {
3238
.spectrum-Icon,
3339
.spectrum-UIIcon {

components/icon/metadata/mods.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1-
| Modifiable custom properties |
2-
| ---------------------------- |
3-
| `--mod-icon-color` |
1+
| Modifiable custom properties |
2+
| ------------------------------ |
3+
| `--mod-icon-block-size` |
4+
| `--mod-icon-color` |
5+
| `--mod-icon-inline-size` |
6+
| `--mod-icon-size` |
7+
| `--mod-ui-icon-large-display` |
8+
| `--mod-ui-icon-medium-display` |

components/icon/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@spectrum-css/icon",
3-
"version": "5.1.0",
3+
"version": "6.0.0-beta.1",
44
"description": "The Spectrum CSS icon component",
55
"license": "Apache-2.0",
66
"author": "Adobe",
@@ -13,9 +13,9 @@
1313
"bugs": {
1414
"url": "https://github.com/adobe/spectrum-css/issues"
1515
},
16-
"main": "dist/index-vars.css",
16+
"main": "dist/index.css",
1717
"peerDependencies": {
18-
"@spectrum-css/vars": ">=9"
18+
"@spectrum-css/tokens": ">=13.1"
1919
},
2020
"publishConfig": {
2121
"access": "public"

components/icon/project.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"$schema": "../../node_modules/nx/schemas/project-schema.json",
33
"name": "icon",
4-
"tags": ["component", "legacy"],
4+
"tags": ["component"],
55
"targets": {
66
"build": {},
77
"clean": {},

components/icon/stories/icon.stories.js

Lines changed: 106 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,27 @@
11
// Import the component markup template
2+
import isChromatic from "chromatic/isChromatic";
3+
import { html } from "lit";
4+
import { styleMap } from "lit/directives/style-map.js";
5+
import { when } from "lit/directives/when.js";
6+
27
import { Template } from "./template";
8+
import { uiIconSizes, uiIconsWithDirections, workflowIcons } from "./utilities.js";
39

4-
import { uiIcons, workflowIcons } from "./utilities.js";
10+
/**
11+
* Create a list of all UI Icons with their sizing numbers.
12+
*
13+
* The list is a little long until Storybook adds a way to use conditional options
14+
* in controls, e.g. a "uiSize" control with options pulled from uiIconSizes:
15+
* @see https://github.com/storybookjs/storybook/discussions/24235
16+
*/
17+
const uiIconNameOptions = uiIconsWithDirections.map((iconName) => {
18+
const baseIconName = iconName.replace(/(Left|Right|Up|Down)$/, '');
19+
// Icons like Gripper that don't have sizes yet, represented by any empty array.
20+
if (uiIconSizes[baseIconName]?.length == 0){
21+
return [baseIconName];
22+
}
23+
return uiIconSizes[baseIconName]?.map(sizeNum => iconName + sizeNum) ?? [];
24+
}).flat();
525

626
export default {
727
title: "Components/Icon",
@@ -13,14 +33,15 @@ export default {
1333
express: { table: { disable: true } },
1434
reducedMotion: { table: { disable: true } },
1535
size: {
16-
name: "Size",
36+
name: "Workflow Icon Size",
1737
type: { name: "string", required: true },
1838
table: {
1939
type: { summary: "string" },
2040
category: "Component",
2141
},
22-
options: ["s", "m", "l", "xl", "xxl"],
42+
options: ["xs", "s", "m", "l", "xl", "xxl"],
2343
control: "select",
44+
if: { arg: "setName", eq: "workflow" },
2445
},
2546
setName: {
2647
name: "Icon set",
@@ -51,15 +72,7 @@ export default {
5172
category: "Content",
5273
},
5374
options: [
54-
...uiIcons.filter((c) => !["Chevron", "Arrow"].includes(c)),
55-
"ArrowRight",
56-
"ArrowLeft",
57-
"ArrowUp",
58-
"ArrowDown",
59-
"ChevronRight",
60-
"ChevronLeft",
61-
"ChevronUp",
62-
"ChevronDown",
75+
...uiIconNameOptions,
6376
],
6477
control: "select",
6578
if: { arg: "setName", eq: "ui" },
@@ -90,10 +103,86 @@ export default {
90103
},
91104
};
92105

93-
export const Default = (args) => Template({
94-
...args,
95-
iconName: args.iconName ?? args.uiIconName,
96-
setName: args.setName ?? (args.uiIconName ? "ui" : "workflow"),
97-
});
106+
export const Default = (args) => {
107+
if (isChromatic()){
108+
return TestTemplate({ ...args });
109+
} else {
110+
return Template({
111+
...args,
112+
iconName: args.iconName ?? args.uiIconName,
113+
setName: args.setName ?? (args.uiIconName ? "ui" : "workflow"),
114+
});
115+
}
116+
}
98117

99118
Default.args = {};
119+
120+
/**
121+
* Chromatic VRT template that displays multiple icons to cover various options.
122+
*/
123+
const TestTemplate = ({
124+
staticColor,
125+
customStyles = {},
126+
...args
127+
}) => {
128+
const workflow_row_args = [
129+
{
130+
setName: "workflow",
131+
iconName: "Alert",
132+
fill: "var(--spectrum-negative-content-color-default)",
133+
},
134+
{
135+
setName: "workflow",
136+
iconName: "Hand",
137+
},
138+
{
139+
setName: "workflow",
140+
iconName: "Help",
141+
},
142+
{
143+
setName: "workflow",
144+
iconName: "ArrowLeft",
145+
},
146+
{
147+
setName: "workflow",
148+
iconName: "ArrowRight",
149+
},
150+
{
151+
setName: "workflow",
152+
iconName: "ChevronDown",
153+
}
154+
];
155+
156+
return html`
157+
${workflow_row_args.map((row_args) => html`
158+
<div
159+
style=${styleMap({
160+
display: "flex",
161+
gap: "16px",
162+
marginBottom: "16px",
163+
})}
164+
>
165+
${['xs','s','m','l','xl','xxl'].map(
166+
(size) => Template({ ...args, ...row_args, size })
167+
)}
168+
</div>`
169+
)}
170+
<div style="margin-top:32px;">
171+
${uiIconsWithDirections.map(iconName => html`
172+
<div
173+
style=${styleMap({
174+
display: "flex",
175+
gap: "16px",
176+
})}
177+
>
178+
${uiIconSizes[iconName.replace(/(Left|Right|Up|Down)$/, '')]?.map((iconSize) =>
179+
Template({ ...args, setName: "ui", iconName: iconName + iconSize })
180+
)}
181+
${when(uiIconSizes[iconName]?.length == 0, () =>
182+
Template({ ...args, setName: "ui", iconName })
183+
)}
184+
</div>`
185+
)}
186+
</div>
187+
`;
188+
};

components/icon/stories/template.js

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { classMap } from "lit/directives/class-map.js";
33
import { ifDefined } from "lit/directives/if-defined.js";
44
import { unsafeSVG } from "lit/directives/unsafe-svg.js";
55

6-
import { fetchIconSVG, uiIcons, workflowIcons } from "./utilities.js";
6+
import { fetchIconSVG, uiIcons, uiIconSizes, workflowIcons } from "./utilities.js";
77

88
import "../index.css";
99

@@ -17,7 +17,7 @@ import "../index.css";
1717
* @description Icon template that renders an icon based on the provided icon name and set name.
1818
* @param {IconProps} props
1919
* @param {string} props.rootClass
20-
* @param {"s"|"m"|"l"|"xl"} props.size
20+
* @param {"xs"|"s"|"m"|"l"|"xl"|"xxl"} props.size
2121
* @param {"ui"|"workflow"} props.setName
2222
* @param {string} props.iconName - Icon name with or without the icon scale number appended. Names with the scale (e.g. 75, 100) will replace it based upon the value of 'size'.
2323
* @param {string} props.fill
@@ -48,22 +48,50 @@ export const Template = ({
4848

4949
let idKey = iconName;
5050

51-
// If a descriptor like Right, Left, Down, or Up is present for the Chevron or the
51+
// If icon set was not provided, try determine which icon set contains this icon.
52+
// Note: icon sets can contain the same icon name, with different icons.
53+
if (!['workflow','ui'].includes(setName)){
54+
if (workflowIcons.includes(idKey)) {
55+
setName = "workflow";
56+
} else if (uiIcons.includes(idKey.replace(/\d{2,3}$/, "").replace(/(Right|Left|Down|Up)$/, ""))) {
57+
setName = "ui";
58+
}
59+
}
60+
61+
if (!setName) {
62+
console.warn(
63+
`Icon: Could not determine the icon set for the provided icon name: ${idKey}.`
64+
);
65+
return html``;
66+
}
67+
68+
// If a descriptor like Right, Left, Down, or Up is present for the UI icons Chevron or
5269
// Arrow, use that only for the class and not the icon fetch.
5370
if (
71+
setName == "ui" &&
5472
uiIcons.some((c) => idKey.startsWith(c)) &&
5573
["Right", "Left", "Down", "Up"].some((c) => idKey.includes(c))
5674
) {
5775
idKey = idKey.replace(/(Right|Left|Down|Up)/, "");
5876
}
5977

60-
// If the icon name includes its scale, we want to leave that scale
61-
// If the icon name does not include scale, reformat it to match the provided sizing.
62-
// E.g. with a size of "s", the icon name "ChevronRight" would become "ChevronRight75".
78+
/**
79+
* Fallback UI Icon sizing number.
80+
*
81+
* If the icon name includes its scale, we want to leave that scale. This is preferred,
82+
* as UI icons do not use workflow icon sizing.
83+
*
84+
* If the UI icon name does not include scale, reformat it to match the provided sizing.
85+
* E.g. with a size of "s", the icon name "ChevronRight" would become "ChevronRight75".
86+
*/
6387
if (
88+
setName == "ui" &&
89+
// Exists in the list of available UI icons.
6490
uiIcons.includes(idKey.replace(/\d{2,3}$/, "")) &&
91+
// Does not already have size number at the end.
6592
!idKey.match(/^(?!\d).*\d{2,3}$/) &&
66-
!idKey.endsWith("Gripper")
93+
// Exclude some UI icons that do not (yet) have size numbers.
94+
uiIconSizes[idKey]?.length != 0
6795
) {
6896
let sizeVal;
6997
switch (size) {
@@ -85,23 +113,9 @@ export const Template = ({
85113

86114
idKey += sizeVal;
87115
iconName += sizeVal;
88-
89-
}
90-
91-
// Determine which icon set contains this icon.
92-
if (workflowIcons.includes(idKey)) {
93-
setName = "workflow";
94-
} else if (uiIcons.includes(idKey.replace(/\d{2,3}$/, ""))) {
95-
setName = "ui";
96-
}
97-
98-
if (!setName) {
99-
console.warn(
100-
`Icon: Could not determine the icon set for the provided icon name: ${idKey}.`
101-
);
102-
return html``;
103116
}
104117

118+
// Fetch SVG file markup, and set optional fill color.
105119
let inlineStyle;
106120
if (fill) inlineStyle = `color: ${fill}`;
107121
let icon;
@@ -110,11 +124,15 @@ export const Template = ({
110124
icon = fetchIconSVG({ iconName: idKey, setName, ...globals });
111125

112126
if (!icon) {
113-
console.warn(`Icon: ${idKey} not found.`);
127+
console.warn(`Icon: "${idKey}" was not found in the "${setName}" icon set.`);
114128
return html``;
115129
}
116130
}
117131

132+
/**
133+
* Classes to apply to the SVG element. Object as used by the classMap function.
134+
* @type {[name: string]: string | boolean | number}
135+
*/
118136
const classList = {
119137
[rootClass]: true,
120138
[`spectrum-UIIcon-${iconName}`]: !!(setName === "ui"),
@@ -136,7 +154,7 @@ export const Template = ({
136154
.map(([k]) => k)
137155
.join(" ")}"${
138156
inlineStyle ? ` style="${inlineStyle}"` : ""
139-
} focusable="false" aria-hidden="true" role="img" width="10" $1>`
157+
} focusable="false" aria-hidden="true" role="img" $1>`
140158
)
141159
)}`;
142160
}

0 commit comments

Comments
 (0)