Skip to content

Commit 5a532e6

Browse files
author
Melissa Thompson
authored
feat(downstate): docs + implementation for example components (#2520)
* feat(downstate): docs + implementation for example components * docs: update mdx * docs: reorg, stories live within foundations * docs: decorator for down state dimension tokens * docs: fix mdx hierarchy console error * fix: small iconOnly button gets min perspective * docs: use markdown, update language * fix: disabled, readonly checkbox doesnt have down state * chore(button,checkbox): update package versions
1 parent 2ae0074 commit 5a532e6

13 files changed

+159
-9
lines changed

.storybook/decorators/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { makeDecorator, useEffect } from "@storybook/preview-api";
22
import { html } from "lit";
33

44
export { withContextWrapper } from "./contextsWrapper.js";
5+
export { withDownStateDimensionCapture } from "./withDownStateDimensionCapture.js";
56
export { withTestingPreviewWrapper } from "./withTestingPreviewWrapper.js";
67

78
/**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
export const withDownStateDimensionCapture = (selector) => (Story, context) => {
2+
const captureDownStateDimensions = () => {
3+
const components = document.querySelectorAll(selector);
4+
components.forEach((component) => {
5+
const { width, height } = component.getBoundingClientRect();
6+
component.style.setProperty('--spectrum-downstate-width', `${width}px`);
7+
component.style.setProperty('--spectrum-downstate-height', `${height}px`);
8+
});
9+
};
10+
11+
document.addEventListener("DOMContentLoaded", () => {
12+
// Wait to make sure the story is fully rendered (otherwise width/height can be wrong)
13+
setTimeout(() => {
14+
captureDownStateDimensions();
15+
}, 100);
16+
});
17+
18+
return Story(context);
19+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { Template } from "../../../components/button/stories/template";
2+
3+
export default {
4+
title: "Foundations/Down state",
5+
description:
6+
"Buttons allow users to perform an action or to navigate to another page. They have multiple styles for various needs, and are ideal for calling attention to where a user needs to do something in order to move forward in a flow.",
7+
component: "Button",
8+
args: {
9+
rootClass: "spectrum-Button",
10+
},
11+
parameters: {
12+
actions: {
13+
handles: ['click .spectrum-Button'],
14+
},
15+
status: {
16+
type: process.env.MIGRATED_PACKAGES.includes("button")
17+
? "migrated"
18+
: undefined,
19+
},
20+
},
21+
tags: ['foundation'],
22+
};
23+
24+
export const ButtonDownState = Template.bind({});
25+
ButtonDownState.args = {
26+
label: "Edit",
27+
variant: "accent",
28+
customStyles: {
29+
"--spectrum-downstate-width": "72px",
30+
"--spectrum-downstate-height": "32px"
31+
}
32+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { Template } from "../../../components/checkbox/stories/template";
2+
3+
export default {
4+
title: "Foundations/Down state",
5+
description:
6+
"Checkboxes allow users to select multiple items from a list of individual items, or mark one individual item as selected.",
7+
component: "Checkbox",
8+
args: {
9+
rootClass: "spectrum-Checkbox",
10+
},
11+
parameters: {
12+
actions: {
13+
handles: ['click input[type="checkbox"]'],
14+
},
15+
status: {
16+
type: process.env.MIGRATED_PACKAGES.includes("checkbox")
17+
? "migrated"
18+
: undefined,
19+
},
20+
},
21+
tags: ['foundation'],
22+
};
23+
24+
export const CheckboxDownState = Template.bind({});
25+
CheckboxDownState.args = {
26+
label: "Checkbox",
27+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { Meta, Story } from '@storybook/blocks';
2+
import * as Checkbox from './checkbox-down-state.stories.js';
3+
import * as Button from './button-down-state.stories.js';
4+
5+
<Meta title="Foundations/Down state" />
6+
7+
# Down state
8+
9+
Down state is a Spectrum 2 feature that creates the illusion of components being pressed-in when active. This functionality is already included in Spectrum 2 components that require down state in this project. It is implemented with a CSS transform. The implementation depends on the size of the interactable element, as shown in the examples below.
10+
11+
## Examples
12+
13+
### Minimum perspective
14+
15+
For elements that have a width of 24px or less, the minimum perspective token is used to apply the down state. One example of a component that uses this token is the checkbox:
16+
17+
<Story of={Checkbox.CheckboxDownState} />
18+
19+
In this case, we use the minimum perspective token:
20+
21+
```
22+
transform:
23+
perspective(var(--spectrum-component-size-minimum-perspective-down))
24+
translateZ(var(--spectrum-component-size-difference-down));
25+
```
26+
27+
### Calculated perspective
28+
29+
For elements that have a width of greater than 24px, we need to use the component's width and height to apply the down state. One example of a component that uses this logic is the button:
30+
31+
<Story of={Button.ButtonDownState} />
32+
33+
In this case, we use a max formula to calculate the perspective based on component width and height (this helps us account for components that may be very wide):
34+
35+
```
36+
transform:
37+
perspective(max(
38+
var(--spectrum-downstate-height),
39+
var(--spectrum-downstate-width) * var(--spectrum-component-size-width-ratio-down)
40+
))
41+
translateZ(var(--spectrum-component-size-difference-down));
42+
```
43+
44+
*Note that in this case, users are required to develop an implementation to determine the width and height of the component. Assign these values to the `--spectrum-downstate-width` and `--spectrum-downstate-height` custom properties in a `style` attribute on the HTML element to expose them for use in the CSS.*

.storybook/main.js

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ module.exports = {
1111
stories: [
1212
"../components/*/stories/*.stories.js",
1313
"./guides/*.mdx",
14+
"./foundations/*/*.mdx",
15+
"./foundations/*/*.stories.js",
1416
"./deprecated/*/*.stories.js",
1517
],
1618
rootDir: "../",

