Skip to content

Commit dc5f820

Browse files
feat(accordion): add direct actions (#4020)
1 parent 7f48b7c commit dc5f820

File tree

6 files changed

+244
-10
lines changed

6 files changed

+244
-10
lines changed

.changeset/spicy-rings-cough.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
"@spectrum-css/accordion": minor
3+
---
4+
5+
Accordion now supports direct actions. Direct actions, which may consist of a quiet action button or a switch, or both, may be added to each accordion item's heading. Direct action items are vertically centered within the heading's first line of text for all sizes and densities, and maintain their own individual key focus states.
6+
7+
To allow the same level of customizability found in other elements within this component, the following --mod custom properties have been added:
8+
9+
- "--mod-accordion-item-direct-actions-height",
10+
- "--mod-accordion-item-direct-actions-spacing",
11+
- "--mod-accordion-item-direct-actions-vertical-spacing"

components/accordion/dist/metadata.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@
2222
".spectrum-Accordion-item.is-open > .spectrum-Accordion-itemHeading .spectrum-Accordion-itemIndicator",
2323
".spectrum-Accordion-item:first-child",
2424
".spectrum-Accordion-itemContent",
25+
".spectrum-Accordion-itemDirectActions",
2526
".spectrum-Accordion-itemHeader",
2627
".spectrum-Accordion-itemHeader.spectrum-Accordion-itemHeader:active",
2728
".spectrum-Accordion-itemHeader:focus-visible",
29+
".spectrum-Accordion-itemHeader:has(+ .spectrum-Accordion-itemDirectActions)",
2830
".spectrum-Accordion-itemHeader:hover",
2931
".spectrum-Accordion-itemHeading",
3032
".spectrum-Accordion-itemIndicator",
@@ -60,6 +62,9 @@
6062
"--mod-accordion-item-content-font-style",
6163
"--mod-accordion-item-content-font-weight",
6264
"--mod-accordion-item-content-line-height",
65+
"--mod-accordion-item-direct-actions-height",
66+
"--mod-accordion-item-direct-actions-spacing",
67+
"--mod-accordion-item-direct-actions-vertical-spacing",
6368
"--mod-accordion-item-focus-indicator-color",
6469
"--mod-accordion-item-focus-indicator-gap",
6570
"--mod-accordion-item-focus-indicator-thickness",
@@ -74,6 +79,7 @@
7479
"--mod-accordion-item-header-font-style",
7580
"--mod-accordion-item-header-font-weight",
7681
"--mod-accordion-item-header-line-height",
82+
"--mod-accordion-item-header-to-direct-actions-space",
7783
"--mod-accordion-item-header-top-to-text-space",
7884
"--mod-accordion-item-min-block-size",
7985
"--mod-accordion-item-minimum-height",
@@ -131,6 +137,9 @@
131137
"--spectrum-accordion-item-content-font-style",
132138
"--spectrum-accordion-item-content-font-weight",
133139
"--spectrum-accordion-item-content-line-height",
140+
"--spectrum-accordion-item-direct-actions-height",
141+
"--spectrum-accordion-item-direct-actions-spacing",
142+
"--spectrum-accordion-item-direct-actions-vertical-spacing",
134143
"--spectrum-accordion-item-focus-indicator-color",
135144
"--spectrum-accordion-item-focus-indicator-gap",
136145
"--spectrum-accordion-item-focus-indicator-thickness",
@@ -145,6 +154,7 @@
145154
"--spectrum-accordion-item-header-font-style",
146155
"--spectrum-accordion-item-header-font-weight",
147156
"--spectrum-accordion-item-header-line-height",
157+
"--spectrum-accordion-item-header-to-direct-actions-space",
148158
"--spectrum-accordion-item-header-top-to-text-space",
149159
"--spectrum-accordion-item-min-block-size",
150160
"--spectrum-accordion-item-minimum-height",
@@ -227,6 +237,7 @@
227237
"--spectrum-neutral-content-color-hover",
228238
"--spectrum-neutral-content-color-key-focus",
229239
"--spectrum-sans-font-family-stack",
240+
"--spectrum-spacing-100",
230241
"--spectrum-transparent-black-100",
231242
"--spectrum-transparent-black-25",
232243
"--spectrum-transparent-black-300"

components/accordion/index.css

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
--spectrum-accordion-item-content-area-top-to-content: var(--spectrum-accordion-content-area-top-to-content);
3232
--spectrum-accordion-item-content-area-bottom-to-content: var(--spectrum-accordion-content-area-bottom-to-content);
3333
--spectrum-accordion-divider-thickness: var(--spectrum-divider-thickness-small);
34+
--spectrum-accordion-item-direct-actions-height: var(--spectrum-component-height-100);
35+
--spectrum-accordion-item-header-to-direct-actions-space: var(--spectrum-spacing-100); /* same for all sizes */
3436

3537
/* Text header */
3638
--spectrum-accordion-item-header-font: var(--spectrum-sans-font-family-stack);
@@ -40,6 +42,7 @@
4042
--spectrum-accordion-item-header-line-height: var(--spectrum-line-height-100);
4143

4244
--spectrum-accordion-item-header-cursor: pointer;
45+
--spectrum-accordion-item-direct-actions-spacing: var(--spectrum-spacing-100);
4346
--spectrum-accordion-animation-duration: var(--spectrum-animation-duration-100);
4447

4548
/* Text body */
@@ -72,6 +75,12 @@
7275
var(--mod-accordion-item-header-top-to-text-space, var(--spectrum-accordion-item-header-top-to-text-space)) + var(--mod-accordion-item-header-bottom-to-text-space, var(--spectrum-accordion-item-header-bottom-to-text-space)) + (var(--mod-accordion-item-header-font-size, var(--spectrum-accordion-item-header-font-size)) * var(--mod-accordion-item-header-line-height, var(--spectrum-accordion-item-header-line-height)))
7376
);
7477

