Skip to content

Commit 0302314

Browse files
cdransfmarissahuysentruytrise-erpelding
committed
chore(storybook): review and complete storybook docs (#6180)
* feat(badge): ensure visual s2 fidelity (#6114) * docs(badge): update rendering-and-styling migration analysis Clarify that fixed positioning is documented in design system guidance and note new S2 badge variants (notification, indicator) tracked in SWC-1831. * feat(badge): add no-label CSS class when label slot is empty Add `swc-Badge--no-label` class via classMap when the default slot has no text content, enabling CSS targeting of icon-only badges. * fix(badge): updates padding block tokens and icon-only gap * feat(badge): support for swc-icon internal * feat(badge): icon only accessibility examples * fix(badge): size types passing into swc-icon * docs(badge): adds todo for missing variants * fix(badge): dynamically passes size to slotted icon * test(badge): anatomy test checks for children elements previously, we were checking for text content when the badge icon slot was just accepting strings. Now the anatomy story is using the swc-icon internal component, so it never has text content (it's got HTML). the badge test now checks for children.length instead. * fix(badge): disabled text control for icon-slot * fix(badge): a11y roles for icon only badges * fix(badge): inline padding - adds new --swc-badge-padding-inline-start custom prop to control the inline padding start of a badge. it changes when there's an icon + label vs. just the text label - also fixes the gap property so that we just redefine the custom prop for the badge gap instead * docs(badge): add todo for icon only badge size story * docs(rules): update docs on template vs custom html rendering * docs: badge examples updated * fix(badge): correct fallbacks for sized badge padding Without this fallback, the start padding on a badge without an icon would always resolve to the 75-scale token regardless of size, because --swc-badge-padding-inline-start was never set in the size override blocks. Adding --swc-badge-padding-inline as an intermediate fallback means size overrides propagate to both sides automatically, while the :has() rules can still override --swc-badge-padding-inline-start for the icon case. * revert(badge): medium stays default size; neutral is default variant * test(badge): update new default assertions * docs(badge): adds @todo to default sizing discrepancy comment * fix(badge): reduce selector specificity and refactor private padding tokens * fix(badge): padding block properties corrected * docs: correct updated css style guides with badge examples * docs: fix typo * docs(badge): use different badge variants per design docs * docs(badge): adds tickets to todo comments * style(progress-circle): clean up code styles (#6146) * chore(storybook): review and complete storybook docs * fix(storybook): revert icon test change to debug test failures * fix(storybook): changes to align w/progress circle being set to indeterminate by default * fix(storybook): correct test failure caused by string mismatch * fix(storybook): correct test failures * fix(testing): correct failing tests in 2nd gen * fix(storybook): correct test failures * chore(storybook): address feedback * chore(storybook): address feedback --------- Co-authored-by: Marissa Huysentruyt <69602589+marissahuysentruyt@users.noreply.github.com> Co-authored-by: rise-erpelding <54716846+rise-erpelding@users.noreply.github.com>
1 parent 1374086 commit 0302314

6 files changed

Lines changed: 232 additions & 42 deletions

File tree

2nd-gen/packages/swc/components/badge/stories/badge.stories.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,31 @@ argTypes['icon-slot'] = {
7777
'Accepts an icon element. The control is disabled. Use the Anatomy story to see icon usage. Enhancements to this control will be added in a future release.',
7878
};
7979

80+
// @todo: create a select dropdown with all available/acceptable icons for a component.
81+
// For now, this arg is turned off in the control table since the string doesn't get parsed as HTML: SWC-1853
82+
argTypes['icon-slot'] = {
83+
...argTypes['icon-slot'],
84+
control: false,
85+
description:
86+
'Accepts an icon element. The control is disabled. Use the Anatomy story to see icon usage. Enhancements to this control will be added in a future release.',
87+
};
88+
89+
argTypes.outline = {
90+
...argTypes.outline,
91+
table: {
92+
...argTypes.outline?.table,
93+
defaultValue: { summary: 'false' },
94+
},
95+
};
96+
97+
argTypes.subtle = {
98+
...argTypes.subtle,
99+
table: {
100+
...argTypes.subtle?.table,
101+
defaultValue: { summary: 'false' },
102+
},
103+
};
104+
80105
/**
81106
* Similar to [status lights](/docs/components-status-light--readme), they use color and text to convey status or category information.
82107
*
@@ -429,6 +454,50 @@ export const TextWrapping: Story = {
429454
tags: ['behaviors'],
430455
};
431456

457+
/**
458+
* Badges flow naturally within prose text to annotate inline content such as headings,
459+
* labels, list items, or table cells.
460+
*
461+
* Because `<swc-badge>` renders as `inline-flex`, it participates in the normal
462+
* text flow without any extra wrapper styling required. Use small (`s`) badges in
463+
* most inline contexts to avoid disrupting line height.
464+
*/
465+
export const Inline: Story = {
466+
render: (args) => html`
467+
<p>
468+
Design system components
469+
${template({
470+
...args,
471+
variant: 'accent',
472+
'default-slot': 'Beta',
473+
size: 's',
474+
})}
475+
</p>
476+
<p>
477+
API documentation
478+
${template({
479+
...args,
480+
variant: 'positive',
481+
'default-slot': 'Stable',
482+
size: 's',
483+
})}
484+
</p>
485+
<p>
486+
Legacy components
487+
${template({
488+
...args,
489+
variant: 'notice',
490+
'default-slot': 'Deprecated',
491+
size: 's',
492+
})}
493+
</p>
494+
`,
495+
parameters: {
496+
flexLayout: 'column-stretch',
497+
},
498+
tags: ['behaviors'],
499+
};
500+
432501
// ────────────────────────────────
433502
// ACCESSIBILITY STORIES
434503
// ────────────────────────────────

2nd-gen/packages/swc/components/divider/stories/divider.stories.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ argTypes['static-color'] = {
4242
options: [undefined, ...Divider.STATIC_COLORS],
4343
};
4444

45+
argTypes.vertical = {
46+
...argTypes.vertical,
47+
table: {
48+
...argTypes.vertical?.table,
49+
defaultValue: { summary: 'false' },
50+
},
51+
};
52+
4553
/**
4654
* A divider is a visual separator that brings clarity to a layout by grouping and dividing
4755
* content in close proximity. Dividers help establish rhythm and hierarchy, making it easier
@@ -219,6 +227,48 @@ export const StaticColors: Story = {
219227
};
220228
StaticColors.storyName = 'Static colors';
221229

230+
// ──────────────────────────────
231+
// BEHAVIORS STORIES
232+
// ──────────────────────────────
233+
234+
/**
235+
* ### Layout orientation
236+
*
237+
* Dividers can be oriented **horizontally** (default) or **vertically** to match
238+
* the layout they serve:
239+
*
240+
* - **Horizontal dividers** separate stacked content, such as sections beneath headings
241+
* - **Vertical dividers** separate side-by-side items in a flex row (e.g., navigation breadcrumbs, toolbars)
242+
*
243+
* Vertical dividers require the parent to have an **explicit height** (`block-size`) —
244+
* without it, `block-size: 100%` resolves to zero and the divider is invisible.
245+
*/
246+
export const LayoutOrientation: Story = {
247+
render: (args) => html`
248+
<nav
249+
style="display: flex; align-items: center; gap: 8px; block-size: 24px;"
250+
>
251+
<span>Overview</span>
252+
${template({ ...args, size: 's', vertical: true })}
253+
<span>Files</span>
254+
${template({ ...args, size: 's', vertical: true })}
255+
<span>Settings</span>
256+
</nav>
257+
<div style="margin-block-start: 16px;">
258+
<h4 style="margin: 0 0 8px 0;">Project details</h4>
259+
${template({ ...args, size: 'l' })}
260+
<p style="margin: 8px 0 0 0;">
261+
Review the project timeline and deliverables.
262+
</p>
263+
</div>
264+
`,
265+
parameters: {
266+
flexLayout: 'column-stretch',
267+
},
268+
tags: ['behaviors'],
269+
};
270+
LayoutOrientation.storyName = 'Layout orientation';
271+
222272
// ────────────────────────────────
223273
// ACCESSIBILITY STORIES
224274
// ────────────────────────────────

2nd-gen/packages/swc/components/progress-circle/stories/progress-circle.stories.ts

Lines changed: 98 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,8 @@ const sizeLabels = {
9191
export const Playground: Story = {
9292
tags: ['autodocs', 'dev'],
9393
args: {
94-
label: 'Uploading document',
94+
size: 'm',
95+
label: 'Processing request',
9596
},
9697
};
9798

@@ -102,7 +103,7 @@ export const Playground: Story = {
102103
export const Overview: Story = {
103104
tags: ['overview'],
104105
args: {
105-
label: 'Uploading document',
106+
label: 'Processing request',
106107
},
107108
};
108109

@@ -118,7 +119,6 @@ export const Overview: Story = {
118119
* 3. **Label** - Accessible text describing the operation (not visually rendered).
119120
*
120121
* > **A11y Note:** Light DOM children are not projected into the shadow tree, so content between the opening and closing tags does not supply an accessible name. Use the `label` attribute or property, or `aria-label` / `aria-labelledby` on the host.
121-
*
122122
*/
123123
export const Anatomy: Story = {
124124
render: () => html`
@@ -165,9 +165,6 @@ export const Sizes: Story = {
165165
)}
166166
`,
167167
tags: ['options'],
168-
args: {
169-
progress: 25,
170-
},
171168
};
172169

173170
/**
@@ -186,7 +183,6 @@ export const StaticColors: Story = {
186183
)}
187184
`,
188185
args: {
189-
progress: 60,
190186
label: 'Processing media',
191187
},
192188
tags: ['options'],
@@ -201,12 +197,34 @@ export const StaticColors: Story = {
201197
// ──────────────────────────
202198

203199
/**
204-
* When no `progress` value is set, the component displays an animated indeterminate
205-
* loading indicator. This is the default state.
206-
* The `aria-valuenow` attribute is removed, signaling to assistive technologies
207-
* that the operation duration is unknown.
200+
* Progress circles can show specific progress values from 0% to 100%.
201+
* Set the `progress` attribute to a value between 0 and 100 to represent determinate progress.
202+
* This automatically sets `aria-valuenow` to the provided value for screen readers.
203+
*/
204+
export const ProgressValues: Story = {
205+
render: (args) => html`
206+
${template({ ...args, progress: 0, label: 'Starting download' })}
207+
${template({ ...args, progress: 25, label: 'Downloading (25%)' })}
208+
${template({ ...args, progress: 50, label: 'Downloading (50%)' })}
209+
${template({ ...args, progress: 75, label: 'Downloading (75%)' })}
210+
${template({ ...args, progress: 100, label: 'Download complete' })}
211+
`,
212+
tags: ['states'],
213+
args: {
214+
size: 'm',
215+
},
216+
parameters: {
217+
'section-order': 2,
218+
},
219+
};
220+
ProgressValues.storyName = 'Progress values';
221+
222+
/**
223+
* The default state — when `progress` is not set, the component displays an animated
224+
* loading indicator. The `aria-valuenow` attribute is omitted, signaling to assistive
225+
* technologies that the operation duration is unknown.
208226
*
209-
* Use indeterminate progress when:
227+
* Use the default (no `progress`) when:
210228
* - The operation duration is unknown
211229
* - Progress cannot be accurately measured
212230
* - Multiple sub-operations are running in parallel
@@ -216,36 +234,80 @@ export const Indeterminate: Story = {
216234
args: {
217235
label: 'Processing request',
218236
},
219-
parameters: {
220-
'section-order': 1,
221-
},
222237
};
223238

239+
// ──────────────────────────────
240+
// BEHAVIORS STORIES
241+
// ──────────────────────────────
242+
224243
/**
225-
* Progress circles can show specific progress values from 0% to 100%.
226-
* Set the `progress` attribute to a value between 0 and 100 to represent determinate progress.
227-
* This automatically sets `aria-valuenow` to the provided value for screen readers.
244+
* A common pattern is pairing a progress circle with a button to communicate
245+
* that an action is in progress after the user clicks. Use `size="s"` to match
246+
* typical button heights and `static-color="white"` on high-emphasis (filled)
247+
* buttons where the icon sits on a colored background.
248+
*
249+
* Button loading states typically omit `progress` since the duration is unknown.
250+
*
251+
* @todo Refactor to use `<swc-button>` once the button component is available.
228252
*/
229-
export const ProgressValues: Story = {
230-
render: () => html`
231-
<swc-progress-circle
232-
progress="0"
233-
label="Starting download"
234-
></swc-progress-circle>
235-
<swc-progress-circle
236-
progress="25"
237-
label="Downloading (25%)"
238-
></swc-progress-circle>
239-
<swc-progress-circle
240-
progress="50"
241-
label="Downloading (50%)"
242-
></swc-progress-circle>
253+
export const LoadingButton: Story = {
254+
render: (args) => html`
255+
<button
256+
style="
257+
display: inline-flex;
258+
align-items: center;
259+
gap: 8px;
260+
padding: 6px 16px;
261+
border: none;
262+
border-radius: 16px;
263+
background: var(--spectrum-accent-background-color-default, #378ef0);
264+
color: #fff;
265+
font: inherit;
266+
font-size: 14px;
267+
cursor: default;
268+
opacity: 0.9;
269+
"
270+
disabled
271+
>
272+
${template({
273+
...args,
274+
size: 's',
275+
'static-color': 'white',
276+
label: 'Saving',
277+
})}
278+
Saving…
279+
</button>
280+
<button
281+
style="
282+
display: inline-flex;
283+
align-items: center;
284+
gap: 8px;
285+
padding: 6px 16px;
286+
border: 2px solid var(--spectrum-accent-background-color-default, #378ef0);
287+
border-radius: 16px;
288+
background: transparent;
289+
color: var(--spectrum-accent-background-color-default, #378ef0);
290+
font: inherit;
291+
font-size: 14px;
292+
cursor: default;
293+
opacity: 0.9;
294+
"
295+
disabled
296+
>
297+
${template({
298+
...args,
299+
size: 's',
300+
label: 'Processing',
301+
})}
302+
Processing…
303+
</button>
243304
`,
244-
tags: ['states'],
245305
parameters: {
246-
'section-order': 2,
306+
flexLayout: true,
247307
},
308+
tags: ['behaviors'],
248309
};
310+
LoadingButton.storyName = 'Loading button';
249311

250312
// ────────────────────────────────
251313
// ACCESSIBILITY STORIES
@@ -262,7 +324,7 @@ export const ProgressValues: Story = {
262324
* 2. **Labeling**: Uses the `label` attribute value as `aria-label`, or rely on `aria-label` / `aria-labelledby` you set on the host
263325
* 3. **Progress state** (determinate):
264326
* - Sets `aria-valuenow` with the current `progress` value
265-
* 4. **Loading state** (indeterminate):
327+
* 4. **Loading state** (indeterminate — default when `progress` is unset):
266328
* - When no `progress` value is set, `aria-valuenow` is omitted
267329
* - Screen readers understand this as an ongoing operation with unknown duration
268330
* 5. **Status communication**: Screen readers announce progress updates as values change
@@ -296,8 +358,7 @@ export const ProgressValues: Story = {
296358
export const Accessibility: Story = {
297359
tags: ['a11y'],
298360
args: {
299-
progress: 60,
300361
size: 'l',
301-
label: 'Uploading presentation slides',
362+
label: 'Syncing files',
302363
},
303364
};

2nd-gen/packages/swc/components/progress-circle/test/progress-circle.a11y.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ test.describe('Progress Circle - ARIA Snapshots', () => {
3333
'swc-progress-circle'
3434
);
3535
await expect(root).toMatchAriaSnapshot(`
36-
- progressbar "Uploading document"
36+
- progressbar "Processing request"
3737
`);
3838
});
3939

0 commit comments

Comments
 (0)