.storybook/manager.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import logo from "./assets/logo.svg";
77
import pkg from "./package.json";
88

99
// Load global styles
10-
import "@spectrum-css/vars/css/globals/index.css";
1110
import "@spectrum-css/vars/css/components/index.css";
11+
import "@spectrum-css/vars/css/globals/index.css";
1212

1313
import "@spectrum-css/vars/css/scales/spectrum-medium.css";
1414
import "@spectrum-css/vars/css/themes/spectrum-light.css";
@@ -53,5 +53,10 @@ addons.setConfig({
5353
}),
5454
sidebar: {
5555
showRoots: false,
56+
filters: {
57+
patterns: (item) => {
58+
return !item.tags.includes('foundation');
59+
}
60+
}
5661
},
5762
});

.storybook/preview.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ export const parameters = {
205205
options: {
206206
storySort: {
207207
method: "alphabetical",
208-
order: ['Guides', ['Contributing', '*', 'Adobe Code of Conduct', 'Changelog'], 'Components', '*'],
208+
order: ['Guides', ['Contributing', '*', 'Adobe Code of Conduct', 'Changelog'], 'Foundations', 'Components', '*'],
209209
includeNames: true,
210210
},
211211
},

components/button/index.css

+13-2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ governing permissions and limitations under the License.
2424
--spectrum-button-focus-ring-thickness: var(--spectrum-focus-indicator-thickness);
2525
--spectrum-button-focus-indicator-color: var(--spectrum-focus-indicator-color);
2626
--spectrum-button-intended-icon-size: var(--spectrum-workflow-icon-size-50);
27+
28+
/* stylelint-disable-next-line spectrum-tools/no-unknown-custom-properties */
29+
--spectrum-downstate-perspective: max(var(--spectrum-downstate-height), var(--spectrum-downstate-width) * var(--spectrum-component-size-width-ratio-down));
2730
}
2831

2932
.spectrum-Button--sizeS {
@@ -42,6 +45,10 @@ governing permissions and limitations under the License.
4245
--spectrum-button-bottom-to-text: var(--spectrum-button-bottom-to-text-small);
4346
--spectrum-button-top-to-icon: var(--spectrum-component-top-to-workflow-icon-75);
4447
--spectrum-button-intended-icon-size: var(--spectrum-workflow-icon-size-75);
48+
49+
&.spectrum-Button--iconOnly {
50+
--spectrum-downstate-perspective: var(--spectrum-component-size-minimum-perspective-down);
51+
}
4552
}
4653

4754
.spectrum-Button--sizeM {
@@ -147,17 +154,21 @@ governing permissions and limitations under the License.
147154
box-shadow: none;
148155
}
149156