78+
/* Calculated vertical spacing for action button and switch to center them within the accordion item */
79+
--spectrum-accordion-item-direct-actions-vertical-spacing: calc(
80+
(var(--mod-accordion-item-min-block-size, var(--spectrum-accordion-item-min-block-size)) -
81+
var(--mod-accordion-item-direct-actions-height, var(--spectrum-accordion-item-direct-actions-height))) / 2
82+
);
83+
7584
/* Right-to-left adjustments for transforms */
7685
&:dir(rtl) {
7786
--spectrum-logical-rotation: matrix(-1, 0, 0, 1, 0, 0);
@@ -100,6 +109,7 @@
100109
--spectrum-accordion-item-header-top-to-text-space: var(--spectrum-accordion-top-to-text-small);
101110
--spectrum-accordion-item-header-bottom-to-text-space: var(--spectrum-accordion-bottom-to-text-small);
102111
--spectrum-accordion-top-to-disclosure-indicator: var(--spectrum-field-top-to-disclosure-icon-small);
112+
--spectrum-accordion-item-direct-actions-height: var(--spectrum-component-height-75); /* component height for switch and action button */
103113
}
104114

105115
.spectrum-Accordion--sizeL {
@@ -116,6 +126,7 @@
116126
--spectrum-accordion-item-header-top-to-text-space: var(--spectrum-accordion-top-to-text-large);
117127
--spectrum-accordion-item-header-bottom-to-text-space: var(--spectrum-accordion-bottom-to-text-large);
118128
--spectrum-accordion-top-to-disclosure-indicator: var(--spectrum-field-top-to-disclosure-icon-large);
129+
--spectrum-accordion-item-direct-actions-height: var(--spectrum-component-height-200);
119130
}
120131

121132
.spectrum-Accordion--sizeXL {
@@ -132,6 +143,7 @@
132143
--spectrum-accordion-item-header-top-to-text-space: var(--spectrum-accordion-top-to-text-extra-large);
133144
--spectrum-accordion-item-header-bottom-to-text-space: var(--spectrum-accordion-bottom-to-text-extra-large);
134145
--spectrum-accordion-top-to-disclosure-indicator: var(--spectrum-field-top-to-disclosure-icon-extra-large);
146+
--spectrum-accordion-item-direct-actions-height: var(--spectrum-component-height-300);
135147
}
136148

137149
.spectrum-Accordion--compact {
@@ -237,6 +249,7 @@
237249
margin: 0;
238250
position: relative;
239251
box-sizing: border-box;
252+
display: flex;
240253
}
241254