157+
&:active {
158+
transform: perspective(var(--spectrum-downstate-perspective)) translateZ(var(--spectrum-component-size-difference-down));
159+
}
160+
150161
.spectrum-Icon {
151162
/* Any block-size difference between the intended workflow icon size and actual icon used.
152163
Helps support any existing use of smaller UI icons instead of intended Workflow icons. */
153164
--_icon-size-difference: max(0px,
154-
var(--spectrum-button-intended-icon-size) -
165+
var(--spectrum-button-intended-icon-size) -
155166
var(--spectrum-icon-block-size, var(--spectrum-button-intended-icon-size))
156167
);
157168

158169
margin-block-start: var(--mod-button-icon-margin-block-start,
159170
max(0px,
160-
var(--mod-button-top-to-icon, var(--spectrum-button-top-to-icon)) -
171+
var(--mod-button-top-to-icon, var(--spectrum-button-top-to-icon)) -
161172
var(--mod-button-border-width, var(--spectrum-button-border-width)) +
162173
(var(--_icon-size-difference, 0px) / 2)
163174
)

components/button/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@spectrum-css/button",
3-
"version": "12.0.3-next.0",
3+
"version": "14.0.0-next.2",
44
"description": "The Spectrum CSS button component",
55
"license": "Apache-2.0",
66
"author": "Adobe",

components/button/stories/button.stories.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { html } from "lit";
22
import { ifDefined } from "lit/directives/if-defined.js";
33
import { styleMap } from "lit/directives/style-map.js";
44
import { when } from "lit/directives/when.js";
5+
import { withDownStateDimensionCapture } from "../../../.storybook/decorators";
56

67
import { default as IconStories } from "@spectrum-css/icon/stories/icon.stories.js";
78
import { Template as Typography } from "@spectrum-css/typography/stories/template.js";
@@ -12,6 +13,7 @@ export default {
1213
description:
1314
"Buttons allow users to perform an action or to navigate to another page. They have multiple styles for various needs, and are ideal for calling attention to where a user needs to do something in order to move forward in a flow.",
1415
component: "Button",
16+
decorators: [withDownStateDimensionCapture('.spectrum-Button:not(:disabled)')],
1517
argTypes: {
1618
size: {
1719
name: "Size",
@@ -100,7 +102,7 @@ export default {
100102
name: "Layout",
101103
description: "How the buttons align in the preview (Storybook only).",
102104
type: { name: "string" },
103-
table: {
105+
table: {
104106
type: { summary: "string" },
105107
category: "Advanced"
106108
},
@@ -349,4 +351,4 @@ Wrapping.args = {
349351
showIconOnlyButton: false,
350352
variant: "accent",
351353
label: "An example of text overflow behavior within the button component. When the button text is too long for the horizontal space available, it wraps to form another line.",
352-
};
354+
};

components/checkbox/index.css

+8-1
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,12 @@ governing permissions and limitations under the License.
150150
}
151151
}
152152

153+
&:not(.is-readOnly):active {
154+
.spectrum-Checkbox-input:not(:disabled) + .spectrum-Checkbox-box {
155+
transform: perspective(var(--spectrum-component-size-minimum-perspective-down)) translateZ(var(--spectrum-component-size-difference-down));
156+
}
157+
}
158+
153159
/* Selected Invalid */
154160
&.is-invalid {
155161
.spectrum-Checkbox-input:checked + .spectrum-Checkbox-box,
@@ -372,6 +378,7 @@ governing permissions and limitations under the License.
372378
}
373379
}
374380
}
381+
375382
/* stylelint-enable max-nesting-depth */
376383

377384
.spectrum-Checkbox-label {
@@ -571,7 +578,7 @@ governing permissions and limitations under the License.
571578
outline-style: auto;
572579
outline-offset: var(--highcontrast-checkbox-focus-indicator-gap, var(--mod-checkbox-focus-indicator-gap, var(--spectrum-checkbox-focus-indicator-gap)));
573580
/* stylelint-disable-next-line declaration-block-no-redundant-longhand-properties */
574-
outline-width: var(--mod-focus-indicator-thickness, var(--spectrum-focus-indicator-thickness));
581+
outline-width: var(--mod-focus-indicator-thickness, var(--spectrum-focus-indicator-thickness));
575582

576583
&::after {
577584
box-shadow:

components/checkbox/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@spectrum-css/checkbox",
3-
"version": "8.1.6-next.0",
3+
"version": "14.0.0-next.2",
44
"description": "The Spectrum CSS checkbox component",
55
"license": "Apache-2.0",
66
"author": "Adobe",

0 commit comments

Comments
 (0)