242255
.spectrum-Accordion-itemIndicator {
@@ -268,15 +281,17 @@
268281

269282
/* Focusable button that expands/collapses the accordion item. */
270283
.spectrum-Accordion-itemHeader {
284+
overflow-wrap: anywhere;
285+
word-break: normal;
271286
box-sizing: border-box;
272287
position: relative;
273-
274288
display: flex;
275289
align-items: flex-start;
276290
justify-content: flex-start;
277291

278292
/* start spacing controlled by edge to disclosure icon spacing */
279293
padding-inline: 0 var(--mod-accordion-edge-to-content-area, var(--spectrum-accordion-edge-to-content-area));
294+
padding-block: 0; /* reset user-agent styles */
280295
line-height: var(--mod-accordion-item-header-line-height, var(--spectrum-accordion-item-header-line-height));
281296

282297
text-overflow: ellipsis;
@@ -313,6 +328,20 @@
313328
background-color: var(--spectrum-accordion-background-color-down);
314329
color: var(--spectrum-accordion-item-header-color-down);
315330
}
331+
332+
&:has(+ .spectrum-Accordion-itemDirectActions) {
333+
/* set spacing between header and direct actions, whether or not noInlinePadding variant is used */
334+
padding-inline-end: var(--mod-accordion-item-header-to-direct-actions-space, var(--spectrum-accordion-item-header-to-direct-actions-space));
335+
}
336+
}
337+
338+
.spectrum-Accordion-itemDirectActions {
339+
margin-inline-end: var(--mod-accordion-edge-to-content-area, var(--spectrum-accordion-edge-to-content-area));
340+
display: inline-flex;
341+
gap: var(--mod-accordion-item-direct-actions-spacing, var(--spectrum-accordion-item-direct-actions-spacing));
342+
343+
/* margin needs to be set on top and bottom to keep compact XL items vertically centered and prevent them from growing vertically */
344+
margin-block: var(--mod-accordion-item-direct-actions-vertical-spacing, var(--spectrum-accordion-item-direct-actions-vertical-spacing));
316345
}
317346

318347
.spectrum-Accordion-item.is-open {

components/accordion/stories/accordion.stories.js

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
import { default as IconStories } from "@spectrum-css/icon/stories/icon.stories.js";
12
import { Sizes } from "@spectrum-css/preview/decorators";
23
import { disableDefaultModes } from "@spectrum-css/preview/modes";
34
import { isQuiet, size } from "@spectrum-css/preview/types";
45
import metadata from "../dist/metadata.json";
56
import packageJson from "../package.json";
6-
import { AccordionGroup, testsContent as accordionContent } from "./accordion.test.js";
7+
import { AccordionGroup, testsContent as accordionContent, directActionsContent, longerContent } from "./accordion.test.js";
78
import { Template } from "./template.js";
89

910
/**
@@ -60,7 +61,36 @@ export default {
6061
},
6162
control: { type: "boolean" },
6263
},
63-
isQuiet
64+
isQuiet,
65+
hasActionButtons: {
66+
name: "Has action buttons",
67+
description: "Adds an action button to each accordion item header, in the direct actions section.",
68+
type: { name: "boolean" },
69+
table: {
70+
type: { summary: "boolean" },
71+
category: "Direct actions",
72+
},
73+
control: { type: "boolean" },
74+
},
75+
actionButtonIconName: {
76+
name: "Action button icon",
77+
...(IconStories?.argTypes?.iconName ?? {}),
78+
if: { arg: "hasActionButtons", truthy: true },
79+
table: {
80+
type: { summary: "string" },
81+
category: "Direct actions",
82+
},
83+
},
84+
hasSwitches: {
85+
name: "Has switches",
86+
description: "Adds a switch to each accordion item header, in the direct actions section.",
87+
type: { name: "boolean" },
88+
table: {
89+
type: { summary: "boolean" },
90+
category: "Direct actions",
91+
},
92+
control: { type: "boolean" },
93+
},
6494
},
6595
args: {
6696
rootClass: "spectrum-Accordion",
@@ -70,6 +100,9 @@ export default {
70100
disableAll: false,
71101
isQuiet: false,
72102
hasNoInlinePadding: false,
103+
hasActionButtons: false,
104+
actionButtonIconName: "Circle",
105+
hasSwitches: false,
73106
},
74107
parameters: {
75108
actions: {
@@ -121,9 +154,9 @@ export const CustomWidth = AccordionGroup.bind({});
121154
CustomWidth.tags = ["!dev"];
122155
CustomWidth.storyName = "Custom width";
123156
CustomWidth.args = {
124-
items: accordionContent,
157+
items: longerContent,
125158
customStyles: {
126-
"--mod-accordion-item-width": "500px",
159+
"--mod-accordion-item-width": "auto",
127160
},
128161
};
129162
CustomWidth.parameters = {
@@ -158,6 +191,18 @@ Spacious.parameters = {
158191
};
159192
Spacious.storyName = "Density: Spacious";
160193

194+
/**
195+
* Direct actions within accordion items are supported. A quiet
196+
* [action button](/?path=/docs/actionbutton--default), a
197+
* [switch](/?path=/docs/switch--default), or both can be added to
198+
* each accordion item header.
199+
*/
200+
export const DirectActions = Template.bind({});
201+
DirectActions.tags = ["!dev"];
202+
DirectActions.args = {
203+
items: directActionsContent
204+
};
205+
161206
/**
162207
* Individual accordion items can be disabled by applying the `.is-disabled` class to the
163208
* `.spectrum-Accordion-item` element. This example also demonstrates the use of the disabled

0 commit comments

Comments
 (0)