From 4fba00fc2254bd1da3a5cd450491e14924bd30e8 Mon Sep 17 00:00:00 2001 From: Casey Eickhoff <48574582+caseyisonit@users.noreply.github.com> Date: Tue, 2 Dec 2025 13:40:20 -0700 Subject: [PATCH 01/11] initial stubbing (#5915) * chore: two ways of working with markdown files for guides * chore: cursor rule for migrating markdown to mdx if needed * chore: stubbed docs and ordered them * chore: lint fix --- .cursor/rules/storybook-mdx-conversion.mdc | 117 ++++++++++++++++++ .vscode/settings.json | 7 +- .../swc/.storybook/DocumentTemplate.mdx | 58 +++++++++ .../get-started/first-gen-vs-second-gen.mdx | 13 ++ .../swc/.storybook/get-started/migration.mdx | 15 +++ .../{guides => get-started}/welcome.mdx | 0 .../.storybook/get-started/what-is-swc.mdx | 15 +++ .../get-started/when-to-use-swc.mdx | 5 + .../accessibility-guides.mdx | 15 +++ .../.storybook/guides/contributor-guide.mdx | 10 ++ .../guides/getting-started-guide.mdx | 7 ++ .../.storybook/guides/project-planning.mdx | 15 +++ .../swc/.storybook/guides/react-wrappers.mdx | 15 +++ .../swc/.storybook/guides/style-guide.mdx | 15 +++ 2nd-gen/packages/swc/.storybook/main.ts | 20 ++- 2nd-gen/packages/swc/.storybook/preview.ts | 41 +++++- CONTRIBUTOR-DOCS/README.mdx | 87 +++++++++++++ 17 files changed, 448 insertions(+), 7 deletions(-) create mode 100644 .cursor/rules/storybook-mdx-conversion.mdc create mode 100644 2nd-gen/packages/swc/.storybook/DocumentTemplate.mdx create mode 100644 2nd-gen/packages/swc/.storybook/get-started/first-gen-vs-second-gen.mdx create mode 100644 2nd-gen/packages/swc/.storybook/get-started/migration.mdx rename 2nd-gen/packages/swc/.storybook/{guides => get-started}/welcome.mdx (100%) create mode 100644 2nd-gen/packages/swc/.storybook/get-started/what-is-swc.mdx create mode 100644 2nd-gen/packages/swc/.storybook/get-started/when-to-use-swc.mdx create mode 100644 2nd-gen/packages/swc/.storybook/guides/accessibility-guides/accessibility-guides.mdx create mode 100644 2nd-gen/packages/swc/.storybook/guides/contributor-guide.mdx create mode 100644 2nd-gen/packages/swc/.storybook/guides/getting-started-guide.mdx create mode 100644 2nd-gen/packages/swc/.storybook/guides/project-planning.mdx create mode 100644 2nd-gen/packages/swc/.storybook/guides/react-wrappers.mdx create mode 100644 2nd-gen/packages/swc/.storybook/guides/style-guide.mdx create mode 100644 CONTRIBUTOR-DOCS/README.mdx diff --git a/.cursor/rules/storybook-mdx-conversion.mdc b/.cursor/rules/storybook-mdx-conversion.mdc new file mode 100644 index 00000000000..86c0a6bf7a5 --- /dev/null +++ b/.cursor/rules/storybook-mdx-conversion.mdc @@ -0,0 +1,117 @@ +# Storybook MDX conversion + +Converts markdown files to MDX format compatible with Storybook rendering. + +## When to apply + +Apply this rule when converting `.md` files to `.mdx` files for display in Storybook, particularly for documentation pages in the 2nd-gen SWC Storybook guides. + +## Conversion steps + +### 1. File extension and imports + +- Change file extension from `.md` to `.mdx` +- Add Storybook imports at the top of the file: + +```typescript +import { Meta } from '@storybook/addon-docs/blocks'; +``` + +- Add a blank line after imports + +### 2. Meta tag + +- Add a `` tag after the imports +- The title should match the document's main heading +- Add a blank line after the Meta tag + +### 3. Convert HTML comments to JSX comments + +Replace HTML comments with JSX-style comments: + +**Before (Markdown):** + +```markdown + +``` + +**After (MDX):** + +```mdx +{/* Document title (editable) */} +``` + +### 4. Preserve all other content + +- Keep all markdown syntax as-is (headings, lists, links, code blocks, etc.) +- Keep all `
` and `` HTML elements unchanged +- Keep all list formatting and indentation unchanged +- Preserve all relative link paths (e.g., `./01_contributor-guides/README.md`) +- Do not modify any content within `
` blocks or navigation lists + +## Example transformation + +**Before (README.md):** + +```markdown + + +# Contributor Documentation + + + +
+In this doc + +- [About Spectrum Web Components](#about-spectrum-web-components) + +
+ + + +## About Spectrum Web Components + +Content here... +``` + +**After (README.mdx):** + +```mdx +import { Meta } from '@storybook/addon-docs/blocks'; + + +{/* Document title (editable) */} + +# Contributor Documentation + +{/* Generated TOC - DO NOT EDIT */} + +
+In this doc + +- [About Spectrum Web Components](#about-spectrum-web-components) + +
+ +{/* Document content (editable) */} + +## About Spectrum Web Components + +Content here... +``` + +## Critical rules + +1. **Only add imports and Meta tag** - Do not modify any other structural elements +2. **Preserve exact formatting** - Keep all whitespace, indentation, and line breaks +3. **Convert ALL HTML comments** - Every `` must become `{/* comment */}` +4. **Keep markdown links** - Do not convert `.md` links to `.mdx` (Storybook may need the original paths) +5. **Blank lines matter** - Maintain blank line after imports and after Meta tag + +## Common mistakes to avoid + +❌ Don't change the document's heading structure +❌ Don't modify navigation lists or TOC content +❌ Don't convert markdown to JSX (keep lists as markdown lists) +❌ Don't add extra formatting or styling +❌ Don't forget to convert ALL HTML comments to JSX comments diff --git a/.vscode/settings.json b/.vscode/settings.json index e3ed778119b..b804f557b18 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -31,5 +31,10 @@ }, "typescript.tsdk": "node_modules/typescript/lib", "lit-plugin.strict": true, - "cSpell.words": ["activedescendant", "coachmark", "valuetext"] + "cSpell.words": ["activedescendant", "coachmark", "valuetext"], + "[mdx]": { + "editor.codeActionsOnSave": { + "source.organizeImports": "never" + } + } } diff --git a/2nd-gen/packages/swc/.storybook/DocumentTemplate.mdx b/2nd-gen/packages/swc/.storybook/DocumentTemplate.mdx new file mode 100644 index 00000000000..40519f81b61 --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/DocumentTemplate.mdx @@ -0,0 +1,58 @@ +import { + Meta, + Title, + Primary, + Controls, + Stories, + Markdown, + ArgTypes, + Description, +} from '@storybook/addon-docs/blocks'; +import '@spectrum-web-components/tabs/sp-tabs.js'; +import '@spectrum-web-components/tabs/sp-tab.js'; +import '@spectrum-web-components/tabs/sp-tab-panel.js'; + + + + + +This template will likely be going away in the future, but for now it's here to help us get started. + +<sp-tabs id="component-doc-tabs" size="xl" selected="overview" auto label="Component Documentation"> + <sp-tab value="overview">Overview</sp-tab> + <sp-tab value="usage">Usage</sp-tab> + <sp-tab value="accessibility">Accessibility</sp-tab> + <sp-tab value="api">API</sp-tab> + <sp-tab value="examples">Examples</sp-tab> + <sp-tab-panel value="overview" style={{ flexDirection: 'column' }}> + <Description /> + <Primary /> + <Controls /> + + ### third level + + hello + + #### fourth level + + bananas my friends + </sp-tab-panel> + <sp-tab-panel value="usage" style={{ flexDirection: 'column' }}> + variations + + </sp-tab-panel> + <sp-tab-panel value="accessibility" style={{ flexDirection: 'column' }}> + Heres some shit about accessibility + </sp-tab-panel> + <sp-tab-panel value="api" style={{ flexDirection: 'column' }}> + <ArgTypes /> + </sp-tab-panel> + <sp-tab-panel value="examples" style={{ flexDirection: 'column' }}> + <Stories /> + </sp-tab-panel> + +</sp-tabs> + +## Feedback + +Have feedback or questions? [Open an issue](https://github.com/adobe/spectrum-web-components/issues/new/choose). diff --git a/2nd-gen/packages/swc/.storybook/get-started/first-gen-vs-second-gen.mdx b/2nd-gen/packages/swc/.storybook/get-started/first-gen-vs-second-gen.mdx new file mode 100644 index 00000000000..f95d9b979fc --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/get-started/first-gen-vs-second-gen.mdx @@ -0,0 +1,13 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + +<Meta title="First Gen vs Second Gen/First Gen vs Second Gen" /> + +# First Gen vs Second Gen + +First Gen SWC is the original implementation of SWC, built with the Spectrum CSS framework. + +Second Gen SWC is the new implementation of SWC, built with the Lit framework. + +## First Gen SWC + +## Second Gen SWC diff --git a/2nd-gen/packages/swc/.storybook/get-started/migration.mdx b/2nd-gen/packages/swc/.storybook/get-started/migration.mdx new file mode 100644 index 00000000000..cd55315b0c6 --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/get-started/migration.mdx @@ -0,0 +1,15 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + +<Meta title="First Gen vs Second Gen/Migration from 1st-gen to 2nd-gen" /> + +# Migration from 1st-gen to 2nd-gen + +## What is the migration process? + +The migration process from 1st-gen to 2nd-gen is a gradual process. + +## What are the benefits of migrating to 2nd-gen? + +The benefits of migrating to 2nd-gen are: + +- Improved performance diff --git a/2nd-gen/packages/swc/.storybook/guides/welcome.mdx b/2nd-gen/packages/swc/.storybook/get-started/welcome.mdx similarity index 100% rename from 2nd-gen/packages/swc/.storybook/guides/welcome.mdx rename to 2nd-gen/packages/swc/.storybook/get-started/welcome.mdx diff --git a/2nd-gen/packages/swc/.storybook/get-started/what-is-swc.mdx b/2nd-gen/packages/swc/.storybook/get-started/what-is-swc.mdx new file mode 100644 index 00000000000..2024895f276 --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/get-started/what-is-swc.mdx @@ -0,0 +1,15 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + +<Meta title="What is SWC?" /> + +# What is SWC? + +SWC is a library of web components that implements the Adobe Spectrum design system. + +It is a collection of components that can be used to build web applications. + +It is built with Lit and TypeScript. + +It is open-source and available on GitHub. + +It is developed by Adobe Design Engineering. diff --git a/2nd-gen/packages/swc/.storybook/get-started/when-to-use-swc.mdx b/2nd-gen/packages/swc/.storybook/get-started/when-to-use-swc.mdx new file mode 100644 index 00000000000..8b5796a0e8b --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/get-started/when-to-use-swc.mdx @@ -0,0 +1,5 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + +<Meta title="When to use SWC?" /> + +# When to use SWC? diff --git a/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/accessibility-guides.mdx b/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/accessibility-guides.mdx new file mode 100644 index 00000000000..9ed5375f2ee --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/accessibility-guides.mdx @@ -0,0 +1,15 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + +<Meta title="Accessibility guides/Accessibility guides" /> + +# Accessibility guides + +This guide will help you understand the accessibility guides for SWC. + +## What is the accessibility guides? + +The accessibility guides are a set of rules that help you write code that is accessible. + +## What are the rules? + +The rules are: diff --git a/2nd-gen/packages/swc/.storybook/guides/contributor-guide.mdx b/2nd-gen/packages/swc/.storybook/guides/contributor-guide.mdx new file mode 100644 index 00000000000..42d2bd92fab --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/guides/contributor-guide.mdx @@ -0,0 +1,10 @@ +import { Meta, Markdown } from '@storybook/addon-docs/blocks'; +import ReadMe from '../../../../../CONTRIBUTOR-DOCS/README.md?raw'; + +<Meta title="Contributor guide" /> + +What is cool about this is that we can use MDX to write the documentation for the contributor docs, and then use the Storybook to render it. + +This also allows us to use the same documentation for the contributor docs and the Storybook guides but control which docs are shown in the Storybook. + +<Markdown>{ReadMe}</Markdown> diff --git a/2nd-gen/packages/swc/.storybook/guides/getting-started-guide.mdx b/2nd-gen/packages/swc/.storybook/guides/getting-started-guide.mdx new file mode 100644 index 00000000000..56b61af01a7 --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/guides/getting-started-guide.mdx @@ -0,0 +1,7 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + +<Meta title="Getting started guide" /> + +# Getting started guide + +This guide will help you get started with SWC as a developer. diff --git a/2nd-gen/packages/swc/.storybook/guides/project-planning.mdx b/2nd-gen/packages/swc/.storybook/guides/project-planning.mdx new file mode 100644 index 00000000000..d5a87b28c36 --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/guides/project-planning.mdx @@ -0,0 +1,15 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + +<Meta title="Project planning" /> + +# Project planning + +This guide will help you understand the project planning for SWC. + +## What is the project planning? + +The project planning is a set of rules that help you write code that is consistent with the SWC style. + +## What are the rules? + +The rules are: diff --git a/2nd-gen/packages/swc/.storybook/guides/react-wrappers.mdx b/2nd-gen/packages/swc/.storybook/guides/react-wrappers.mdx new file mode 100644 index 00000000000..7ca4e4383db --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/guides/react-wrappers.mdx @@ -0,0 +1,15 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + +<Meta title="React wrappers" /> + +# React wrappers + +This guide will help you understand the React wrappers for SWC. + +## What are the React wrappers? + +The React wrappers are a set of React components that help you use SWC in your React applications. + +## What are the rules? + +The rules are: diff --git a/2nd-gen/packages/swc/.storybook/guides/style-guide.mdx b/2nd-gen/packages/swc/.storybook/guides/style-guide.mdx new file mode 100644 index 00000000000..fd57952990f --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/guides/style-guide.mdx @@ -0,0 +1,15 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + +<Meta title="Style guide" /> + +# Style guide + +This guide will help you understand the style guide for SWC. + +## What is the style guide? + +The style guide is a set of rules that help you write code that is consistent with the SWC style. + +## What are the rules? + +The rules are: diff --git a/2nd-gen/packages/swc/.storybook/main.ts b/2nd-gen/packages/swc/.storybook/main.ts index 3f29c12473a..0584d96a736 100644 --- a/2nd-gen/packages/swc/.storybook/main.ts +++ b/2nd-gen/packages/swc/.storybook/main.ts @@ -1,6 +1,6 @@ -import { resolve, dirname } from 'path'; -import { mergeConfig } from 'vite'; +import { dirname, resolve } from 'path'; import { fileURLToPath } from 'url'; +import { mergeConfig } from 'vite'; const __dirname = dirname(fileURLToPath(import.meta.url)); @@ -8,15 +8,25 @@ const __dirname = dirname(fileURLToPath(import.meta.url)); const config = { stories: [ { - directory: 'guides', - files: '*.@(md|mdx)', - titlePrefix: 'Guides', + directory: 'get-started', + files: '*.mdx', + titlePrefix: 'Get Started', }, { directory: '../components', files: '*/stories/*.stories.ts', titlePrefix: 'Components', }, + { + directory: 'guides', + files: '*.mdx', + titlePrefix: 'Guides', + }, + { + directory: 'guides', + files: '**/*.mdx', + titlePrefix: 'Guides', + }, ], framework: '@storybook/web-components-vite', core: { diff --git a/2nd-gen/packages/swc/.storybook/preview.ts b/2nd-gen/packages/swc/.storybook/preview.ts index baef8b1d57a..530a0f6ea8c 100644 --- a/2nd-gen/packages/swc/.storybook/preview.ts +++ b/2nd-gen/packages/swc/.storybook/preview.ts @@ -1,8 +1,9 @@ /** @type { import('@storybook/web-components').Preview } */ +import '../tokens/global-vars.css'; import '../tokens/index.css'; import '../tokens/light-vars.css'; import '../tokens/medium-vars.css'; -import '../tokens/global-vars.css'; +import DocumentTemplate from './DocumentTemplate.mdx'; import { setCustomElementsManifest } from '@storybook/web-components'; import { @@ -49,6 +50,44 @@ const preview = { ], }, }, + docs: { + codePanel: true, + page: DocumentTemplate, + toc: { + contentsSelector: '.sbdocs-content', + headingSelector: 'h2, h3', + ignoreSelector: '#primary', + disable: false, + unsafeTocbotOptions: { + orderedList: false, + }, + }, + }, + options: { + storySort: { + method: 'alphabetical-by-kind', + order: [ + 'Get Started', + [ + 'Welcome to 2nd-gen SWC', + 'What is SWC?', + 'When to use SWC?', + 'First Gen vs Second Gen', + ], + 'Components', + 'Guides', + [ + 'Getting started guide', + 'Contributor guide', + 'Style guide', + 'Project planning', + 'Accessibility guides', + 'React wrappers', + ], + 'Resources', + ], + }, + }, }, tags: ['autodocs'], }; diff --git a/CONTRIBUTOR-DOCS/README.mdx b/CONTRIBUTOR-DOCS/README.mdx new file mode 100644 index 00000000000..4e6cbc87830 --- /dev/null +++ b/CONTRIBUTOR-DOCS/README.mdx @@ -0,0 +1,87 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + +<Meta title="MDX in CONTRIBUTOR-DOCS" /> +{/* Document title (editable) */} + +# Contributor Documentation + +{/* Generated TOC - DO NOT EDIT */} + +<details open> +<summary><strong>In this doc</strong></summary> + +- [About Spectrum Web Components](#about-spectrum-web-components) +- [About the 1st-gen-to-2nd-gen transition](#about-the-1st-gen-to-2nd-gen-transition) +- [About these docs](#about-these-docs) + +</details> + +<details open> +<summary><strong>Beneath this doc</strong></summary> + +- [Contributor guides](01_contributor-guides/README.md) + - [Getting involved](01_contributor-guides/01_getting-involved.md) + - [Using the issue tracker](01_contributor-guides/02_using-the-issue-tracker.md) + - [Working in the SWC repo](01_contributor-guides/03_working-in-the-swc-repo.md) + - [Making a pull request](01_contributor-guides/04_making-a-pull-request.md) + - [Participating in PR reviews](01_contributor-guides/05_participating-in-pr-reviews.md) + - [Releasing SWC](01_contributor-guides/06_releasing-swc.md) + - [Authoring contributor docs](01_contributor-guides/07_authoring-contributor-docs/README.md) + - [Patching dependencies](01_contributor-guides/08_patching-dependencies.md) + - [Accessibility testing](01_contributor-guides/09_accessibility-testing.md) +- [Style guide](02_style-guide/README.md) +- [Project planning](03_project-planning/README.md) + - [Objectives and strategy](03_project-planning/01_objectives-and-strategy.md) + - [Workstreams](03_project-planning/02_workstreams/README.md) + - [Components](03_project-planning/03_components/README.md) + - [Milestones](03_project-planning/04_milestones/README.md) +- [Accessbility Guide](04_accessibility_guides/README.md) + - [Semantic HTML and ARIA](04_accessibility_guides/01_semantic_html_aria.md) + - [Accessible pattern libraries](04_accessibility_guides/02_accessible_pattern_libraries.md) + - [Keyboard testing](04_accessibility_guides/03_keyboard_testing.md) + - [Screen reader testing](04_accessibility_guides/04_screen_reader_testing.md) + - [Wave toolbar testing](04_accessibility_guides/05_wave_toolbar_testing.md) + - [Accessibility resources](04_accessibility_guides/06_accessibility_resources.md) + +</details> + +{/* Document content (editable) */} + +## About Spectrum Web Components + +Spectrum Web Components (SWC) is a library of web components that implements Adobe's Spectrum design system. + +While SWC is used primarily by Adobe product teams, it is open-sourced and available for general use. + +SWC is developed by a core team in Adobe Design Engineering, but we welcome contributions from inside and outside Adobe. + +## About the 1st-gen-to-2nd-gen transition + +Spectrum Web Components is currently in transition from its first generation (1st-gen) to its second generation (2nd-gen). + +- To understand how this transition affects the SWC code base, see [Repository Structure](./01_contributor-guides/03_working-in-the-swc-repo.md#repository-structure). +- To understand the motivation for this transition, see [Objectives and Strategy](./03_project-planning/01_objectives-and-strategy.md). + +## About these docs + +These docs contain essential information about the SWC project for both maintainers (members of the core team) and contributors from outside the core team. + +The docs are organized into three main sections to help you find the information you need: + +**[Contributor Guides](./01_contributor-guides/README.md)** - Topical guides for working on the project. This section includes guides for getting started, understanding processes, and accomplishing specific tasks like adding new components or editing these contributor docs themselves. + +**[Style Guide](./02_style-guide/README.md)** - Comprehensive style guide covering project-wide conventions and area-specific rules. This section is useful for human reference and for AI-assisted work, documenting our approaches to linting, JSDoc conventions, component structure, and other coding standards. + +**[Accessbility Guide](./04_accessbility_guides/README.md)** - Accessibility guide covering essential accessibility knowledge and practices for customers and contributors to Spectrum Web Components. + +**[Project Planning](./03_project-planning/README.md)** - Strategic planning documentation including objectives, workstreams, component roadmaps, and milestones. This section contains: + +- **[Objectives and Strategy](./03_project-planning/01_objectives-and-strategy.md)** - Strategic context for the 1st-gen-to-2nd-gen transition, including our goals and approach. + +- **[Workstreams](./03_project-planning/02_workstreams/README.md)** - Workstream-centric view of cross-cutting work affecting many or all components, helping us work toward specific objectives and coordinate efforts. + +- **[Components](./03_project-planning/03_components/README.md)** - Component-centric view of individual components and how they're affected by multiple workstreams, useful for understanding each component's roadmap and status. + +- **[Milestones](./03_project-planning/04_milestones/README.md)** - Information about project milestones and their goals. + +Together, the Workstreams and Components views help us manage the project roadmap, ensuring we make progress on strategic objectives while maintaining clarity about the state and evolution of individual components. From afbb34225bc583e9b1942159b44b75e28fbfc1dc Mon Sep 17 00:00:00 2001 From: Nikki Massaro <5090492+nikkimk@users.noreply.github.com> Date: Thu, 4 Dec 2025 21:14:35 -0500 Subject: [PATCH 02/11] docs(a11y): added a11y guides to storybook (#5919) * docs(a11y): added a11y guides to storybook * docs(a11y): fixed typo --- .../accessibility-guides/00_overview.mdx | 162 ++++++++++++++++++ .../01_semantic_html_aria.mdx | 5 + .../02_accessible_pattern_libraries.mdx | 5 + .../03_keyboard_testing.mdx | 5 + .../04_screen_reader_testing.mdx | 5 + .../05_wave_toolbar_testing.mdx | 5 + .../06_accessibility_resources.mdx | 5 + .../accessibility-guides.mdx | 15 -- 2nd-gen/packages/swc/.storybook/preview.ts | 9 + 9 files changed, 201 insertions(+), 15 deletions(-) create mode 100644 2nd-gen/packages/swc/.storybook/guides/accessibility-guides/00_overview.mdx create mode 100644 2nd-gen/packages/swc/.storybook/guides/accessibility-guides/01_semantic_html_aria.mdx create mode 100644 2nd-gen/packages/swc/.storybook/guides/accessibility-guides/02_accessible_pattern_libraries.mdx create mode 100644 2nd-gen/packages/swc/.storybook/guides/accessibility-guides/03_keyboard_testing.mdx create mode 100644 2nd-gen/packages/swc/.storybook/guides/accessibility-guides/04_screen_reader_testing.mdx create mode 100644 2nd-gen/packages/swc/.storybook/guides/accessibility-guides/05_wave_toolbar_testing.mdx create mode 100644 2nd-gen/packages/swc/.storybook/guides/accessibility-guides/06_accessibility_resources.mdx delete mode 100644 2nd-gen/packages/swc/.storybook/guides/accessibility-guides/accessibility-guides.mdx diff --git a/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/00_overview.mdx b/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/00_overview.mdx new file mode 100644 index 00000000000..45fe0463719 --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/00_overview.mdx @@ -0,0 +1,162 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + +<Meta title="Accessibility guides/Overview" /> + +# Accessibility guides + +This guide provides essential accessibility knowledge and practices for customers and contributors to Spectrum Web Components. Building and using accessible components ensures that all users, regardless of ability, can effectively interact with web applications. + +## What is accessibility? + +**Accessibility** (often abbreviated as **a11y**) is the practice of making web content and applications usable by as many people as possible. This means designing and developing in ways that remove barriers preventing people with disabilities from perceiving, understanding, navigating, and interacting with digital content. + +In the context of web components, accessibility ensures that custom elements work seamlessly with assistive technologies and follow established patterns that users have come to expect. + +## Why accessibility matters + +### User inclusion + +Accordiing to the [World Health Organization](https://www.who.int/news-room/fact-sheets/detail/disability-and-health), approximately one in six people, or 16%% of the world's population, lives with some form of disability. Building accessible components ensures your applications serve the widest possible audience. + +### Ethical considerations + +Building accessible software is simply the right thing to do. Digital content has become essential to modern life, and excluding people with disabilities from accessing it perpetuates inequality. + +### Business benefits + +- **Larger market reach**: More users can access your applications +- **Better SEO**: Accessible HTML often improves search engine optimization +- **Improved usability for everyone**: Accessibility features benefit all users (e.g., captions help in noisy environments) +- **Reduced legal risk**: Proactive accessibility reduces litigation exposure +- **Increased compatibility**: with more web-enabled devices and assistive technologies being adopted by users + +### Legal requirements + +Many jurisdictions have legal requirements for digital accessibility: + +- **[Americans with Disabilities Act (ADA)](hhttps://www.ada.gov/topics/intro-to-ada/)** requires federal and state government entities as well as private entities that own, operate, lease, or lease to places of public accommodation must be accessible to people with disabilities +- **[Section 508](https://www.section508.gov/)** applies to US federal government entities but impacts any entity that does buisness with the US federal government +- **[European Accessibility Act](https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=COM%3A2015%3A0615%3AFINa)** establishes accessbility standards for the EU; applies to "applies to any business’s product or service that is sold or in use within the Eurozone, not just EU member state businesses" [deque blog post](https://www.deque.com/blog/eu-web-accessibility-compliance-and-legislation/) +- **[Accessibility for Ontarians with Disabilities Act (AODA)](https://www.ontario.ca/laws/statute/05a11a)** "applies to every person or organization in the public and private sectors of the Province of Ontario, including the Legislative Assembly of Ontario" to comply with defined accessbility guidelines for EU member states + +## Types of disabilities + +When building accessible components, consider these categories of disabilities: + +### Visual disabilities + +- Blindness: Complete inability to see +- Low vision: Reduced visual acuity that cannot be corrected with glasses +- Color blindness: Difficulty distinguishing between certain colors +- Light sensitivity: Difficulty with bright lights or certain color contrasts + +### Auditory disabilities + +- Deafness: Complete inability to hear +- Hard of hearing: Partial hearing loss +- Audio processing disorders: Difficulty processing auditory information + +### Motor disabilities + +- Limited fine motor control: Difficulty with precise movements like clicking small targets +- Tremors or spasms: Involuntary movements affecting interaction +- Paralysis: Inability to move certain body parts +- Repetitive stress injuries: Pain or difficulty from repeated motions + +### Cognitive, learning, and neurological disabilities + +- Learning disabilities: Dyslexia, dyscalculia, and other processing differences +- Memory impairments: Difficulty retaining or recalling information +- Attention disorders: Difficulty maintaining focus +- Autism spectrum disorders: Different sensory processing and communication patterns +- Seizure disorders: Different types of epilepsy and migraines, often triggered by visual or auditory stimuli + +### Temporary and situational disabilities + +- Temporary: Broken arm, eye surgery recovery, ear infection +- Situational: Bright sunlight affecting screen visibility, noisy environment, holding a baby while trying to navigate with one hand + +## Assistive technologies + +Users interact with web components using various assistive technologies: + +### Screen readers + +- **[JAWS](https://www.freedomscientific.com/products/software/jaws/)**: Popular Windows screen reader, often used with Chrome or Edge browsers +- **[NVDA](https://www.nvaccess.org/about-nvda/)**: Free, open-source Windows screen reader, often used with Firefox browsers +- **[VoiceOver](hhttps://support.apple.com/guide/voiceover/turn-voiceover-on-or-off-vo2682/mac)**: Built-in screen reader for macOS and iOS, often used with Safari browsers +- **[TalkBack](https://support.google.com/accessibility/android/answer/6007100?hl=en)**: Built-in screen reader for Android, often used with Chrome browsers +- **[Narrator](https://support.microsoft.com/en-us/windows/complete-guide-to-narrator-e4397a0d-ef4f-b386-d8ae-c172f109bdb1)**: Built-in Windows screen reader, often used with Edge browsers + +### Alternative input methods + +- **Keyboard navigation**: Users navigate without a mouse using <kbd>Tab</kbd>, arrow keys, <kbd>Enter</kbd>, <kbd>Space</kbd>, and <kbd>Escape</kbd> +- **Voice control**: Software like Dragon NaturallySpeaking allows voice commands +- **Switch devices**: Single or dual-switch systems for users with limited mobility +- **Eye tracking**: Systems that track eye movement for navigation + +### Visual assistance tools + +- **Screen magnification**: Software that enlarges portions of the screen +- **High contrast modes**: Operating system settings that increase contrast +- **Custom stylesheets**: User-defined CSS to override default styles + +## Web Content Accessibility Guidelines (WCAG) + +The **[Web Content Accessibility Guidelines (WCAG)](https://www.w3.org/WAI/standards-guidelines/wcag/glance/)** are the international standard for web accessibility, developed by the World Wide Web Consortium (W3C). + +### Purpose + +WCAG provides a single shared standard for web content accessibility that meets the needs of individuals, organizations, and governments internationally. + +### Organization + +WCAG is organized around four principles (often remembered as **POUR**): + +1. **Perceivable**: Information and user interface components must be presentable to users in ways they can perceive +2. **Operable**: User interface components and navigation must be operable +3. **Understandable**: Information and the operation of user interface must be understandable +4. **Robust**: Content must be robust enough to be interpreted by a wide variety of user agents, including assistive technologies and future tools + +### Conformance levels + +WCAG defines three conformance levels: + +- **Level A**: The minimum level of accessibility. Addresses the most basic web accessibility features +- **Level AA**: The commonly targeted level. Addresses the biggest and most common barriers for disabled users +- **Level AAA**: The highest level. Provides the greatest level of accessibility but is not always achievable for all content + +**Target for Spectrum Web Components**: Level AA conformance is the standard we aim to achieve, as it represents best practices for most web content. + +## Authoring Tool Accessibility Guidelines (ATAG) + +The **[Authoring Tool Accessibility Guidelines (ATAG)](https://www.w3.org/WAI/standards-guidelines/atag/)** provide standards for tools used to create web content, including component libraries, content management systems, and development frameworks. + +### Why ATAG matters for component libraries + +Spectrum Web Components is an authoring tool in the sense that it provides building blocks for creating web content and applications. ATAG is relevant because: + +1. **Accessible by default**: Components should make it easy to create accessible content without requiring deep accessibility expertise. (Our components should handle as much semantic HTML and ARIA internally as much as possible.) +2. **Support accessible content creation**: Components should not create barriers to producing accessible applications. (It should be possible to use our components in and accessible way.) +3. **Promote accessibility**: Documentation and APIs should encourage accessible patterns. (Our documentation and APIs should encourage accessible patterns.) + +### ATAG principles + +ATAG has two main parts: + +- **Part A**: Make the authoring tool user interface accessible (the component library itself must be usable by developers with disabilities) +- **Part B**: Support the production of accessible content (components should facilitate creating accessible applications) + +## Resources + +For deeper understanding and ongoing reference, consult these authoritative sources: + +- [W3C Web Accessibility Initiative (WAI)](https://www.w3.org/WAI/) - The main hub for web accessibility standards and resources +- [WCAG 2.1 Guidelines](https://www.w3.org/TR/WCAG21/) - The complete specification for web content accessibility +- [ATAG 2.0 Overview](https://www.w3.org/WAI/standards-guidelines/atag/) - Understanding authoring tool accessibility +- [WebAIM Introduction to Web Accessibility](https://webaim.org/intro/) - Practical introduction to accessibility concepts +- [The A11y Project Checklist](https://www.a11yproject.com/checklist/) - A beginner-friendly accessibility checklist + +## Next steps + +Explore the guides in this section to learn specific accessibility practices. diff --git a/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/01_semantic_html_aria.mdx b/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/01_semantic_html_aria.mdx new file mode 100644 index 00000000000..db829e9cae1 --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/01_semantic_html_aria.mdx @@ -0,0 +1,5 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + +<Meta title="Accessibility guides/Semantic HTML and ARIA" /> + +# Semantic HTML and ARIA diff --git a/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/02_accessible_pattern_libraries.mdx b/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/02_accessible_pattern_libraries.mdx new file mode 100644 index 00000000000..8bb1b264225 --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/02_accessible_pattern_libraries.mdx @@ -0,0 +1,5 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + +<Meta title="Accessibility guides/Accessible pattern libraries" /> + +# Accessible pattern libraries diff --git a/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/03_keyboard_testing.mdx b/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/03_keyboard_testing.mdx new file mode 100644 index 00000000000..5a37b291c7b --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/03_keyboard_testing.mdx @@ -0,0 +1,5 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + +<Meta title="Accessibility guides/Keyboard testing" /> + +# Keyboard testing diff --git a/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/04_screen_reader_testing.mdx b/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/04_screen_reader_testing.mdx new file mode 100644 index 00000000000..85439fdd4ad --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/04_screen_reader_testing.mdx @@ -0,0 +1,5 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + +<Meta title="Accessibility guides/Screen reader testing" /> + +# Screen reader testing diff --git a/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/05_wave_toolbar_testing.mdx b/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/05_wave_toolbar_testing.mdx new file mode 100644 index 00000000000..79489e92261 --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/05_wave_toolbar_testing.mdx @@ -0,0 +1,5 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + +<Meta title="Accessibility guides/Wave toolbar testing" /> + +# Wave toolbar testing diff --git a/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/06_accessibility_resources.mdx b/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/06_accessibility_resources.mdx new file mode 100644 index 00000000000..46e7c47276e --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/06_accessibility_resources.mdx @@ -0,0 +1,5 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + +<Meta title="Accessibility guides/Accessibility resources" /> + +# Accessibility resources diff --git a/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/accessibility-guides.mdx b/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/accessibility-guides.mdx deleted file mode 100644 index 9ed5375f2ee..00000000000 --- a/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/accessibility-guides.mdx +++ /dev/null @@ -1,15 +0,0 @@ -import { Meta } from '@storybook/addon-docs/blocks'; - -<Meta title="Accessibility guides/Accessibility guides" /> - -# Accessibility guides - -This guide will help you understand the accessibility guides for SWC. - -## What is the accessibility guides? - -The accessibility guides are a set of rules that help you write code that is accessible. - -## What are the rules? - -The rules are: diff --git a/2nd-gen/packages/swc/.storybook/preview.ts b/2nd-gen/packages/swc/.storybook/preview.ts index 530a0f6ea8c..9e8b07d4390 100644 --- a/2nd-gen/packages/swc/.storybook/preview.ts +++ b/2nd-gen/packages/swc/.storybook/preview.ts @@ -82,6 +82,15 @@ const preview = { 'Style guide', 'Project planning', 'Accessibility guides', + [ + 'Overview', + 'Semantic HTML and ARIA', + 'Accessible pattern libraries', + 'Keyboard testing', + 'Screen reader testing', + 'Wave toolbar testing', + 'Accessibility resources' + ], 'React wrappers', ], 'Resources', From 054a200acedd6fdd06b14d78f9991b385db2a4c8 Mon Sep 17 00:00:00 2001 From: Casey Eickhoff <48574582+caseyisonit@users.noreply.github.com> Date: Fri, 5 Dec 2025 08:23:16 -0700 Subject: [PATCH 03/11] chore: two doc blocks to get custom docs added to the template (#5917) * chore: two doc blocks to get custom docs added to the template * chore: clean upa few things * chore: usage stories and descriptions for custom doc blocks * chore: streamlining tags in stories and created capitalize utility * chore: review fixes * chore: updated tags in stories to new pattern --- .vscode/settings.json | 2 +- .../core/components/divider/Divider.types.ts | 2 + .../progress-circle/ProgressCircle.base.ts | 3 +- .../progress-circle/ProgressCircle.types.ts | 1 + .../core/shared/utilities/capitalize.ts | 32 +++++++ .../packages/core/shared/utilities/index.ts | 13 +++ .../swc/.storybook/DocumentTemplate.mdx | 23 ++--- .../swc/.storybook/blocks/SpectrumDocs.tsx | 67 +++++++++++++++ .../swc/.storybook/blocks/SpectrumStories.tsx | 41 +++++++++ .../get-started/first-gen-vs-second-gen.mdx | 14 +++- .../swc/.storybook/get-started/migration.mdx | 15 ---- ...ources.mdx => accessibility_resources.mdx} | 0 ...s.mdx => accessible_pattern_libraries.mdx} | 0 ...board_testing.mdx => keyboard_testing.mdx} | 0 .../{00_overview.mdx => overview.mdx} | 0 ..._testing.mdx => screen_reader_testing.mdx} | 0 ...c_html_aria.mdx => semantic_html_aria.mdx} | 0 ...r_testing.mdx => wave_toolbar_testing.mdx} | 0 2nd-gen/packages/swc/.storybook/main.ts | 32 +++++-- .../packages/swc/.storybook/preview-head.html | 5 ++ 2nd-gen/packages/swc/.storybook/preview.ts | 6 +- .../components/asset/stories/asset.stories.ts | 1 + .../packages/swc/components/badge/Badge.ts | 1 + .../components/badge/stories/badge.stories.ts | 35 ++++---- .../swc/components/divider/Divider.ts | 9 +- .../divider/stories/divider.a11y.mdx | 15 ++++ .../divider/stories/divider.stories.ts | 61 ++++++++++++-- .../progress-circle/ProgressCircle.ts | 12 +-- .../stories/progress-circle.a11y.mdx | 43 ++++++++++ .../stories/progress-circle.stories.ts | 83 ++++++++++++++----- .../stories/progress-circle.usage.mdx | 9 ++ .../stories/status-light.stories.ts | 23 ++--- 32 files changed, 423 insertions(+), 125 deletions(-) create mode 100644 2nd-gen/packages/core/shared/utilities/capitalize.ts create mode 100644 2nd-gen/packages/core/shared/utilities/index.ts create mode 100644 2nd-gen/packages/swc/.storybook/blocks/SpectrumDocs.tsx create mode 100644 2nd-gen/packages/swc/.storybook/blocks/SpectrumStories.tsx delete mode 100644 2nd-gen/packages/swc/.storybook/get-started/migration.mdx rename 2nd-gen/packages/swc/.storybook/guides/accessibility-guides/{06_accessibility_resources.mdx => accessibility_resources.mdx} (100%) rename 2nd-gen/packages/swc/.storybook/guides/accessibility-guides/{02_accessible_pattern_libraries.mdx => accessible_pattern_libraries.mdx} (100%) rename 2nd-gen/packages/swc/.storybook/guides/accessibility-guides/{03_keyboard_testing.mdx => keyboard_testing.mdx} (100%) rename 2nd-gen/packages/swc/.storybook/guides/accessibility-guides/{00_overview.mdx => overview.mdx} (100%) rename 2nd-gen/packages/swc/.storybook/guides/accessibility-guides/{04_screen_reader_testing.mdx => screen_reader_testing.mdx} (100%) rename 2nd-gen/packages/swc/.storybook/guides/accessibility-guides/{01_semantic_html_aria.mdx => semantic_html_aria.mdx} (100%) rename 2nd-gen/packages/swc/.storybook/guides/accessibility-guides/{05_wave_toolbar_testing.mdx => wave_toolbar_testing.mdx} (100%) create mode 100644 2nd-gen/packages/swc/components/divider/stories/divider.a11y.mdx create mode 100644 2nd-gen/packages/swc/components/progress-circle/stories/progress-circle.a11y.mdx create mode 100644 2nd-gen/packages/swc/components/progress-circle/stories/progress-circle.usage.mdx diff --git a/.vscode/settings.json b/.vscode/settings.json index b804f557b18..f2e480e57d2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -31,7 +31,7 @@ }, "typescript.tsdk": "node_modules/typescript/lib", "lit-plugin.strict": true, - "cSpell.words": ["activedescendant", "coachmark", "valuetext"], + "cSpell.words": ["activedescendant", "AUTODOCS", "coachmark", "valuetext"], "[mdx]": { "editor.codeActionsOnSave": { "source.organizeImports": "never" diff --git a/2nd-gen/packages/core/components/divider/Divider.types.ts b/2nd-gen/packages/core/components/divider/Divider.types.ts index 1cef3379e58..25aee5d3dd9 100644 --- a/2nd-gen/packages/core/components/divider/Divider.types.ts +++ b/2nd-gen/packages/core/components/divider/Divider.types.ts @@ -16,3 +16,5 @@ export const DIVIDER_VALID_SIZES: ElementSize[] = ['s', 'm', 'l'] as const; export const DIVIDER_STATIC_COLORS = ['white', 'black'] as const; export type DividerStaticColor = (typeof DIVIDER_STATIC_COLORS)[number]; + +export type DividerSize = (typeof DIVIDER_VALID_SIZES)[number]; diff --git a/2nd-gen/packages/core/components/progress-circle/ProgressCircle.base.ts b/2nd-gen/packages/core/components/progress-circle/ProgressCircle.base.ts index 553f6ab63f5..a56e68518e8 100644 --- a/2nd-gen/packages/core/components/progress-circle/ProgressCircle.base.ts +++ b/2nd-gen/packages/core/components/progress-circle/ProgressCircle.base.ts @@ -20,6 +20,7 @@ import { getLabelFromSlot } from '@spectrum-web-components/core/shared/get-label import { PROGRESS_CIRCLE_VALID_SIZES, + ProgressCircleSize, ProgressCircleStaticColor, } from './ProgressCircle.types.js'; @@ -40,7 +41,7 @@ import { * @fires progress-change - Dispatched when the progress value changes */ export abstract class ProgressCircleBase extends SizedMixin(SpectrumElement, { - validSizes: PROGRESS_CIRCLE_VALID_SIZES, + validSizes: PROGRESS_CIRCLE_VALID_SIZES as ProgressCircleSize[], }) { // ───────────────────────── // API TO OVERRIDE diff --git a/2nd-gen/packages/core/components/progress-circle/ProgressCircle.types.ts b/2nd-gen/packages/core/components/progress-circle/ProgressCircle.types.ts index ae243bbe1fb..cf0072a4a62 100644 --- a/2nd-gen/packages/core/components/progress-circle/ProgressCircle.types.ts +++ b/2nd-gen/packages/core/components/progress-circle/ProgressCircle.types.ts @@ -30,3 +30,4 @@ export type ProgressCircleStaticColorS2 = export type ProgressCircleStaticColor = | ProgressCircleStaticColorS1 | ProgressCircleStaticColorS2; +export type ProgressCircleSize = (typeof PROGRESS_CIRCLE_VALID_SIZES)[number]; diff --git a/2nd-gen/packages/core/shared/utilities/capitalize.ts b/2nd-gen/packages/core/shared/utilities/capitalize.ts new file mode 100644 index 00000000000..9b0a34108c2 --- /dev/null +++ b/2nd-gen/packages/core/shared/utilities/capitalize.ts @@ -0,0 +1,32 @@ +/** + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +/** + * Capitalizes the first character of a string. + * + * @param str - The string to capitalize + * @returns The capitalized string, or an empty string if the input is not a string + * + * @example + * ```typescript + * capitalize('hello') // Returns: 'Hello' + * capitalize('world') // Returns: 'World' + * capitalize('') // Returns: '' + * capitalize(undefined) // Returns: '' + * ``` + */ +export function capitalize(str?: string): string { + if (typeof str !== 'string') { + return ''; + } + return str.charAt(0).toUpperCase() + str.slice(1); +} diff --git a/2nd-gen/packages/core/shared/utilities/index.ts b/2nd-gen/packages/core/shared/utilities/index.ts new file mode 100644 index 00000000000..da21d19be32 --- /dev/null +++ b/2nd-gen/packages/core/shared/utilities/index.ts @@ -0,0 +1,13 @@ +/** + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +export { capitalize } from './capitalize.js'; diff --git a/2nd-gen/packages/swc/.storybook/DocumentTemplate.mdx b/2nd-gen/packages/swc/.storybook/DocumentTemplate.mdx index 40519f81b61..c232c6920bc 100644 --- a/2nd-gen/packages/swc/.storybook/DocumentTemplate.mdx +++ b/2nd-gen/packages/swc/.storybook/DocumentTemplate.mdx @@ -4,10 +4,12 @@ import { Primary, Controls, Stories, - Markdown, ArgTypes, Description, + Subtitle, } from '@storybook/addon-docs/blocks'; +import { SpectrumDocs } from './blocks/SpectrumDocs'; +import { SpectrumStories } from './blocks/SpectrumStories'; import '@spectrum-web-components/tabs/sp-tabs.js'; import '@spectrum-web-components/tabs/sp-tab.js'; import '@spectrum-web-components/tabs/sp-tab-panel.js'; @@ -15,8 +17,7 @@ import '@spectrum-web-components/tabs/sp-tab-panel.js'; <Meta isTemplate /> <Title /> - -This template will likely be going away in the future, but for now it's here to help us get started. +<Subtitle /> <sp-tabs id="component-doc-tabs" size="xl" selected="overview" auto label="Component Documentation"> <sp-tab value="overview">Overview</sp-tab> @@ -28,26 +29,18 @@ This template will likely be going away in the future, but for now it's here to <Description /> <Primary /> <Controls /> - - ### third level - - hello - - #### fourth level - - bananas my friends </sp-tab-panel> <sp-tab-panel value="usage" style={{ flexDirection: 'column' }}> - variations - + <SpectrumDocs tag="usage" /> </sp-tab-panel> <sp-tab-panel value="accessibility" style={{ flexDirection: 'column' }}> - Heres some shit about accessibility + <SpectrumDocs tag="a11y" /> </sp-tab-panel> <sp-tab-panel value="api" style={{ flexDirection: 'column' }}> - <ArgTypes /> + <ArgTypes /> </sp-tab-panel> <sp-tab-panel value="examples" style={{ flexDirection: 'column' }}> + <SpectrumDocs tag="examples" /> <Stories /> </sp-tab-panel> diff --git a/2nd-gen/packages/swc/.storybook/blocks/SpectrumDocs.tsx b/2nd-gen/packages/swc/.storybook/blocks/SpectrumDocs.tsx new file mode 100644 index 00000000000..d0286d35fd3 --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/blocks/SpectrumDocs.tsx @@ -0,0 +1,67 @@ +/// <reference types="vite/client" /> +import { useOf } from '@storybook/addon-docs/blocks'; +import React, { useEffect, useState } from 'react'; + +const TAGS = ['overview', 'usage', 'a11y', 'examples']; + +// Glob import all MDX files from component stories directories as compiled React components +const mdxModules = import.meta.glob<{ default: React.ComponentType }>( + '../../components/**/*.mdx', + { + eager: false, + } +); + +/** + * A block that dynamically loads and renders MDX documentation + * based on the current component's title and the specified tag. + * + * @param of - The Storybook meta or story to resolve the component from + * @param tag - The MDX filename to load (e.g., "a11y", "usage", "examples") + */ +export const SpectrumDocs = ({ + of, + tag = 'usage', +}: { + of?: any; + tag?: string; +}) => { + const resolvedOf = useOf(of || 'meta', ['meta']); + const [MdxComponent, setMdxComponent] = + useState<React.ComponentType | null>(null); + + useEffect(() => { + // Extract component name from the title (e.g., "Components/Progress Circle" -> "progress-circle") + const title = resolvedOf.preparedMeta?.title || ''; + const componentName = title + .split('/') + .pop() + ?.toLowerCase() + .replace(/\s+/g, '-'); + + // Find the matching MDX file path based on component name and tag + const matchingPath = Object.keys(mdxModules).find((path) => { + const pathLower = path.toLowerCase(); + return ( + pathLower.includes(`/${componentName}/`) && + pathLower.endsWith(`/${componentName}.${tag}.mdx`) + ); + }); + + if (matchingPath) { + // Import the compiled MDX module and get its default export (the React component) + mdxModules[matchingPath]().then((mod) => + setMdxComponent(() => mod.default) + ); + } else { + setMdxComponent(null); + } + }, [resolvedOf, tag]); + + if (!MdxComponent) { + return <p>No {tag} documentation available.</p>; + } + + // Render the MDX as a React component - JSX will work! + return <MdxComponent />; +}; diff --git a/2nd-gen/packages/swc/.storybook/blocks/SpectrumStories.tsx b/2nd-gen/packages/swc/.storybook/blocks/SpectrumStories.tsx new file mode 100644 index 00000000000..835f0ba5944 --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/blocks/SpectrumStories.tsx @@ -0,0 +1,41 @@ +import { Story, Description, useOf } from '@storybook/addon-docs/blocks'; +import React from 'react'; + +/** + * A block that renders all stories tagged with a specified tag from the component's stories file. + * - if a meta reference is passed, it finds all tagged stories from that meta + * - if nothing is passed, it defaults to the current meta + * + * @param of - The Storybook meta or story to resolve the component from + * @param tag - The story tag to filter by (e.g., "usage", "a11y", "examples") + */ +export const SpectrumStories = ({ + of, + tag = 'usage', +}: { + of?: any; + tag?: string; +}) => { + const resolvedOf = useOf(of || 'meta', ['story', 'meta']); + const taggedStories = Object.values( + resolvedOf.type === 'meta' + ? resolvedOf.csfFile.stories + : [resolvedOf.story] + ).filter((story: any) => story.tags?.includes(tag)); + + if (taggedStories.length === 0) { + return null; + } + + return ( + <> + {taggedStories.map((story: any) => ( + <React.Fragment key={story.id}> + <h3>{story.name}</h3> + <Description /> + <Story of={story.moduleExport} /> + </React.Fragment> + ))} + </> + ); +}; diff --git a/2nd-gen/packages/swc/.storybook/get-started/first-gen-vs-second-gen.mdx b/2nd-gen/packages/swc/.storybook/get-started/first-gen-vs-second-gen.mdx index f95d9b979fc..19d1f7dbd38 100644 --- a/2nd-gen/packages/swc/.storybook/get-started/first-gen-vs-second-gen.mdx +++ b/2nd-gen/packages/swc/.storybook/get-started/first-gen-vs-second-gen.mdx @@ -1,6 +1,6 @@ import { Meta } from '@storybook/addon-docs/blocks'; -<Meta title="First Gen vs Second Gen/First Gen vs Second Gen" /> +<Meta title="First Gen vs Second Gen" /> # First Gen vs Second Gen @@ -11,3 +11,15 @@ Second Gen SWC is the new implementation of SWC, built with the Lit framework. ## First Gen SWC ## Second Gen SWC + +## Migration from 1st-gen to 2nd-gen + +### What is the migration process? + +The migration process from 1st-gen to 2nd-gen is a gradual process. + +### What are the benefits of migrating to 2nd-gen? + +The benefits of migrating to 2nd-gen are: + +- Improved performance diff --git a/2nd-gen/packages/swc/.storybook/get-started/migration.mdx b/2nd-gen/packages/swc/.storybook/get-started/migration.mdx deleted file mode 100644 index cd55315b0c6..00000000000 --- a/2nd-gen/packages/swc/.storybook/get-started/migration.mdx +++ /dev/null @@ -1,15 +0,0 @@ -import { Meta } from '@storybook/addon-docs/blocks'; - -<Meta title="First Gen vs Second Gen/Migration from 1st-gen to 2nd-gen" /> - -# Migration from 1st-gen to 2nd-gen - -## What is the migration process? - -The migration process from 1st-gen to 2nd-gen is a gradual process. - -## What are the benefits of migrating to 2nd-gen? - -The benefits of migrating to 2nd-gen are: - -- Improved performance diff --git a/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/06_accessibility_resources.mdx b/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/accessibility_resources.mdx similarity index 100% rename from 2nd-gen/packages/swc/.storybook/guides/accessibility-guides/06_accessibility_resources.mdx rename to 2nd-gen/packages/swc/.storybook/guides/accessibility-guides/accessibility_resources.mdx diff --git a/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/02_accessible_pattern_libraries.mdx b/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/accessible_pattern_libraries.mdx similarity index 100% rename from 2nd-gen/packages/swc/.storybook/guides/accessibility-guides/02_accessible_pattern_libraries.mdx rename to 2nd-gen/packages/swc/.storybook/guides/accessibility-guides/accessible_pattern_libraries.mdx diff --git a/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/03_keyboard_testing.mdx b/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/keyboard_testing.mdx similarity index 100% rename from 2nd-gen/packages/swc/.storybook/guides/accessibility-guides/03_keyboard_testing.mdx rename to 2nd-gen/packages/swc/.storybook/guides/accessibility-guides/keyboard_testing.mdx diff --git a/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/00_overview.mdx b/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/overview.mdx similarity index 100% rename from 2nd-gen/packages/swc/.storybook/guides/accessibility-guides/00_overview.mdx rename to 2nd-gen/packages/swc/.storybook/guides/accessibility-guides/overview.mdx diff --git a/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/04_screen_reader_testing.mdx b/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/screen_reader_testing.mdx similarity index 100% rename from 2nd-gen/packages/swc/.storybook/guides/accessibility-guides/04_screen_reader_testing.mdx rename to 2nd-gen/packages/swc/.storybook/guides/accessibility-guides/screen_reader_testing.mdx diff --git a/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/01_semantic_html_aria.mdx b/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/semantic_html_aria.mdx similarity index 100% rename from 2nd-gen/packages/swc/.storybook/guides/accessibility-guides/01_semantic_html_aria.mdx rename to 2nd-gen/packages/swc/.storybook/guides/accessibility-guides/semantic_html_aria.mdx diff --git a/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/05_wave_toolbar_testing.mdx b/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/wave_toolbar_testing.mdx similarity index 100% rename from 2nd-gen/packages/swc/.storybook/guides/accessibility-guides/05_wave_toolbar_testing.mdx rename to 2nd-gen/packages/swc/.storybook/guides/accessibility-guides/wave_toolbar_testing.mdx diff --git a/2nd-gen/packages/swc/.storybook/main.ts b/2nd-gen/packages/swc/.storybook/main.ts index 0584d96a736..c9a95aa6755 100644 --- a/2nd-gen/packages/swc/.storybook/main.ts +++ b/2nd-gen/packages/swc/.storybook/main.ts @@ -7,20 +7,15 @@ const __dirname = dirname(fileURLToPath(import.meta.url)); /** @type { import('@storybook/web-components-vite').StorybookConfig } */ const config = { stories: [ - { - directory: 'get-started', - files: '*.mdx', - titlePrefix: 'Get Started', - }, { directory: '../components', - files: '*/stories/*.stories.ts', + files: '**/*.stories.ts', titlePrefix: 'Components', }, { - directory: 'guides', + directory: 'get-started', files: '*.mdx', - titlePrefix: 'Guides', + titlePrefix: 'Get Started', }, { directory: 'guides', @@ -28,12 +23,31 @@ const config = { titlePrefix: 'Guides', }, ], + docs: { + defaultName: 'README', + }, framework: '@storybook/web-components-vite', + tags: { + a11y: { + defaultFilterSelection: 'exclude', + }, + usage: { + defaultFilterSelection: 'exclude', + }, + examples: { + defaultFilterSelection: 'exclude', + }, + }, core: { disableTelemetry: true, }, addons: [ - '@storybook/addon-docs', + { + name: '@storybook/addon-docs', + options: { + transcludeMarkdown: true, + }, + }, '@storybook/addon-a11y', '@storybook/addon-designs', '@storybook/addon-vitest', diff --git a/2nd-gen/packages/swc/.storybook/preview-head.html b/2nd-gen/packages/swc/.storybook/preview-head.html index b17fd06e5d9..95e0ee7007a 100644 --- a/2nd-gen/packages/swc/.storybook/preview-head.html +++ b/2nd-gen/packages/swc/.storybook/preview-head.html @@ -2,6 +2,11 @@ <link rel="dns-prefetch" href="https://use.typekit.net" /> <!-- For Adobe Clean font support --> <link rel="stylesheet" href="https://use.typekit.net/evk7lzt.css" /> +<script> + try { + Typekit.load(); + } catch (e) {} +</script> <style> /* Fix for Storybook's zoom wrapper interfering with forced-colors mode */ diff --git a/2nd-gen/packages/swc/.storybook/preview.ts b/2nd-gen/packages/swc/.storybook/preview.ts index 9e8b07d4390..63bc13f3150 100644 --- a/2nd-gen/packages/swc/.storybook/preview.ts +++ b/2nd-gen/packages/swc/.storybook/preview.ts @@ -56,10 +56,10 @@ const preview = { toc: { contentsSelector: '.sbdocs-content', headingSelector: 'h2, h3', - ignoreSelector: '#primary', + ignoreSelector: '.sbdocs-subtitle', disable: false, unsafeTocbotOptions: { - orderedList: false, + // orderedList: false, }, }, }, @@ -98,7 +98,7 @@ const preview = { }, }, }, - tags: ['autodocs'], + tags: ['!autodocs', '!dev'], }; export default preview; diff --git a/2nd-gen/packages/swc/components/asset/stories/asset.stories.ts b/2nd-gen/packages/swc/components/asset/stories/asset.stories.ts index 0f5b9ce294a..f6bb80ce3ec 100644 --- a/2nd-gen/packages/swc/components/asset/stories/asset.stories.ts +++ b/2nd-gen/packages/swc/components/asset/stories/asset.stories.ts @@ -35,6 +35,7 @@ type Story = StoryObj; export const Default: Story = { render: (args) => html` <swc-asset variant="${args.variant}"></swc-asset> `, + tags: ['autodocs', 'dev'], // render: () => html` // <swc-asset style="height: 128px"> diff --git a/2nd-gen/packages/swc/components/badge/Badge.ts b/2nd-gen/packages/swc/components/badge/Badge.ts index 66683f169d2..09393fde30b 100644 --- a/2nd-gen/packages/swc/components/badge/Badge.ts +++ b/2nd-gen/packages/swc/components/badge/Badge.ts @@ -28,6 +28,7 @@ import styles from './badge.css'; * A badge component that displays short, descriptive information about an element. * Badges are typically used to indicate status, categories, or provide supplementary information. * + * * @element swc-badge * * @example diff --git a/2nd-gen/packages/swc/components/badge/stories/badge.stories.ts b/2nd-gen/packages/swc/components/badge/stories/badge.stories.ts index 4d590ae63f5..7f568323990 100644 --- a/2nd-gen/packages/swc/components/badge/stories/badge.stories.ts +++ b/2nd-gen/packages/swc/components/badge/stories/badge.stories.ts @@ -16,6 +16,7 @@ import type { Meta, StoryObj as Story } from '@storybook/web-components'; import { getStorybookHelpers } from '@wc-toolkit/storybook-helpers'; import { Badge } from '@adobe/swc/badge'; +import { capitalize } from '@spectrum-web-components/core/shared/utilities'; import '@adobe/swc/badge'; @@ -51,7 +52,8 @@ argTypes.fixed = { args['default-slot'] = 'Badge'; /** - * Badges are for showing a small amount of color-categorized metadata. They're ideal for getting a user's attention. There are two additional styles - subtle fill and outline - in addition to the default, bold fill style. + * Badges are for showing a small amount of color-categorized metadata. They're ideal for getting a user's attention. + * There are two additional styles - subtle fill and outline - in addition to the default, bold fill style. * * Because outline and subtle fill styles draw a similar level of attention, choose only one to use consistently within a single product. Bold fill can be paired with either style, and is reserved for high-attention badging only. */ @@ -71,9 +73,9 @@ const meta: Meta = { export default meta; -// ─────────────── -// STORIES -// ─────────────── +// ──────────────────── +// AUTODOCS STORY +// ──────────────────── type BadgeVariant = typeof Badge.prototype.variant; type BadgeSize = typeof Badge.prototype.size; @@ -85,8 +87,13 @@ export const Default: Story = { args: { size: 'm', }, + tags: ['autodocs', 'dev'], }; +// ───────────────────── +// USAGE STORIES +// ───────────────────── + /** * Badges can be rendered with or without an icon. Icons can be passed to the component using the `icon` slot and can be sourced from either the Spectrum icon library or a custom icon library as needed. */ @@ -95,7 +102,7 @@ export const WithIcon: Story = { ['icon-slot']: '✓', }, // Removes the story from the side navigation while keeping in the docs view - tags: ['!dev'], + tags: ['usage'], }; /** @@ -112,7 +119,7 @@ export const SemanticVariants: Story = { ` ) ), - tags: ['!dev'], + tags: ['usage'], }; /** @@ -135,7 +142,7 @@ export const Outline: Story = { ` ) ), - tags: ['!dev'], + tags: ['usage'], }; /** @@ -152,7 +159,7 @@ export const ColorVariants: Story = { ` ) ), - tags: ['!dev'], + tags: ['usage'], }; export const Sizes: Story = { @@ -166,7 +173,7 @@ export const Sizes: Story = { ` ) ), - tags: ['!dev'], + tags: ['usage'], }; /** @@ -183,21 +190,13 @@ export const Subtle: Story = { ` ) ), - tags: ['!dev'], + tags: ['usage'], }; // ──────────────────────── // HELPER FUNCTIONS // ──────────────────────── -/* @todo Pull this up into a utility function for all components to leverage */ -function capitalize(str?: string): string { - if (typeof str !== 'string') { - return ''; - } - return str.charAt(0).toUpperCase() + str.slice(1); -} - /* @todo Pull this up into a decorator for all stories to leverage */ function CONTAINER(content: TemplateResult<1>[]): TemplateResult { return html`<div diff --git a/2nd-gen/packages/swc/components/divider/Divider.ts b/2nd-gen/packages/swc/components/divider/Divider.ts index fc845e4ea8f..2cdad17b231 100644 --- a/2nd-gen/packages/swc/components/divider/Divider.ts +++ b/2nd-gen/packages/swc/components/divider/Divider.ts @@ -14,17 +14,10 @@ import { CSSResultArray, html, TemplateResult } from 'lit'; import { classMap } from 'lit/directives/class-map.js'; import { DividerBase } from '@spectrum-web-components/core/components/divider'; +import { capitalize } from '@spectrum-web-components/core/shared/utilities'; import styles from './divider.css'; -// @todo Pull this up into a utility function for all components to leverage -function capitalize(str?: string): string { - if (typeof str !== 'string') { - return ''; - } - return str.charAt(0).toUpperCase() + str.slice(1); -} - /** * @element swc-divider */ diff --git a/2nd-gen/packages/swc/components/divider/stories/divider.a11y.mdx b/2nd-gen/packages/swc/components/divider/stories/divider.a11y.mdx new file mode 100644 index 00000000000..2cf9b4fdabb --- /dev/null +++ b/2nd-gen/packages/swc/components/divider/stories/divider.a11y.mdx @@ -0,0 +1,15 @@ +This is coming from the accessibility markdown file through the AccessibilityDocs block. + +# Accessibility + +The `<sp-divider>` element implements the following accessibility features: + +- **ARIA role**: Automatically sets `role="separator"` to ensure proper semantic meaning for assistive technologies +- **Orientation support**: When `vertical` is true, automatically sets `aria-orientation="vertical"` to indicate the divider's orientation + +#### Best practices + +- Medium or large dividers can be used with header text to visually create a section or page title. Place the divider below the header for best results. +- Ensure sufficient color contrast when using `static-color` variants on colored backgrounds. +- Use dividers to create meaningful visual separation, not just decorative lines. +- Use dividers sparingly; excessive use can diminish their visual impact. diff --git a/2nd-gen/packages/swc/components/divider/stories/divider.stories.ts b/2nd-gen/packages/swc/components/divider/stories/divider.stories.ts index 625fc3bef03..832640935fc 100644 --- a/2nd-gen/packages/swc/components/divider/stories/divider.stories.ts +++ b/2nd-gen/packages/swc/components/divider/stories/divider.stories.ts @@ -60,21 +60,26 @@ const meta: Meta = { export default meta; -// ─────────────── -// STORIES -// ─────────────── - type DividerSize = typeof Divider.prototype.size; +// ──────────────────── +// PRIMARY STORIES +// ──────────────────── + /** * By default, dividers are horizontal and should be used for separating content vertically. The medium divider is the default size. */ -export const Default: Story = { +export const Playground: Story = { args: { size: 'm', }, + tags: ['autodocs', 'dev'], }; +// ──────────────────── +// USAGE STORIES +// ──────────────────── + /** * The small divider is used to divide similar components such as table rows, action button groups, and components within a panel. * @@ -101,7 +106,7 @@ export const Sizes: Story = { )} </div> `, - tags: ['!dev'], + tags: ['usage'], }; /** @@ -118,7 +123,7 @@ export const Vertical: Story = { )} </div> `, - tags: ['!dev'], + tags: ['!dev', '!autodocs', 'usage'], }; /** @@ -135,7 +140,7 @@ export const StaticBlack: Story = { )} </div> `, - tags: ['!dev'], + tags: ['!dev', '!autodocs', 'usage'], }; export const StaticWhite: Story = { @@ -149,5 +154,43 @@ export const StaticWhite: Story = { )} </div> `, - tags: ['!dev'], + tags: ['!dev', '!autodocs', 'usage'], +}; + +// ──────────────────────────────── +// ACCESSIBILITY STORIES +// ──────────────────────────────── + +/** + * EXAMPLE: Accessibility Documentation + */ +export const Accessibility: Story = { + render: () => html` + <div> + <p> + This is coming from the accessibility story through the + Accessibility block. This option allows us to fully customize + the accessibility documentation for a component by writing a + custom story that renders the accessibility documentation. + </p> + </div> + `, + tags: ['!dev', '!autodocs', 'a11y'], +}; + +/** + * EXAMPLE: Keyboard Navigation Documentation + */ +export const KeyboardNavigation: Story = { + render: () => html` + <div> + <p> + This is coming from the keyboard navigation story through the + Accessibility block. This option allows us to fully customize + the accessibility documentation for a component by writing a + custom story that renders the accessibility documentation. + </p> + </div> + `, + tags: ['!dev', '!autodocs', 'a11y'], }; diff --git a/2nd-gen/packages/swc/components/progress-circle/ProgressCircle.ts b/2nd-gen/packages/swc/components/progress-circle/ProgressCircle.ts index 2b0431b2223..76f976933ef 100644 --- a/2nd-gen/packages/swc/components/progress-circle/ProgressCircle.ts +++ b/2nd-gen/packages/swc/components/progress-circle/ProgressCircle.ts @@ -19,18 +19,12 @@ import { ProgressCircleBase, type ProgressCircleStaticColorS2, } from '@spectrum-web-components/core/components/progress-circle'; +import { capitalize } from '@spectrum-web-components/core/shared/utilities'; import progressCircleStyles from './progress-circle.css'; - -function capitalize(str?: string): string { - if (typeof str !== 'string') { - return ''; - } - return str.charAt(0).toUpperCase() + str.slice(1); -} /** - * A progress circle component that visually represents the completion progress of a task. - * Can be used in both determinate (with specific progress value) and indeterminate (loading) states. + * Progress circles show the progression of a system operation such as downloading, uploading, processing, etc. in a visual way. + * They can represent determinate (with a specific progress value) or indeterminate (loading) progress. * * @element swc-progress-circle * diff --git a/2nd-gen/packages/swc/components/progress-circle/stories/progress-circle.a11y.mdx b/2nd-gen/packages/swc/components/progress-circle/stories/progress-circle.a11y.mdx new file mode 100644 index 00000000000..68285e44793 --- /dev/null +++ b/2nd-gen/packages/swc/components/progress-circle/stories/progress-circle.a11y.mdx @@ -0,0 +1,43 @@ +import { Canvas, Story, Meta } from '@storybook/addon-docs/blocks'; +import * as ProgressCircleStories from './progress-circle.stories'; + +This is coming from the accessibility markdown file through the AccessibilityDocs block. + +## Accessibility + +### Features + +<Canvas of={ProgressCircleStories.Indeterminate} meta={ProgressCircleStories} /> + +The `<sp-progress-circle>` element implements several accessibility features: + +1. **ARIA Role**: Automatically sets `role="progressbar"` for proper semantic meaning +2. **Labeling**: + - Uses the `label` attribute value as `aria-label` + - When determinate, adds `aria-valuenow` with the current progress + - Includes `aria-valuemin="0"` and `aria-valuemax="100"` for the progress range +3. **Status Communication**: + - Screen readers announce progress updates + - Indeterminate state is properly conveyed to assistive technologies + +### Best Practices + +- Always provide a descriptive `label` that explains what the progress represents +- Use determinate progress when possible to give users a clear sense of completion +- For determinate progress, ensure the `progress` value accurately reflects the actual progress +- Consider using `size="l"` for primary loading states to improve visibility +- Ensure sufficient color contrast when using `static-color="white"` + +```html +<!-- Example with good accessibility --> +<sp-progress-circle + label="Downloading report.pdf - 24 MB of 50 MB" + progress="48" +></sp-progress-circle> + +<!-- For unknown duration operations --> +<sp-progress-circle + label="Connecting to server" + indeterminate +></sp-progress-circle> +``` diff --git a/2nd-gen/packages/swc/components/progress-circle/stories/progress-circle.stories.ts b/2nd-gen/packages/swc/components/progress-circle/stories/progress-circle.stories.ts index e8985065668..1894fd6fa1d 100644 --- a/2nd-gen/packages/swc/components/progress-circle/stories/progress-circle.stories.ts +++ b/2nd-gen/packages/swc/components/progress-circle/stories/progress-circle.stories.ts @@ -35,15 +35,11 @@ const { events, args, argTypes, template } = getStorybookHelpers( // control: { type: 'range', min: 0, max: 100, step: 1 }, // }; -/* - * @todo This is properly configuring the Select, but the control doesn't - * seem to work; need to investigate. - */ -// argTypes.size = { -// ...argTypes.size, -// control: { type: 'select' }, -// options: ProgressCircle.VALID_SIZES, -// }; +argTypes.size = { + ...argTypes.size, + control: { type: 'select' }, + options: ProgressCircle.VALID_SIZES, +}; argTypes['static-color'] = { ...argTypes['static-color'], @@ -52,8 +48,9 @@ argTypes['static-color'] = { }; /** - * A progress circle component that visually represents the completion progress of a task. - * Can be used in both determinate (with specific progress value) and indeterminate (loading) states. + * Progress circles show the progression of a system operation such as downloading, uploading, processing, etc. in a visual way. + * + * They can represent determinate or indeterminate progress. */ const meta: Meta = { title: 'Progress circle', @@ -62,6 +59,9 @@ const meta: Meta = { argTypes, render: (args) => template(args), parameters: { + docs: { + subtitle: `Progress circles show the progression of a system operation such as downloading, uploading, processing, etc. in a visual way. They can represent determinate or indeterminate progress.`, + }, actions: { handles: events, }, @@ -71,19 +71,27 @@ const meta: Meta = { export default meta; -// ─────────────── -// STORIES -// ─────────────── +// ──────────────────── +// AUTODOCS STORY +// ──────────────────── -export const Default: Story = { +export const Playground: Story = { args: { progress: 50, size: 'm', label: 'Loading progress', }, render: (args) => template(args), + tags: ['autodocs', 'dev'], }; +// ───────────────────── +// USAGE STORIES +// ───────────────────── + +/** + * This is the description fo the sizes story + */ export const Sizes: Story = { render: () => html` <div style="display: flex; gap: 24px; align-items: center;"> @@ -104,7 +112,7 @@ export const Sizes: Story = { ></swc-progress-circle> </div> `, - tags: ['!dev'], + tags: ['usage'], }; export const ProgressValues: Story = { @@ -128,7 +136,7 @@ export const ProgressValues: Story = { ></swc-progress-circle> </div> `, - tags: ['!dev'], + tags: ['usage'], }; export const Indeterminate: Story = { @@ -151,7 +159,7 @@ export const Indeterminate: Story = { ></swc-progress-circle> </div> `, - tags: ['!dev'], + tags: ['usage'], }; export const StaticWhite: Story = { @@ -179,7 +187,7 @@ export const StaticWhite: Story = { ></swc-progress-circle> </div> `, - tags: ['!dev'], + tags: ['usage'], }; export const StaticBlack: Story = { @@ -207,7 +215,7 @@ export const StaticBlack: Story = { ></swc-progress-circle> </div> `, - tags: ['!dev'], + tags: ['usage'], }; export const IndeterminateStaticWhite: Story = { @@ -235,5 +243,38 @@ export const IndeterminateStaticWhite: Story = { ></swc-progress-circle> </div> `, - tags: ['!dev'], + tags: ['usage'], +}; + +// ──────────────────────────────── +// ACCESSIBILITY STORIES +// ──────────────────────────────── + +export const Accessibility: Story = { + render: () => html` + <div> + <p> + This is coming from the accessibility story through the + Accessibility block. This option allows us to fully customize + the accessibility documentation for a component by writing a + custom story that renders the accessibility documentation. + </p> + </div> + `, + tags: ['a11y'], +}; + +export const KeyboardNavigation: Story = { + render: () => html` + <div> + <p> + This is coming from the keyboard navigation story through the + Accessibility block. This option allows us to fully customize + allows us to fully customize the accessibility documentation for + a component by writing a custom story that renders the + accessibility documentation. + </p> + </div> + `, + tags: ['a11y'], }; diff --git a/2nd-gen/packages/swc/components/progress-circle/stories/progress-circle.usage.mdx b/2nd-gen/packages/swc/components/progress-circle/stories/progress-circle.usage.mdx new file mode 100644 index 00000000000..39bb66e8ac3 --- /dev/null +++ b/2nd-gen/packages/swc/components/progress-circle/stories/progress-circle.usage.mdx @@ -0,0 +1,9 @@ +import { Canvas, Story, Meta } from '@storybook/addon-docs/blocks'; +import { SpectrumStories } from '../../../.storybook/blocks/SpectrumStories'; +import * as ProgressCircleStories from './progress-circle.stories'; + +<Meta title="Progress circle/Usage" /> + +# Usage + +<SpectrumStories of={ProgressCircleStories} tag="usage" /> diff --git a/2nd-gen/packages/swc/components/status-light/stories/status-light.stories.ts b/2nd-gen/packages/swc/components/status-light/stories/status-light.stories.ts index 567898fa3f5..8360f58adb3 100644 --- a/2nd-gen/packages/swc/components/status-light/stories/status-light.stories.ts +++ b/2nd-gen/packages/swc/components/status-light/stories/status-light.stories.ts @@ -15,6 +15,7 @@ import type { Meta, StoryObj as Story } from '@storybook/web-components'; import { getStorybookHelpers } from '@wc-toolkit/storybook-helpers'; import { StatusLight } from '@adobe/swc/status-light'; +import { capitalize } from '@spectrum-web-components/core/shared/utilities'; import '@adobe/swc/status-light'; @@ -74,7 +75,9 @@ type StatusLightSize = typeof StatusLight.prototype.size; * Status lights should always include a label with text that clearly communicates the kind of status being shown. Color * alone is not enough to communicate the status. Do not change the text color to match the dot. */ -export const Default: Story = {}; +export const Default: Story = { + tags: ['autodocs', 'dev'], +}; /** When the text is too long for the horizontal space available, it wraps to form another line. */ export const TextWrapping: Story = { @@ -83,9 +86,8 @@ export const TextWrapping: Story = { This is a very long status light label that wraps when it reaches its max inline size </swc-status-light>`, - tags: ['!dev'], + tags: ['usage'], }; -TextWrapping.storyName = 'Text wrapping'; /** * When status lights have a semantic meaning, they use semantic colors. Use these variants for the following statuses: @@ -108,9 +110,8 @@ export const SemanticVariants: Story = { ` ) ), - tags: ['!dev'], + tags: ['usage'], }; -SemanticVariants.storyName = 'Semantic variants'; /** * When status lights are used to color code categories and labels that are commonly found in data visualization, @@ -127,7 +128,7 @@ export const NonsemanticVariants: Story = { ` ) ), - tags: ['!dev'], + tags: ['usage'], }; NonsemanticVariants.storyName = 'Non-semantic variants'; @@ -147,21 +148,13 @@ export const Sizes: Story = { ` ) ), - tags: ['!dev'], + tags: ['usage'], }; // ──────────────────────── // HELPER FUNCTIONS // ──────────────────────── -/* @todo Pull this up into a utility function for all components to leverage */ -function capitalize(str?: string): string { - if (typeof str !== 'string') { - return ''; - } - return str.charAt(0).toUpperCase() + str.slice(1); -} - /* @todo Pull this up into a utility function for more components to leverage. Are all sizes accounted for? */ function sizeMap(str?: StatusLightSize): string { const sizeLabels = { From ececb42f8039053e11575b0dc1920d7d06311ccb Mon Sep 17 00:00:00 2001 From: Nikki Massaro <5090492+nikkimk@users.noreply.github.com> Date: Fri, 5 Dec 2025 17:28:15 -0500 Subject: [PATCH 04/11] docs: updated and formatted next-gen docs (#5924) * docs(progress-circle): updated and formatted progress circle dpcs * docs(divider): updated and formatted divider stories * docs(divider): added size args to stories * docs(status-ligt): updated status-light docs and stories * docs(progress-circle): added progress arg type for docs and stories * docs(divider): added description to stories and docs * docs(badge): added description to stories and docs * docs(status-light): made correction to docs * docs(status-light): made correction to docs * docs(badge): updated badge docs and stories * docs: fixed typos * docs: removed the 'usage' tag from stories * docs(assets): updates asset docs and stories --- .../swc/.storybook/DocumentTemplate.mdx | 31 +---- 2nd-gen/packages/swc/.storybook/preview.ts | 14 +-- .../components/asset/stories/asset.stories.ts | 104 +++++++++++++--- .../components/asset/stories/asset.usage.mdx | 61 +++++++++ .../components/badge/stories/badge.stories.ts | 74 +++++++++-- .../components/badge/stories/badge.usage.mdx | 115 +++++++++++++++++ .../divider/stories/divider.a11y.mdx | 15 --- .../divider/stories/divider.stories.ts | 112 ++++++----------- .../divider/stories/divider.usage.mdx | 77 ++++++++++++ .../stories/progress-circle.a11y.mdx | 43 ------- .../stories/progress-circle.stories.ts | 116 +++++++++++++----- .../stories/progress-circle.usage.mdx | 98 ++++++++++++++- .../stories/status-light.stories.ts | 42 ++++--- .../stories/status-light.usage.mdx | 75 +++++++++++ 14 files changed, 732 insertions(+), 245 deletions(-) create mode 100644 2nd-gen/packages/swc/components/asset/stories/asset.usage.mdx create mode 100644 2nd-gen/packages/swc/components/badge/stories/badge.usage.mdx delete mode 100644 2nd-gen/packages/swc/components/divider/stories/divider.a11y.mdx create mode 100644 2nd-gen/packages/swc/components/divider/stories/divider.usage.mdx delete mode 100644 2nd-gen/packages/swc/components/progress-circle/stories/progress-circle.a11y.mdx create mode 100644 2nd-gen/packages/swc/components/status-light/stories/status-light.usage.mdx diff --git a/2nd-gen/packages/swc/.storybook/DocumentTemplate.mdx b/2nd-gen/packages/swc/.storybook/DocumentTemplate.mdx index c232c6920bc..383a8b82650 100644 --- a/2nd-gen/packages/swc/.storybook/DocumentTemplate.mdx +++ b/2nd-gen/packages/swc/.storybook/DocumentTemplate.mdx @@ -18,33 +18,14 @@ import '@spectrum-web-components/tabs/sp-tab-panel.js'; <Title /> <Subtitle /> +<Primary /> -<sp-tabs id="component-doc-tabs" size="xl" selected="overview" auto label="Component Documentation"> - <sp-tab value="overview">Overview</sp-tab> - <sp-tab value="usage">Usage</sp-tab> - <sp-tab value="accessibility">Accessibility</sp-tab> - <sp-tab value="api">API</sp-tab> - <sp-tab value="examples">Examples</sp-tab> - <sp-tab-panel value="overview" style={{ flexDirection: 'column' }}> - <Description /> - <Primary /> - <Controls /> - </sp-tab-panel> - <sp-tab-panel value="usage" style={{ flexDirection: 'column' }}> - <SpectrumDocs tag="usage" /> - </sp-tab-panel> - <sp-tab-panel value="accessibility" style={{ flexDirection: 'column' }}> - <SpectrumDocs tag="a11y" /> - </sp-tab-panel> - <sp-tab-panel value="api" style={{ flexDirection: 'column' }}> - <ArgTypes /> - </sp-tab-panel> - <sp-tab-panel value="examples" style={{ flexDirection: 'column' }}> - <SpectrumDocs tag="examples" /> - <Stories /> - </sp-tab-panel> +<SpectrumDocs tag="usage" /> -</sp-tabs> +## API + +<Primary /> +<Controls /> ## Feedback diff --git a/2nd-gen/packages/swc/.storybook/preview.ts b/2nd-gen/packages/swc/.storybook/preview.ts index 63bc13f3150..52564c3a35e 100644 --- a/2nd-gen/packages/swc/.storybook/preview.ts +++ b/2nd-gen/packages/swc/.storybook/preview.ts @@ -55,7 +55,7 @@ const preview = { page: DocumentTemplate, toc: { contentsSelector: '.sbdocs-content', - headingSelector: 'h2, h3', + headingSelector: 'h2:not(.demo), h3:not(.demo), h4:not(.demo)', ignoreSelector: '.sbdocs-subtitle', disable: false, unsafeTocbotOptions: { @@ -84,12 +84,12 @@ const preview = { 'Accessibility guides', [ 'Overview', - 'Semantic HTML and ARIA', - 'Accessible pattern libraries', - 'Keyboard testing', - 'Screen reader testing', - 'Wave toolbar testing', - 'Accessibility resources' + 'Semantic HTML and ARIA', + 'Accessible pattern libraries', + 'Keyboard testing', + 'Screen reader testing', + 'Wave toolbar testing', + 'Accessibility resources', ], 'React wrappers', ], diff --git a/2nd-gen/packages/swc/components/asset/stories/asset.stories.ts b/2nd-gen/packages/swc/components/asset/stories/asset.stories.ts index f6bb80ce3ec..df10d956555 100644 --- a/2nd-gen/packages/swc/components/asset/stories/asset.stories.ts +++ b/2nd-gen/packages/swc/components/asset/stories/asset.stories.ts @@ -11,35 +11,107 @@ */ import { html } from 'lit'; -import type { Meta, StoryObj } from '@storybook/web-components'; +import type { Meta, StoryObj as Story } from '@storybook/web-components'; +import { getStorybookHelpers } from '@wc-toolkit/storybook-helpers'; import '@adobe/swc/asset'; +// ──────────────── +// METADATA +// ──────────────── + +const { events, args, argTypes, template } = getStorybookHelpers('swc-asset'); + +argTypes.variant = { + ...argTypes.variant, + control: { type: 'select' }, + options: [undefined, 'file', 'folder'], +}; + +argTypes.label = { + control: { type: 'text' }, +}; + +argTypes.size = { + control: { disable: true }, +}; + +// since we cant't use HTML templates in a slot control, +// we need to use a select option and render a predefined HTML template based on the selected option +argTypes['default-slot'] = { + ...argTypes['default-slot'], + control: { type: 'select' }, + options: [undefined, 'slotted image'], +}; + +/* + * Use an `<sp-asset>` element to visually represent a file, folder or image in your application. + * File and folder representations will center themselves horizontally and vertically in the space provided to the element. + * Images will be contained to the element, growing to the element's full height while centering itself within the width provided. + */ const meta: Meta = { title: 'Asset', component: 'swc-asset', - argTypes: { - variant: { - control: { type: 'select' }, - options: ['file', 'folder', undefined], + args, + argTypes, + render: (args) => template(args), + parameters: { + actions: { + handles: events, }, }, + tags: ['migrated'], }; export default meta; -type Story = StoryObj; -// export const Default: Story = { -// render: (args) => html` <swc-asset variant="${args.variant}"></swc-asset> `, -// }; +// ──────────────────── +// AUTODOCS STORY +// ──────────────────── -export const Default: Story = { - render: (args) => html` <swc-asset variant="${args.variant}"></swc-asset> `, +/* + * Use an `<sp-asset>` element to visually represent a file, folder or image in your application. + * File and folder representations will center themselves horizontally and vertically in the space provided to the element. + * Images will be contained to the element, growing to the element's full height while centering itself within the width provided. + */ +export const Playground: Story = { + // since we cant't use HTML templates in a slot control, + // we need to use a select option and render a predefined HTML template based on the selected option + render: (args) => + html`<swc-asset label="${args.label}" variant="${args.variant}"> + ${args['default-slot'] === 'slotted image' + ? html`<img src="https://picsum.photos/120/120" alt="Avatar" />` + : ''} + </swc-asset>`, + args: { + variant: 'file', + label: 'picture.png', + }, tags: ['autodocs', 'dev'], +}; - // render: () => html` - // <swc-asset style="height: 128px"> - // <img src=${portrait} alt="Demo Graphic" /> - // </swc-asset> - // `, +// ───────────────────── +// USAGE STORIES +// ───────────────────── +export const Anatomy: Story = { + render: () => + html`<swc-asset label="Avatar" + ><img src="https://picsum.photos/120/120" alt="Avatar" + /></swc-asset>`, + tags: ['autodocs', '!dev'], +}; + +export const File: Story = { + args: { + variant: 'file', + label: 'README.md', + }, + tags: ['!dev'], +}; +export const Folder: Story = { + args: { + variant: 'folder', + label: 'packages/swc/', + }, + tags: ['!dev'], }; diff --git a/2nd-gen/packages/swc/components/asset/stories/asset.usage.mdx b/2nd-gen/packages/swc/components/asset/stories/asset.usage.mdx new file mode 100644 index 00000000000..09561615d39 --- /dev/null +++ b/2nd-gen/packages/swc/components/asset/stories/asset.usage.mdx @@ -0,0 +1,61 @@ +import { Canvas, Story, Meta } from '@storybook/addon-docs/blocks'; +import { SpectrumStories } from '../../../.storybook/blocks/SpectrumStories'; +import * as AssetStories from './asset.stories'; + +<Meta tag="usage" /> + +## Usage + +``` +yarn add @spectrum-web-components/asset +``` + +Import the side effectful registration of `<sp-asset>` via: + +``` +import '@spectrum-web-components/asset/sp-asset.js'; +``` + +When looking to leverage the `Asset` base class as a type and/or for extension purposes, do so via: + +``` +import { Asset } from '@spectrum-web-components/asset'; +``` + +### Anatomy + +A asset is made up of the following parts: + +- A large file or folder icon based on the asset `variant` +- An accessible label for the asset +- Optional content to be displayed in the asset when an acceptable value for `variant` is not present + +<Canvas of={AssetStories.Anatomy} withToolbar={true} sourceState="shown" /> + +#### Optional content + +Optional content, like a preview thumbnail or an icon, can be slotted into an assets + +<Canvas of={AssetStories.Playground} withToolbar={true} sourceState="shown" /> + +### Options + +It is not recommended to make badges interactive. Consider using a different component if you need interactivity, such as buttons, tags, or links. + +#### Variants + +When the `file` or `folder` variant is added, an icon displays instead of the slotted content. + +<Canvas of={AssetStories.File} withToolbar={true} sourceState="shown" /> + +<Canvas of={AssetStories.Folder} withToolbar={true} sourceState="shown" /> + +### Accessibility + +The asset component implements several accessibility features: + +- **Labeling**: Uses the `label` attribute value as `aria-label` + +#### Best Practices + +- Always provide a descriptive `label` that explains what the progress represents, unless the asset is purely decorative diff --git a/2nd-gen/packages/swc/components/badge/stories/badge.stories.ts b/2nd-gen/packages/swc/components/badge/stories/badge.stories.ts index 7f568323990..9610e1086ad 100644 --- a/2nd-gen/packages/swc/components/badge/stories/badge.stories.ts +++ b/2nd-gen/packages/swc/components/badge/stories/badge.stories.ts @@ -11,6 +11,7 @@ */ import { html, TemplateResult } from 'lit'; +import { ifDefined } from 'lit/directives/if-defined.js'; import { styleMap } from 'lit/directives/style-map.js'; import type { Meta, StoryObj as Story } from '@storybook/web-components'; import { getStorybookHelpers } from '@wc-toolkit/storybook-helpers'; @@ -38,16 +39,11 @@ argTypes.fixed = { options: [undefined, ...Badge.FIXED_VALUES], }; -/* - * @todo This is properly configuring the Select, but the control doesn't - * seem to work; need to investigate. - */ - -// argTypes.size = { -// ...argTypes.size, -// control: { type: 'select' }, -// options: Badge.VALID_SIZES, -// }; +argTypes.size = { + ...argTypes.size, + control: { type: 'select' }, + options: Badge.VALID_SIZES, +}; args['default-slot'] = 'Badge'; @@ -79,11 +75,11 @@ export default meta; type BadgeVariant = typeof Badge.prototype.variant; type BadgeSize = typeof Badge.prototype.size; - +type FixedValues = typeof Badge.prototype.fixed; /** - * Badges can contain label, icon, or label and icon. Text wrapping is also included when a `max-inline-size` is applied to the badge. + * `<sp-badge>` elements display a small amount of color-categorized metadata. They're ideal for getting a user's attention. */ -export const Default: Story = { +export const Playground: Story = { args: { size: 'm', }, @@ -122,6 +118,34 @@ export const SemanticVariants: Story = { tags: ['usage'], }; +export const NonsemanticVariants: Story = { + render: () => + CONTAINER( + Badge.VARIANTS_COLOR.map( + (variant) => html` + <swc-badge variant=${variant as BadgeVariant} + >${capitalize(variant)}</swc-badge + > + ` + ) + ), + tags: ['usage'], +}; + +export const Fixed: Story = { + render: () => + CONTAINER( + Badge.FIXED_VALUES.map( + (fixed) => html` + <swc-badge fixed=${ifDefined(fixed as FixedValues)} + >${capitalize(fixed)}</swc-badge + > + ` + ) + ), + tags: ['usage'], +}; + /** * The `outline` style is only valid for semantic color variants. */ @@ -193,6 +217,30 @@ export const Subtle: Story = { tags: ['usage'], }; +export const Textwrapping: Story = { + render: () => html` + <swc-badge style="max-inline-size: 100px"> + This is a very long badge label that wraps when it reaches its max + inline size + </swc-badge> + `, + tags: ['!dev'], +}; + +export const A11y: Story = { + render: () => html` + <swc-badge variant="positive">approved</swc-badge> + <swc-badge variant="negative">rejected</swc-badge> + <swc-badge variant="notice">needs approval</swc-badge> + <swc-badge variant="informative">new feature</swc-badge> + <swc-badge variant="neutral">version 1.2.10</swc-badge> + <swc-badge variant="celery">available</swc-badge> + <swc-badge variant="yellow">busy</swc-badge> + <swc-badge variant="silver">out of office</swc-badge> + `, + tags: ['autodocs', '!dev'], +}; + // ──────────────────────── // HELPER FUNCTIONS // ──────────────────────── diff --git a/2nd-gen/packages/swc/components/badge/stories/badge.usage.mdx b/2nd-gen/packages/swc/components/badge/stories/badge.usage.mdx new file mode 100644 index 00000000000..c1ccaeebaf9 --- /dev/null +++ b/2nd-gen/packages/swc/components/badge/stories/badge.usage.mdx @@ -0,0 +1,115 @@ +import { Canvas, Story, Meta } from '@storybook/addon-docs/blocks'; +import { SpectrumStories } from '../../../.storybook/blocks/SpectrumStories'; +import * as BadgeStories from './badge.stories'; + +<Meta tag="usage" /> + +## Usage + +```bash +yarn add @spectrum-web-components/badge +``` + +Import the side effectful registration of `<sp-badge>` via: + +```js +import '@spectrum-web-components/badge/sp-badge.js'; +``` + +When looking to leverage the `Badge` base class as a type and/or for extension purposes, do so via: + +```js +import { Badge } from '@spectrum-web-components/badge'; +``` + +### Anatomy + +A badge is made up of the following parts: + +- Ttext can be displayed within the badge by using the default slot. +- An optional icon element (`<sp-icon-*>`) can be used to display an icon within the badge. + +Badges can contain either a label, an icon, or both. + +<Canvas of={BadgeStories.Playground} withToolbar={true} sourceState="shown" /> + +#### Icon + +Badges can be rendered with or without an icon. Icons can be passed to the component using the `icon` slot and can be sourced from either the Spectrum icon library or a custom icon library as needed. + +<Canvas of={BadgeStories.WithIcon} withToolbar={true} sourceState="shown" /> + +### Options + +It is not recommended to make badges interactive. Consider using a different component if you need interactivity, such as buttons, tags, or links. + +#### Sizes + +<Canvas of={BadgeStories.Sizes} withToolbar={true} sourceState="shown" /> + +#### Variants + +The `<sp-badge>` can be customized with either semantic or non-semantic variants. Badges are intended as display elements (like status lights), so avoid using badges for critical actions. + +When badges have a semantic meaning, they use semantic colors. Use these variants for the following statuses: + +- **Positive**: approved, complete, success, new, purchased, licensed +- **Informative**: active, in use, live, published +- **Negative**: error, alert, rejected, failed +- **Neutral**: archived, deleted, paused, draft, not started, ended + +<Canvas + of={BadgeStories.SemanticVariants} + withToolbar={true} + sourceState="shown" +/> + +When badges are for color-coded categories, they use non-semantic colors. Non-semantic variants are ideally used for when there are 8 categories or less. + +<Canvas + of={BadgeStories.NonsemanticVariants} + withToolbar={true} + sourceState="shown" +/> + +#### Outline + +The `outline` style is only valid for semantic color variants. + +<Canvas of={BadgeStories.Outline} withToolbar={true} sourceState="shown" /> + +#### Subtle + +The `subtle` style is available for all variants. It is useful when you want to reduce the visual prominence of the badge while still mapping to the design system color palette. + +<Canvas of={BadgeStories.Subtle} withToolbar={true} sourceState="shown" /> + +#### Fixed positioning + +`<sp-badge>` can be displayed as if it is "fixed" to the edge of a UI. The `fixed` attribute can be leveraged to alter the border rounding based on the position you would like to achieve. Fixed positioning options include `block-start`, `block-end`, `inline-start`, and `inline-end`. + +<Canvas of={BadgeStories.Fixed} withToolbar={true} sourceState="shown" /> + +### Behaviors + +#### Text wrapping + +Badges are not interactive by default. + +When a badge's label is too long for the available horizontal space, it wraps to form another line. Text wrapping can be enforced when a `max-inline-size` is applied to the badge. + +<Canvas of={BadgeStories.Textwrapping} withToolbar={true} sourceState="shown" /> + +### Accessibility + +The badge component implements several accessibility feature: + +- **Color Meaning**: Colors are used in combination with text labels to ensure that status information is not conveyed through color alone. + +#### Best Practices + +- Use semantic variants (`positive`, `negative`, `notice`, `info`, `neutral`) when the status has specific meaning +- Include a clear, descriptive text label that explains the status +- Ensure sufficient color contrast between the status light and its background + +<Canvas of={BadgeStories.A11y} withToolbar={true} sourceState="shown" /> diff --git a/2nd-gen/packages/swc/components/divider/stories/divider.a11y.mdx b/2nd-gen/packages/swc/components/divider/stories/divider.a11y.mdx deleted file mode 100644 index 2cf9b4fdabb..00000000000 --- a/2nd-gen/packages/swc/components/divider/stories/divider.a11y.mdx +++ /dev/null @@ -1,15 +0,0 @@ -This is coming from the accessibility markdown file through the AccessibilityDocs block. - -# Accessibility - -The `<sp-divider>` element implements the following accessibility features: - -- **ARIA role**: Automatically sets `role="separator"` to ensure proper semantic meaning for assistive technologies -- **Orientation support**: When `vertical` is true, automatically sets `aria-orientation="vertical"` to indicate the divider's orientation - -#### Best practices - -- Medium or large dividers can be used with header text to visually create a section or page title. Place the divider below the header for best results. -- Ensure sufficient color contrast when using `static-color` variants on colored backgrounds. -- Use dividers to create meaningful visual separation, not just decorative lines. -- Use dividers sparingly; excessive use can diminish their visual impact. diff --git a/2nd-gen/packages/swc/components/divider/stories/divider.stories.ts b/2nd-gen/packages/swc/components/divider/stories/divider.stories.ts index 832640935fc..84e2200bc26 100644 --- a/2nd-gen/packages/swc/components/divider/stories/divider.stories.ts +++ b/2nd-gen/packages/swc/components/divider/stories/divider.stories.ts @@ -24,16 +24,11 @@ import '@adobe/swc/divider'; const { events, args, argTypes, template } = getStorybookHelpers('swc-divider'); -/* - * @todo This is properly configuring the Select, but the control doesn't - * seem to work; need to investigate. - */ - -// argTypes.size = { -// ...argTypes.size, -// control: { type: 'select' }, -// options: Divider.VALID_SIZES, -// }; +argTypes.size = { + ...argTypes.size, + control: { type: 'select' }, + options: Divider.VALID_SIZES, +}; argTypes['static-color'] = { ...argTypes['static-color'], @@ -67,7 +62,8 @@ type DividerSize = typeof Divider.prototype.size; // ──────────────────── /** - * By default, dividers are horizontal and should be used for separating content vertically. The medium divider is the default size. + * An `<sp-divider>` brings clarity to a layout by grouping and dividing content that exists in close proximity. + * It can also be used to establish rhythm and hierarchy. */ export const Playground: Story = { args: { @@ -88,25 +84,19 @@ export const Playground: Story = { * The large divider should only be used for page titles or section titles. */ export const Sizes: Story = { - render: () => html` - <div style="display: flex; flex-direction: row; gap: 16px;"> - ${Divider.VALID_SIZES.map( - (size) => html` - <div> - <h3> - ${size === 's' - ? 'Small' - : size === 'l' - ? 'Large' - : 'Medium'} - </h3> - ${template({ size: size as DividerSize })} - </div> - ` - )} - </div> - `, - tags: ['usage'], + render: () => + html` <div style="display: flex; flex-direction: row; gap: 16px;"> + ${Divider.VALID_SIZES.map((size) => { + const label = + size === 's' ? 'Small' : size === 'l' ? 'Large' : 'Medium'; + return html`<div> + <h3 class="demo">${label}</h3> + <swc-divider size=${size}></swc-divider> + <p>Text below the divider.</p> + </div>`; + })} + </div>`, + tags: ['!dev'], }; /** @@ -116,11 +106,14 @@ export const Vertical: Story = { args: { vertical: true, }, - render: (args: Record<string, unknown>) => html` + render: () => html` <div style="display: flex; flex-direction: row; gap: 48px;"> - ${Divider.VALID_SIZES.map((size) => - template({ ...args, size: size as DividerSize }) - )} + ${Divider.VALID_SIZES.map((size) => { + const label = + size === 's' ? 'Small' : size === 'l' ? 'Large' : 'Medium'; + return html` <h3 class="demo">${label}</h3> + <swc-divider vertical size=${size}></swc-divider>`; + })} </div> `, tags: ['!dev', '!autodocs', 'usage'], @@ -129,7 +122,7 @@ export const Vertical: Story = { /** * Use the static color options when a divider needs to be placed on top of a color background or visual. Static color dividers are available in black or white regardless of color theme. */ -export const StaticBlack: Story = { +export const StaticColors: Story = { args: { 'static-color': 'black', }, @@ -142,10 +135,9 @@ export const StaticBlack: Story = { `, tags: ['!dev', '!autodocs', 'usage'], }; - -export const StaticWhite: Story = { +export const StaticBlack: Story = { args: { - 'static-color': 'white', + 'static-color': 'black', }, render: (args: Record<string, unknown>) => html` <div style="display: flex; gap: 24px; align-items: center;"> @@ -157,40 +149,16 @@ export const StaticWhite: Story = { tags: ['!dev', '!autodocs', 'usage'], }; -// ──────────────────────────────── -// ACCESSIBILITY STORIES -// ──────────────────────────────── - -/** - * EXAMPLE: Accessibility Documentation - */ -export const Accessibility: Story = { - render: () => html` - <div> - <p> - This is coming from the accessibility story through the - Accessibility block. This option allows us to fully customize - the accessibility documentation for a component by writing a - custom story that renders the accessibility documentation. - </p> - </div> - `, - tags: ['!dev', '!autodocs', 'a11y'], -}; - -/** - * EXAMPLE: Keyboard Navigation Documentation - */ -export const KeyboardNavigation: Story = { - render: () => html` - <div> - <p> - This is coming from the keyboard navigation story through the - Accessibility block. This option allows us to fully customize - the accessibility documentation for a component by writing a - custom story that renders the accessibility documentation. - </p> +export const StaticWhite: Story = { + args: { + 'static-color': 'white', + }, + render: (args: Record<string, unknown>) => html` + <div style="display: flex; gap: 24px; align-items: center;"> + ${Divider.VALID_SIZES.map((size) => + template({ ...args, size: size as DividerSize }) + )} </div> `, - tags: ['!dev', '!autodocs', 'a11y'], + tags: ['!dev', '!autodocs', 'usage'], }; diff --git a/2nd-gen/packages/swc/components/divider/stories/divider.usage.mdx b/2nd-gen/packages/swc/components/divider/stories/divider.usage.mdx new file mode 100644 index 00000000000..1a6bed678c4 --- /dev/null +++ b/2nd-gen/packages/swc/components/divider/stories/divider.usage.mdx @@ -0,0 +1,77 @@ +import { Canvas, Story, Meta } from '@storybook/addon-docs/blocks'; +import { SpectrumStories } from '../../../.storybook/blocks/SpectrumStories'; +import * as DividerStories from './divider.stories'; + +<Meta tag="usage" /> + +## Usage + +```zsh +yarn add @spectrum-web-components/divider +``` + +Import the side effectful registration of `<sp-divider>` via: + +```js +import '@spectrum-web-components/divider/sp-divider.js'; +``` + +When looking to leverage the `Divider` base class as a type and/or for extension purposes, do so via: + +```js +import { Divider } from '@spectrum-web-components/divider'; +``` + +### Anatomy + +A divider consists of line two key aspects: + +- An optional size +- An optional orientation +- An optional static color for backgrounds that have color + +<Canvas of={DividerStories.Playground} withToolbar={true} sourceState="shown" /> + +### Options + +#### Sizes + +Dividers come in three sizes to fit various contexts, `s`, `m`, or `l`: + +<Canvas of={DividerStories.Sizes} withToolbar={true} sourceState="shown" /> + +#### Vertical + +The default horizontal divider is used to separate content stacked vertically. To separate horizonally content use the `vertical` attribute. + +When a vertical divider is used inside of a flex container, use `align-self: stretch; height: auto;` on the divider. + +<Canvas of={DividerStories.Vertical} withToolbar={true} sourceState="shown" /> + +#### Static color + +When displaying over images or colored backgrounds, use the `static-color` attribute for better contrast, e.g. `static-color="white"` on a dark background or `static-color="black"` on a light background: + +<Canvas + of={DividerStories.StaticBlack} + withToolbar={true} + sourceState="shown" +/> +<Canvas + of={DividerStories.StaticWhite} + withToolbar={true} + sourceState="shown" +/> + +### Accessibility + +The `<sp-divider>` element implements the following accessibility features: + +- **ARIA role**: Automatically sets `role="separator"` to ensure proper semantic meaning for assistive technologies +- **Orientation support**: When `vertical` is true, automatically sets `aria-orientation="vertical"` to indicate the divider's orientation + +#### Best practices + +- Medium or large dividers can be used with header text to visually create a section or page title. Place the divider below the header for best results. +- Use dividers to create meaningful visual separation, not just decorative lines. +- Use dividers sparingly; excessive use can diminish their visual impact. diff --git a/2nd-gen/packages/swc/components/progress-circle/stories/progress-circle.a11y.mdx b/2nd-gen/packages/swc/components/progress-circle/stories/progress-circle.a11y.mdx deleted file mode 100644 index 68285e44793..00000000000 --- a/2nd-gen/packages/swc/components/progress-circle/stories/progress-circle.a11y.mdx +++ /dev/null @@ -1,43 +0,0 @@ -import { Canvas, Story, Meta } from '@storybook/addon-docs/blocks'; -import * as ProgressCircleStories from './progress-circle.stories'; - -This is coming from the accessibility markdown file through the AccessibilityDocs block. - -## Accessibility - -### Features - -<Canvas of={ProgressCircleStories.Indeterminate} meta={ProgressCircleStories} /> - -The `<sp-progress-circle>` element implements several accessibility features: - -1. **ARIA Role**: Automatically sets `role="progressbar"` for proper semantic meaning -2. **Labeling**: - - Uses the `label` attribute value as `aria-label` - - When determinate, adds `aria-valuenow` with the current progress - - Includes `aria-valuemin="0"` and `aria-valuemax="100"` for the progress range -3. **Status Communication**: - - Screen readers announce progress updates - - Indeterminate state is properly conveyed to assistive technologies - -### Best Practices - -- Always provide a descriptive `label` that explains what the progress represents -- Use determinate progress when possible to give users a clear sense of completion -- For determinate progress, ensure the `progress` value accurately reflects the actual progress -- Consider using `size="l"` for primary loading states to improve visibility -- Ensure sufficient color contrast when using `static-color="white"` - -```html -<!-- Example with good accessibility --> -<sp-progress-circle - label="Downloading report.pdf - 24 MB of 50 MB" - progress="48" -></sp-progress-circle> - -<!-- For unknown duration operations --> -<sp-progress-circle - label="Connecting to server" - indeterminate -></sp-progress-circle> -``` diff --git a/2nd-gen/packages/swc/components/progress-circle/stories/progress-circle.stories.ts b/2nd-gen/packages/swc/components/progress-circle/stories/progress-circle.stories.ts index 1894fd6fa1d..88e4c40e578 100644 --- a/2nd-gen/packages/swc/components/progress-circle/stories/progress-circle.stories.ts +++ b/2nd-gen/packages/swc/components/progress-circle/stories/progress-circle.stories.ts @@ -30,10 +30,10 @@ const { events, args, argTypes, template } = getStorybookHelpers( * @todo Blurring the range control seems to cause a catastrophic Storybook * render failure, so disabling for now. */ -// argTypes.progress = { -// ...argTypes.progress, -// control: { type: 'range', min: 0, max: 100, step: 1 }, -// }; +argTypes.progress = { + ...argTypes.progress, + control: { type: 'number', min: 0, max: 100, step: 1 }, +}; argTypes.size = { ...argTypes.size, @@ -89,6 +89,23 @@ export const Playground: Story = { // USAGE STORIES // ───────────────────── +export const Anatomy: Story = { + render: () => html` + <div style="display: flex; gap: 24px; align-items: center;"> + <swc-progress-circle + progress=${25} + size="l" + label="Loading..." + ></swc-progress-circle> + <swc-progress-circle + indeterminate + label="Saving progress" + ></swc-progress-circle> + </div> + `, + tags: ['autodocs', '!dev'], +}; + /** * This is the description fo the sizes story */ @@ -162,6 +179,56 @@ export const Indeterminate: Story = { tags: ['usage'], }; +export const StaticColors: Story = { + render: () => html` + <div + style="background: linear-gradient(45deg, rgb(64 0 22), rgb(14 24 67)); padding: 24px; display: inline-flex; gap: 24px; align-items: center;" + > + <swc-progress-circle + .progress=${60} + static-color="white" + size="s" + label="Loading on dark background" + ></swc-progress-circle> + <swc-progress-circle + .progress=${60} + static-color="white" + size="m" + label="Loading on dark background" + ></swc-progress-circle> + <swc-progress-circle + .progress=${60} + static-color="white" + size="l" + label="Loading on dark background" + ></swc-progress-circle> + </div> + <div + style="background: linear-gradient(45deg, rgb(255 241 246), rgb(238 245 255)); padding: 24px; display: inline-flex; gap: 24px; align-items: center;" + > + <swc-progress-circle + .progress=${60} + static-color="black" + size="s" + label="Loading on dark background" + ></swc-progress-circle> + <swc-progress-circle + .progress=${60} + static-color="black" + size="m" + label="Loading on dark background" + ></swc-progress-circle> + <swc-progress-circle + .progress=${60} + static-color="black" + size="l" + label="Loading on dark background" + ></swc-progress-circle> + </div> + `, + tags: ['!dev', 'usage'], +}; + export const StaticWhite: Story = { render: () => html` <div @@ -187,7 +254,7 @@ export const StaticWhite: Story = { ></swc-progress-circle> </div> `, - tags: ['usage'], + tags: ['!dev'], }; export const StaticBlack: Story = { @@ -215,7 +282,7 @@ export const StaticBlack: Story = { ></swc-progress-circle> </div> `, - tags: ['usage'], + tags: ['!dev'], }; export const IndeterminateStaticWhite: Story = { @@ -243,38 +310,25 @@ export const IndeterminateStaticWhite: Story = { ></swc-progress-circle> </div> `, - tags: ['usage'], + tags: ['!dev'], }; // ──────────────────────────────── // ACCESSIBILITY STORIES // ──────────────────────────────── -export const Accessibility: Story = { - render: () => html` - <div> - <p> - This is coming from the accessibility story through the - Accessibility block. This option allows us to fully customize - the accessibility documentation for a component by writing a - custom story that renders the accessibility documentation. - </p> - </div> - `, - tags: ['a11y'], -}; - -export const KeyboardNavigation: Story = { +export const A11y: Story = { render: () => html` - <div> - <p> - This is coming from the keyboard navigation story through the - Accessibility block. This option allows us to fully customize - allows us to fully customize the accessibility documentation for - a component by writing a custom story that renders the - accessibility documentation. - </p> + <div + style="background: linear-gradient(45deg, rgb(64 0 22), rgb(14 24 67)); padding: 24px; display: flex; gap: 24px; align-items: center;" + > + <swc-progress-circle + .progress=${60} + static-color="white" + size="l" + label="Loading on dark background" + ></swc-progress-circle> </div> `, - tags: ['a11y'], + tags: ['!dev'], }; diff --git a/2nd-gen/packages/swc/components/progress-circle/stories/progress-circle.usage.mdx b/2nd-gen/packages/swc/components/progress-circle/stories/progress-circle.usage.mdx index 39bb66e8ac3..41bbb62658e 100644 --- a/2nd-gen/packages/swc/components/progress-circle/stories/progress-circle.usage.mdx +++ b/2nd-gen/packages/swc/components/progress-circle/stories/progress-circle.usage.mdx @@ -2,8 +2,100 @@ import { Canvas, Story, Meta } from '@storybook/addon-docs/blocks'; import { SpectrumStories } from '../../../.storybook/blocks/SpectrumStories'; import * as ProgressCircleStories from './progress-circle.stories'; -<Meta title="Progress circle/Usage" /> +<Meta tag="usage" /> -# Usage +## Usage -<SpectrumStories of={ProgressCircleStories} tag="usage" /> +```zsh +yarn add @spectrum-web-components/progress-circle +``` + +Import the side effectful registration of `<sp-progress-circle>` via: + +```ts +import '@spectrum-web-components/progress-circle/sp-progress-circle.js'; +``` + +When looking to leverage the `ProgressCircle` base class as a type and/or for extension purposes, do so via: + +```ts +import { ProgressCircle } from '@spectrum-web-components/progress-circle'; +``` + +### Anatomy + +A progress circle consists of several key parts: + +- A label (via `slot="label"`) +- A progress value (via `progress` attribute) +- An an optional indeterminate state (via `indeterminate` attribute) +- An optional size +- An optional static color for backgrounds that have color + +<Canvas + of={ProgressCircleStories.Anatomy} + withToolbar={true} + sourceState="shown" +/> + +### Options + +#### Sizes + +Progress circles come in three sizes to fit various contexts: + +<Canvas + of={ProgressCircleStories.Sizes} + withToolbar={true} + sourceState="shown" +/> + +#### Static Colors + +When displaying over images or colored backgrounds, use the `static-color` attribute for better contrast, e.g. `static-color="white"` on a dark background or `static-color="black"` on a light background: + +<Canvas + of={ProgressCircleStories.StaticColors} + withToolbar={true} + sourceState="shown" +/> + +### States + +#### Indeterminate + +Use indeterminate progress when the duration cannot be calculated: + +<Canvas + of={ProgressCircleStories.Indeterminate} + withToolbar={true} + sourceState="shown" +/> + +## Accessibility + +### Features + +The `<sp-progress-circle>` element implements several accessibility features: + +1. **ARIA Role**: Automatically sets `role="progressbar"` for proper semantic meaning +2. **Labeling**: + - Uses the `label` attribute value as `aria-label` + - When determinate, adds `aria-valuenow` with the current progress + - Includes `aria-valuemin="0"` and `aria-valuemax="100"` for the progress range +3. **Status Communication**: + - Screen readers announce progress updates + - Indeterminate state is properly conveyed to assistive technologies + +### Best Practices + +- Always provide a descriptive `label` that explains what the progress represents +- Use determinate progress when possible to give users a clear sense of completion +- For determinate progress, ensure the `progress` value accurately reflects the actual progress +- Consider using size="l" for primary loading states to improve visibility + +<Canvas + of={ProgressCircleStories.A11y} + withToolbar={true} + sourceState="shown" +/> diff --git a/2nd-gen/packages/swc/components/status-light/stories/status-light.stories.ts b/2nd-gen/packages/swc/components/status-light/stories/status-light.stories.ts index 8360f58adb3..92b10e422b7 100644 --- a/2nd-gen/packages/swc/components/status-light/stories/status-light.stories.ts +++ b/2nd-gen/packages/swc/components/status-light/stories/status-light.stories.ts @@ -31,23 +31,11 @@ argTypes.variant = { options: StatusLight.VARIANTS, }; -/* - * @todo This is properly configuring the Select, but the control doesn't - * seem to work; need to investigate. - * - * We may have to explicitly bind the args to the component (particularly - * helpful for the size property) so the Storybook controls work as expected. - * - * i.e. render: (args) => - html`<swc-status-light .size=${args.size} variant=${args.variant} - >${args['default-slot']}</swc-status-light - >`, - */ -// argTypes.size = { -// ...argTypes.size, -// control: { type: 'select' }, -// options: StatusLight.VALID_SIZES, -// }; +argTypes.size = { + ...argTypes.size, + control: { type: 'select' }, + options: StatusLight.VALID_SIZES, +}; args['default-slot'] = 'Status light'; args.size = 'm'; @@ -72,10 +60,10 @@ type StatusLightVariant = typeof StatusLight.prototype.variant; type StatusLightSize = typeof StatusLight.prototype.size; /** - * Status lights should always include a label with text that clearly communicates the kind of status being shown. Color - * alone is not enough to communicate the status. Do not change the text color to match the dot. + * An `<sp-status-light>` is a great way to convey semantic meaning, such as statuses and categories. + * It provides visual indicators through colored dots accompanied by descriptive text. */ -export const Default: Story = { +export const Playground: Story = { tags: ['autodocs', 'dev'], }; @@ -151,6 +139,20 @@ export const Sizes: Story = { tags: ['usage'], }; +export const A11y: Story = { + render: () => html` + <swc-status-light variant="positive">approved</swc-status-light> + <swc-status-light variant="negative">rejected</swc-status-light> + <swc-status-light variant="notice">needs approval</swc-status-light> + <swc-status-light variant="info">new feature</swc-status-light> + <swc-status-light variant="neutral">version 1.2.10</swc-status-light> + <swc-status-light variant="celery">online</swc-status-light> + <swc-status-light variant="yellow">busy</swc-status-light> + <swc-status-light variant="silver">away</swc-status-light> + `, + tags: ['autodocs', '!dev'], +}; + // ──────────────────────── // HELPER FUNCTIONS // ──────────────────────── diff --git a/2nd-gen/packages/swc/components/status-light/stories/status-light.usage.mdx b/2nd-gen/packages/swc/components/status-light/stories/status-light.usage.mdx new file mode 100644 index 00000000000..09c94a26912 --- /dev/null +++ b/2nd-gen/packages/swc/components/status-light/stories/status-light.usage.mdx @@ -0,0 +1,75 @@ +import { Canvas, Story, Meta } from '@storybook/addon-docs/blocks'; +import { SpectrumStories } from '../../../.storybook/blocks/SpectrumStories'; +import * as StatusLightStories from './status-light.stories'; + +<Meta tag="usage" /> + +## Usage + +``` +yarn add @spectrum-web-components/status-light +``` + +Import the side effectful registration of `<sp-status-light>` via: + +``` +import '@spectrum-web-components/status-light/sp-status-light.js'; +``` + +When looking to leverage the `StatusLight` base class as a type and/or for extension purposes, do so via: + +``` +import { StatusLight } from '@spectrum-web-components/status-light'; +``` + +### Anatomy + +A status light consists of a colored dot indicator and a required text label. The dot's color represents the status or category, while the text provides additional context. The following are key aspects of status-light: + +- Required text +- An optional size +- An optional variant + +<Canvas + of={StatusLightStories.Playground} + withToolbar={true} + sourceState="shown" +/> + +### Options + +#### Sizes + +Status lights come in three sizes to fit various contexts, `s`, `m`, or `l`: + +<Canvas of={StatusLightStories.Sizes} withToolbar={true} sourceState="shown" /> + +#### Variants + +Status lights come in various semantic and non-semantic variants to convey different meanings. The `variant` attribute controls the main variant of the status light, with `neutral` being the default. + +<Canvas + of={StatusLightStories.SemanticVariants} + withToolbar={true} + sourceState="shown" +/> + +<Canvas + of={StatusLightStories.NonsemanticVariants} + withToolbar={true} + sourceState="shown" +/> + +### Accessibility + +The status light component implements several accessibility feature: + +- **Color Meaning**: Colors are used in combination with text labels to ensure that status information is not conveyed through color alone. + +#### Best Practices + +- Use semantic variants (`positive`, `negative`, `notice`, `info`, `neutral`) when the status has specific meaning +- Include a clear, descriptive text label that explains the status +- Ensure sufficient color contrast between the status light and its background + +<Canvas of={StatusLightStories.A11y} withToolbar={true} sourceState="shown" /> From 0905bbd6ff777a8da0e6f3542ad19a0f1a935138 Mon Sep 17 00:00:00 2001 From: Nikki Massaro <5090492+nikkimk@users.noreply.github.com> Date: Tue, 9 Dec 2025 10:48:04 -0500 Subject: [PATCH 05/11] docs(asset): modified asset story (#5926) --- .../swc/components/asset/stories/asset.stories.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/2nd-gen/packages/swc/components/asset/stories/asset.stories.ts b/2nd-gen/packages/swc/components/asset/stories/asset.stories.ts index df10d956555..3990613c1d1 100644 --- a/2nd-gen/packages/swc/components/asset/stories/asset.stories.ts +++ b/2nd-gen/packages/swc/components/asset/stories/asset.stories.ts @@ -40,8 +40,7 @@ argTypes.size = { // we need to use a select option and render a predefined HTML template based on the selected option argTypes['default-slot'] = { ...argTypes['default-slot'], - control: { type: 'select' }, - options: [undefined, 'slotted image'], + control: { type: 'text' }, }; /* @@ -77,15 +76,11 @@ export default meta; export const Playground: Story = { // since we cant't use HTML templates in a slot control, // we need to use a select option and render a predefined HTML template based on the selected option - render: (args) => - html`<swc-asset label="${args.label}" variant="${args.variant}"> - ${args['default-slot'] === 'slotted image' - ? html`<img src="https://picsum.photos/120/120" alt="Avatar" />` - : ''} - </swc-asset>`, + render: (args) => template({ ...args }), args: { - variant: 'file', label: 'picture.png', + variant: undefined, + 'default-slot': `<img src="https://picsum.photos/120/120" alt="Avatar" />`, }, tags: ['autodocs', 'dev'], }; From 3e4e94606af8b655c5d2fcce62eee7b83232c008 Mon Sep 17 00:00:00 2001 From: Nikki Massaro <5090492+nikkimk@users.noreply.github.com> Date: Tue, 9 Dec 2025 14:31:18 -0500 Subject: [PATCH 06/11] docs: migrated contributor and project-planning docs (#5928) * docs(contributor-guides): mrigrated contributor guides * docs(contributor-docs): updated contributor docs to reflect storybook migration * docs(contributor-guides): updated based on new IA and use of storybook * docs(contributor-guides): fixed MDX errors * docs(contributor-guides): fixed TOC * docs(contributor-guides): fixed typo * docs(contributor-guides): fixed TOC * docs(project-planning): migrated project-planning docs to storybook * docs(project-planning): fixed typo * docs(guides): fixed links --- .../guides/accessibility-guides/overview.mdx | 4 +- .../.storybook/guides/contributor-guide.mdx | 10 - .../accessibility-testing.mdx | 436 ++++++++++++ ...uthoring-spectrum-web-component-guides.mdx | 102 +++ .../contributor-guides/getting-involved.mdx | 64 ++ .../making-a-pull-request.mdx | 180 +++++ .../participating-in-pr-reviews.mdx | 101 +++ .../patching-dependencies.mdx | 63 ++ .../contributor-guides/releasing-swc.mdx | 169 +++++ .../using-the-issue-tracker.mdx | 159 +++++ .../working-in-the-swc-repo.mdx | 128 ++++ .../.storybook/guides/project-planning.mdx | 15 - .../guides/project-planning/components.mdx | 7 + .../guides/project-planning/milestones.mdx | 17 +- .../guides/project-planning/overview.mdx | 31 +- .../1st-gen-spectrum-2-enhancements.mdx | 7 + .../add-2nd-gen-swc-component.mdx | 8 +- .../add-stories-for-2nd-gen-swc-component.mdx | 8 +- ...tor-rendering-out-of-1st-gen-component.mdx | 8 +- .../formalize-spectrum-data-model.mdx | 8 +- ...rendering-and-styles-from-spectrum-css.mdx | 19 +- .../move-base-class-to-2nd-gen-code.mdx | 8 +- .../2nd-gen-component-migration/overview.mdx | 642 ++++++++++++++++++ .../2nd-gen-defnition-and-development.mdx | 10 +- .../workstreams/about-workstreams.mdx | 23 + .../accessibility-improvements.mdx | 11 + .../workstreams/component-improvements.mdx | 12 + 2nd-gen/packages/swc/.storybook/preview.ts | 39 +- .../components/badge/stories/badge.usage.mdx | 2 +- .../01_status.md | 80 --- .../02_2nd-gen-component-migration/README.md | 34 - .../03_accessibility-improvements/README.md | 15 - .../04_component-improvements/README.md | 16 - .../README.md | 11 - .../02_workstreams/README.md | 52 -- .../03_components/README.md | 11 - .../03_project-planning/README.md | 55 -- 37 files changed, 2172 insertions(+), 393 deletions(-) delete mode 100644 2nd-gen/packages/swc/.storybook/guides/contributor-guide.mdx create mode 100644 2nd-gen/packages/swc/.storybook/guides/contributor-guides/accessibility-testing.mdx create mode 100644 2nd-gen/packages/swc/.storybook/guides/contributor-guides/authoring-spectrum-web-component-guides.mdx create mode 100644 2nd-gen/packages/swc/.storybook/guides/contributor-guides/getting-involved.mdx create mode 100644 2nd-gen/packages/swc/.storybook/guides/contributor-guides/making-a-pull-request.mdx create mode 100644 2nd-gen/packages/swc/.storybook/guides/contributor-guides/participating-in-pr-reviews.mdx create mode 100644 2nd-gen/packages/swc/.storybook/guides/contributor-guides/patching-dependencies.mdx create mode 100644 2nd-gen/packages/swc/.storybook/guides/contributor-guides/releasing-swc.mdx create mode 100644 2nd-gen/packages/swc/.storybook/guides/contributor-guides/using-the-issue-tracker.mdx create mode 100644 2nd-gen/packages/swc/.storybook/guides/contributor-guides/working-in-the-swc-repo.mdx delete mode 100644 2nd-gen/packages/swc/.storybook/guides/project-planning.mdx create mode 100644 2nd-gen/packages/swc/.storybook/guides/project-planning/components.mdx rename CONTRIBUTOR-DOCS/03_project-planning/04_milestones/README.md => 2nd-gen/packages/swc/.storybook/guides/project-planning/milestones.mdx (75%) rename CONTRIBUTOR-DOCS/03_project-planning/01_objectives-and-strategy.md => 2nd-gen/packages/swc/.storybook/guides/project-planning/overview.mdx (85%) create mode 100644 2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/1st-gen-spectrum-2-enhancements.mdx rename CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/02_step-by-step/04_implement-2nd-gen-component.md => 2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-component-migration/add-2nd-gen-swc-component.mdx (69%) rename CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/02_step-by-step/06_add-stories-for-2nd-gen-component.md => 2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-component-migration/add-stories-for-2nd-gen-swc-component.mdx (69%) rename CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/02_step-by-step/01_factor-rendering-out-of-1st-gen-component.md => 2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-component-migration/factor-rendering-out-of-1st-gen-component.mdx (72%) rename CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/02_step-by-step/03_formalize-spectrum-data-model.md => 2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-component-migration/formalize-spectrum-data-model.mdx (73%) rename CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/02_step-by-step/05_migrate-rendering-and-styles.md => 2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-component-migration/migrate-rendering-and-styles-from-spectrum-css.mdx (89%) rename CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/02_step-by-step/02_move-base-class-to-2nd-gen-core.md => 2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-component-migration/move-base-class-to-2nd-gen-code.mdx (58%) create mode 100644 2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-component-migration/overview.mdx rename CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/01_2nd-gen-definition-and-development/README.md => 2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-defnition-and-development.mdx (62%) create mode 100644 2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/about-workstreams.mdx create mode 100644 2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/accessibility-improvements.mdx create mode 100644 2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/component-improvements.mdx delete mode 100644 CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/01_status.md delete mode 100644 CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/README.md delete mode 100644 CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/03_accessibility-improvements/README.md delete mode 100644 CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/04_component-improvements/README.md delete mode 100644 CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/05_1st-gen-spectrum-2-enhancements/README.md delete mode 100644 CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/README.md delete mode 100644 CONTRIBUTOR-DOCS/03_project-planning/03_components/README.md delete mode 100644 CONTRIBUTOR-DOCS/03_project-planning/README.md diff --git a/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/overview.mdx b/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/overview.mdx index 45fe0463719..07f3de2a73d 100644 --- a/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/overview.mdx +++ b/2nd-gen/packages/swc/.storybook/guides/accessibility-guides/overview.mdx @@ -34,7 +34,7 @@ Building accessible software is simply the right thing to do. Digital content ha Many jurisdictions have legal requirements for digital accessibility: -- **[Americans with Disabilities Act (ADA)](hhttps://www.ada.gov/topics/intro-to-ada/)** requires federal and state government entities as well as private entities that own, operate, lease, or lease to places of public accommodation must be accessible to people with disabilities +- **[Americans with Disabilities Act (ADA)](https://www.ada.gov/topics/intro-to-ada/)** requires federal and state government entities as well as private entities that own, operate, lease, or lease to places of public accommodation must be accessible to people with disabilities - **[Section 508](https://www.section508.gov/)** applies to US federal government entities but impacts any entity that does buisness with the US federal government - **[European Accessibility Act](https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=COM%3A2015%3A0615%3AFINa)** establishes accessbility standards for the EU; applies to "applies to any business’s product or service that is sold or in use within the Eurozone, not just EU member state businesses" [deque blog post](https://www.deque.com/blog/eu-web-accessibility-compliance-and-legislation/) - **[Accessibility for Ontarians with Disabilities Act (AODA)](https://www.ontario.ca/laws/statute/05a11a)** "applies to every person or organization in the public and private sectors of the Province of Ontario, including the Legislative Assembly of Ontario" to comply with defined accessbility guidelines for EU member states @@ -84,7 +84,7 @@ Users interact with web components using various assistive technologies: - **[JAWS](https://www.freedomscientific.com/products/software/jaws/)**: Popular Windows screen reader, often used with Chrome or Edge browsers - **[NVDA](https://www.nvaccess.org/about-nvda/)**: Free, open-source Windows screen reader, often used with Firefox browsers -- **[VoiceOver](hhttps://support.apple.com/guide/voiceover/turn-voiceover-on-or-off-vo2682/mac)**: Built-in screen reader for macOS and iOS, often used with Safari browsers +- **[VoiceOver](https://support.apple.com/guide/voiceover/turn-voiceover-on-or-off-vo2682/mac)**: Built-in screen reader for macOS and iOS, often used with Safari browsers - **[TalkBack](https://support.google.com/accessibility/android/answer/6007100?hl=en)**: Built-in screen reader for Android, often used with Chrome browsers - **[Narrator](https://support.microsoft.com/en-us/windows/complete-guide-to-narrator-e4397a0d-ef4f-b386-d8ae-c172f109bdb1)**: Built-in Windows screen reader, often used with Edge browsers diff --git a/2nd-gen/packages/swc/.storybook/guides/contributor-guide.mdx b/2nd-gen/packages/swc/.storybook/guides/contributor-guide.mdx deleted file mode 100644 index 42d2bd92fab..00000000000 --- a/2nd-gen/packages/swc/.storybook/guides/contributor-guide.mdx +++ /dev/null @@ -1,10 +0,0 @@ -import { Meta, Markdown } from '@storybook/addon-docs/blocks'; -import ReadMe from '../../../../../CONTRIBUTOR-DOCS/README.md?raw'; - -<Meta title="Contributor guide" /> - -What is cool about this is that we can use MDX to write the documentation for the contributor docs, and then use the Storybook to render it. - -This also allows us to use the same documentation for the contributor docs and the Storybook guides but control which docs are shown in the Storybook. - -<Markdown>{ReadMe}</Markdown> diff --git a/2nd-gen/packages/swc/.storybook/guides/contributor-guides/accessibility-testing.mdx b/2nd-gen/packages/swc/.storybook/guides/contributor-guides/accessibility-testing.mdx new file mode 100644 index 00000000000..f0d53e0b68f --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/guides/contributor-guides/accessibility-testing.mdx @@ -0,0 +1,436 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + +<Meta title="Contributor guides/Accessibility testing" /> + +# Accessibility testing + +## About this guide + +This guide covers automated accessibility testing for Spectrum Web Components using Playwright. You'll learn how to write, run, and maintain accessibility tests for both 1st-gen and 2nd-gen components. + +## Quick start + +```bash +# From project root, 1st-gen, or 2nd-gen directory +yarn test:a11y # Run all tests (both generations) +yarn test:a11y:1st # Run only 1st generation tests +yarn test:a11y:2nd # Run only 2nd generation tests +yarn test:a11y:ui # Interactive UI mode (great for debugging) +``` + +Tests automatically start the required Storybook instances and run in Chromium. + +## What we test + +Two complementary approaches: + +### 1. ARIA snapshots + +Captures the accessibility tree structure and compares it to a baseline. Detects unintentional changes to: + +- ARIA roles +- ARIA attributes +- Text content +- Accessibility tree structure + +**Coverage:** ~40% of accessibility issues + +### 2. aXe-core validation + +Automatically checks ~50+ WCAG 2.0/2.1 Level A/AA rules: + +- Color contrast +- Keyboard navigation +- ARIA validity +- Semantic HTML +- Focus management + +**Coverage:** ~50% of accessibility issues + +**Together:** These catch the most common accessibility issues early in development. + +## Adding tests to a component + +### 1st generation components + +Create `<component>.a11y.spec.ts` in your component's `test/` directory: + +```typescript +// 1st-gen/packages/badge/test/badge.a11y.spec.ts + +import { expect, test } from '@playwright/test'; +import AxeBuilder from '@axe-core/playwright'; +import { gotoStory } from '../../../test/a11y-helpers.js'; + +test.describe('Badge - ARIA Snapshots', () => { + test('should have correct accessibility tree', async ({ page }) => { + const badge = await gotoStory(page, 'badge--default', 'sp-badge'); + await expect(badge).toMatchAriaSnapshot(); + }); +}); + +test.describe('Badge - aXe Validation', () => { + test('should not have accessibility violations', async ({ page }) => { + await gotoStory(page, 'badge--default', 'sp-badge'); + + const results = await new AxeBuilder({ page }) + .withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa']) + .analyze(); + + expect(results.violations).toEqual([]); + }); +}); +``` + +**Key details:** + +- Story ID: `'badge--default'` (check Storybook URL at `localhost:8080`) +- Element name: `'sp-badge'` (the custom element tag name) +- Helper import: `'../../../test/a11y-helpers.js'` (1st-gen test helpers) + +### 2nd generation components + +Same pattern, different details: + +```typescript +// 2nd-gen/packages/swc/components/badge/test/badge.a11y.spec.ts + +import { expect, test } from '@playwright/test'; +import AxeBuilder from '@axe-core/playwright'; +import { gotoStory } from '../../../utils/a11y-helpers.js'; + +test.describe('Badge - ARIA Snapshots', () => { + test('should have correct accessibility tree', async ({ page }) => { + const badge = await gotoStory( + page, + 'components-badge--default', // 2nd gen story ID format + 'swc-badge' // 2nd gen element name + ); + await expect(badge).toMatchAriaSnapshot(); + }); +}); + +test.describe('Badge - aXe Validation', () => { + test('should not have accessibility violations', async ({ page }) => { + await gotoStory(page, 'components-badge--default', 'swc-badge'); + + const results = await new AxeBuilder({ page }) + .withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa']) + .analyze(); + + expect(results.violations).toEqual([]); + }); +}); +``` + +**Key differences:** + +- Story ID: `'components-badge--default'` (check Storybook URL at `localhost:6006`) +- Element name: `'swc-badge'` (instead of `sp-badge`) +- Helper import: `'../../../utils/a11y-helpers.js'` (from swc utils directory) +- Storybook port: 6006 (vs 8080 for 1st gen) - automatically handled by Playwright + +## Test helper reference + +Test helpers are available in each generation: + +- 1st gen: `1st-gen/test/a11y-helpers.ts` +- 2nd gen: `2nd-gen/packages/swc/utils/a11y-helpers.ts` + +### `gotoStory(page, storyId, elementSelector)` + +Navigate to a Storybook story and wait deterministically for the component to be ready. + +**Parameters:** + +- `page`: Playwright Page object +- `storyId`: Storybook story ID (from the URL) +- `elementSelector`: CSS selector for the component (usually the custom element name) + +**Returns:** Playwright `Locator` for the component + +**Example:** + +```typescript +// Wait for component to be fully ready +const badge = await gotoStory(page, 'badge--default', 'sp-badge'); + +// Now safe to test +await expect(badge).toMatchAriaSnapshot(); +``` + +**How it works:** + +1. Navigates to story URL +2. Waits for custom element definition (`customElements.whenDefined`) +3. Waits for Storybook to render content +4. Waits for element visibility +5. Waits for Web Component upgrade + +This eliminates flaky tests caused by testing components before they're ready. + +### `waitForCustomElement(page, tagName)` + +Wait for a custom element to be defined. + +```typescript +await waitForCustomElement(page, 'sp-badge'); +``` + +### `waitForStoryReady(page, elementSelector)` + +Wait for Storybook story to render and component to be visible. + +```typescript +const element = await waitForStoryReady(page, 'sp-badge'); +``` + +## Finding story IDs + +Open Storybook and navigate to your component. The story ID is in the URL: + +**1st gen** (`localhost:8080`): + +``` +http://localhost:8080/?path=/story/badge--default + ^^^^^^^^^^^^^ + Story ID +``` + +**2nd gen** (`localhost:6006`): + +``` +http://localhost:6006/?path=/story/components-badge--default + ^^^^^^^^^^^^^^^^^^^^^^^^ + Story ID +``` + +## Running tests + +### From project root + +```bash +yarn test:a11y # All tests (both generations) +yarn test:a11y:1st # Only 1st generation +yarn test:a11y:2nd # Only 2nd generation +yarn test:a11y:ui # Interactive UI mode +``` + +### From generation directories + +```bash +# From 1st-gen +cd 1st-gen +yarn test:a11y # All tests (both generations) +yarn test:a11y badge # Specific component +yarn test:a11y:1st # Only 1st gen +yarn test:a11y:2nd # Only 2nd gen +yarn test:a11y badge --update-snapshots # Update ARIA baselines +yarn test:a11y:ui # UI mode + +# From 2nd-gen (new home for shared infrastructure) +cd 2nd-gen +yarn test:a11y # All tests (both generations) +yarn test:a11y:1st # Only 1st gen +yarn test:a11y:2nd # Only 2nd gen +yarn test:a11y:ui # UI mode +``` + +### Updating snapshots + +When you intentionally change a component's accessibility tree: + +```bash +yarn test:a11y <component> --update-snapshots +``` + +This updates the baseline ARIA snapshots in `<component>.a11y.spec.ts-snapshots/`. + +## Test results + +### ARIA snapshot files + +ARIA snapshots are saved as YAML files in `<test-file>-snapshots/`: + +```yaml +# Example: Badge default variant +- text: 'Default' +``` + +These files are: + +- ✅ **Committed to git** - They're the baseline +- ✅ **Updated with** `--update-snapshots` +- ✅ **Compared on every run** - Detect regressions + +**When snapshots fail:** + +1. Review the diff in the test output +2. If the change is intentional, update snapshots +3. If unexpected, fix the component + +### aXe violations + +When aXe finds violations, it reports: + +- **What's wrong** - Rule that failed +- **Where it is** - Element selector +- **How to fix it** - Link to documentation + +**Example:** + +``` +Expected: [] +Received: [ + { + id: "color-contrast", + impact: "serious", + description: "Ensures the contrast between foreground and background colors meets WCAG 2 AA", + help: "Elements must have sufficient color contrast", + helpUrl: "https://dequeuniversity.com/rules/axe/4.4/color-contrast", + nodes: [...] + } +] +``` + +## Best practices + +### Test coverage + +**Do test:** + +- Default state +- All semantic variants (positive, negative, info, etc.) +- Size variants (s, m, l, xl) +- Interactive states (disabled, selected, focused) +- With different content (text, icons, numbers) + +**Don't need to test:** + +- Every color combination +- Every possible prop combination +- Styling details (use visual regression for that) + +### When tests fail + +**ARIA snapshot failures:** + +1. Review the diff - is this intentional? +2. If yes: Update snapshots with `--update-snapshots` +3. If no: Fix the component to restore expected structure + +**aXe violations:** + +1. Read the violation message and linked docs +2. Fix the component to address the issue +3. Re-run tests to verify + +**Test timeout/hanging:** + +- Check that Storybook is running +- Verify the story ID is correct +- Ensure the element selector matches + +### Tips + +- **Start with ARIA snapshots** - They're fast to write and catch structural changes +- **Add aXe tests for critical paths** - Form controls, navigation, overlays +- **Use UI mode for debugging** - `yarn test:a11y:ui` shows live browser +- **Test variants separately** - One test per story keeps failures focused +- **Commit ARIA snapshots** - They're living documentation + +## Configuration + +### Playwright config + +`playwright.a11y.config.ts` (at the root) defines two projects: + +```typescript +projects: [ + { + name: '1st-gen', + testMatch: '**/packages/*/test/**/*.a11y.spec.ts', + use: { baseURL: 'http://localhost:8080' }, + }, + { + name: '2nd-gen', + testMatch: '**/packages/swc/components/*/test/**/*.a11y.spec.ts', + use: { baseURL: 'http://localhost:6006' }, + }, +]; +``` + +This allows both generations to run against their respective Storybook instances. + +### Auto-starting Storybook + +Tests automatically start Storybook when needed: + +```typescript +webServer: [ + { + command: 'cd ../1st-gen && yarn storybook', + port: 8080, + reuseExistingServer: !process.env.CI, + }, + { + command: 'cd packages/swc && yarn storybook', + port: 6006, + reuseExistingServer: !process.env.CI, + }, +]; +``` + +## File structure + +``` +spectrum-web-components/ +├── playwright.a11y.config.ts # Playwright config (both gens) +├── CONTRIBUTOR-DOCS/ +│ └── 01_contributor-guides/ +│ └── 09_accessibility-testing.md # This guide +├── 1st-gen/ +│ ├── package.json # Test scripts (points to root config) +│ ├── test/ +│ │ └── a11y-helpers.ts # 1st gen test helpers +│ └── packages/ +│ ├── badge/test/ +│ │ ├── badge.a11y.spec.ts # Tests +│ │ └── badge.a11y.spec.ts-snapshots/ # ARIA baselines +│ └── status-light/test/ +│ ├── status-light.a11y.spec.ts +│ └── status-light.a11y.spec.ts-snapshots/ +└── 2nd-gen/ + ├── package.json # Test scripts (points to root config) + └── packages/swc/ + ├── utils/ + │ └── a11y-helpers.ts # 2nd gen test helpers + └── components/ + ├── badge/test/ + │ ├── badge.a11y.spec.ts + │ └── badge.a11y.spec.ts-snapshots/ + └── status-light/test/ + ├── status-light.a11y.spec.ts + └── status-light.a11y.spec.ts-snapshots/ +``` + +## Resources + +- [Playwright accessibility testing](https://playwright.dev/docs/accessibility-testing) +- [Playwright ARIA snapshots](https://playwright.dev/docs/aria-snapshots) +- [aXe-core rules](https://github.com/dequelabs/axe-core/blob/develop/doc/rule-descriptions.md) +- [WCAG 2.1 quick reference](https://www.w3.org/WAI/WCAG21/quickref/) + +## Benefits + +**For developers:** + +- Catch issues in seconds, not days +- Clear, actionable failure messages +- No manual testing needed for basic checks + +**For the project:** + +- Scalable to all components +- CI-ready (runs on every PR) +- Complements manual testing diff --git a/2nd-gen/packages/swc/.storybook/guides/contributor-guides/authoring-spectrum-web-component-guides.mdx b/2nd-gen/packages/swc/.storybook/guides/contributor-guides/authoring-spectrum-web-component-guides.mdx new file mode 100644 index 00000000000..400c68f39cf --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/guides/contributor-guides/authoring-spectrum-web-component-guides.mdx @@ -0,0 +1,102 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + +<Meta title="Contributor guides/Authoring SWC guides" /> + +# Authoring SWC guides + +## Overview + +This document provides guidance for maintainers of the Spectrum Web Components guides. The SWC guides are MDX files (`.mdx`) located in the `.storybook/guides/` directory and rendered through Storybook. + +## Writing & editing docs + +### Creating a new doc + +To create a new doc: + +1. Decide where to place it within the `.storybook/guides/` directory structure +2. Create an MDX file with your content +3. Add the document to the story sort order in `preview.ts` (see [Ordering docs](#ordering-docs)) + +Your MDX file should contain an H1 heading representing the document title, along with whatever content you want to include: + +```mdx +# Your document title + +Your content goes here. + +## Section one + +More content... +``` + +### Editing existing docs + +When editing existing docs, simply modify the MDX content directly. There are no auto-generated sections or special markers to work around. + +### Titles and headings + +- Each document should have a title, represented by a Markdown H1 (`#`) heading +- Within each document, use proper heading hierarchy (don't skip levels) +- Avoid duplicate heading names in the same document (they'll create conflicting anchor links in the table of contents) + +### Links + +When linking to other docs, use Storybook's path query parameter format: + +```mdx +[Getting involved](?path=/docs/guides-contributor-guides-getting-involved--docs) +``` + +The path follows the pattern: `?path=/docs/{category}-{subcategory}-{doc-name}--docs` + +## Organizing docs + +### Folder structure + +- Keep the hierarchy shallow when possible (avoid deeply nested structures) +- Group related content into folders within `.storybook/guides/` + +### File naming conventions + +- Use lowercase kebab-case for all file names: `getting-involved.mdx`, `working-in-the-swc-repo.mdx` +- No numeric prefixes are needed; ordering is controlled separately in `preview.ts` + +### Ordering docs + +Document order in the Storybook sidebar is controlled by the `storySort` configuration in `.storybook/preview.ts`. + +To add or reorder docs, update the `order` array in the `storySort` options: + +```typescript +options: { + storySort: { + method: 'alphabetical-by-kind', + order: [ + 'Get Started', + 'Components', + 'Guides', + [ + 'Contributor guide', + [ + 'Getting involved', + 'Using the issue tracker', + 'Working in the SWC repo', + // Add new docs here in desired order + ], + ], + ], + }, +}, +``` + +- Documents not listed in the `order` array will appear alphabetically after explicitly ordered items +- Nested arrays represent subcategories + +## Committing updates + +When adding new docs, make sure to: + +1. Create the MDX file with your content +2. Update the `storySort` order in `preview.ts` if you need specific positioning +3. Commit both changes together to keep the navigation in sync with content diff --git a/2nd-gen/packages/swc/.storybook/guides/contributor-guides/getting-involved.mdx b/2nd-gen/packages/swc/.storybook/guides/contributor-guides/getting-involved.mdx new file mode 100644 index 00000000000..0e2b83fea1d --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/guides/contributor-guides/getting-involved.mdx @@ -0,0 +1,64 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + +<Meta title="Contributor guides/Getting involved" /> + +# Getting involved + +## Welcome + +Welcome! We're excited you're interested in improving Spectrum Web Components. Whether you're reporting bugs, adding new features, writing documentation, or helping other users, your contributions make this project better for everyone. + +Here you'll find a broad overview of how you can get involved. Please read through these guidelines to help keep the contribution process smooth and to ensure we're all on the same page. + +## Community & support + +A fantastic first step to contributing is filing an issue. This is where you can: + +- Ask questions, file bugs, and troubleshoot with other users. +- Propose new features and ideas or get feedback on your own through a linked pull request. +- Additionally, you can check GitHub Discussions to stay up-to-date with any major announcements about the project. + +### External contributors + +**Adobe Employees, read Internal contributors section below.** +If you need support or have a question about how something works, filing an issue is the best place to start. A team member will be in touch to either triage your issue or follow-up with you in the comments. + +### Internal contributors + +If you work for Adobe, our Slack channel #spectrum_web_components has some great workflows to get you started. Be sure to read the Welcome Canvas when you join. + +## How you can contribute + +There's a common misconception that you need to code in order to contribute. In reality, there are many different ways to help: + +- Filing well-structured bug reports that show what's broken and how to reproduce it. +- Suggesting new features that improve the current design system. +- Improving our documentation to make it clearer for the next person. +- Reviewing pull requests from other community members and sharing feedback. +- Helping other users on GitHub Discussions. +- Advocating for the project on social media or at meetups. + +Of course, contributing code is also welcome, from fixing a bug to building a brand-new component. All types of contributions help keep Spectrum Web Components thriving. + +## Contributor license agreement + +We require all external contributors to sign our [Contributor License Agreement](https://opensource.adobe.com/cla.html) (CLA). If you haven't signed it before making your first contribution, please do so—otherwise, we can't merge your changes. + +## Code of conduct + +Spectrum Web Components abides by the [Adobe Code of Conduct](https://github.com/adobe/spectrum-web-components/blob/main/CODE_OF_CONDUCT.md). By participating, you agree to treat all community members kindly and respectfully. We're committed to fostering a welcoming, inclusive environment. +Should any behavior fall short of these expectations, please report it to [Grp-opensourceoffice@adobe.com](mailto:Grp-opensourceoffice@adobe.com). + +## Developing locally + +Read the steps outlined in [Working in the SWC repo](?path=/docs/guides-contributor-guides-working-in-the-swc-repo--docs) to get your environment set up. + +If you encounter hurdles, feel free to ask for help in your pull request or in the community forum. + +## Thank you + +We appreciate everyone who invests time, energy, and expertise into Spectrum Web Components. Your contributions—big or small—help this library evolve to serve a broader audience and remain at a high standard of quality. + +If you have any suggestions for improving these guidelines, feel free to open a pull request or bring it up in our community discussions. We're always eager to make the contribution experience better. + +Happy contributing! diff --git a/2nd-gen/packages/swc/.storybook/guides/contributor-guides/making-a-pull-request.mdx b/2nd-gen/packages/swc/.storybook/guides/contributor-guides/making-a-pull-request.mdx new file mode 100644 index 00000000000..1e3e38d9634 --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/guides/contributor-guides/making-a-pull-request.mdx @@ -0,0 +1,180 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + +<Meta title="Contributor guides/Making a pull request" /> + +# Making a pull request + +This document outlines our team's expectations and best practices for creating and submitting pull requests for Spectrum Web Components. + +## Scoping and planning your PR + +### Testing + +Quality and stability are important. We require writing tests for any fixes or features you introduce. This helps ensure: + +- Bugs don't resurface later. +- New features work as intended for all users. +- Overall library reliability remains high. + +For 1st-gen testing guidance, see the [1st-gen README.md](https://github.com/adobe/spectrum-web-components/blob/main/1st-gen/README.md). Testing guidance for 2nd-gen is forthcoming. + +If you're unsure how to write tests for certain parts of the library, don't hesitate to ask maintainers for guidance. We appreciate every effort to keep the code solid! + +### Documentation + +In addition to well-tested code, documentation is crucial. Whenever you add or change a feature, include documentation for it in the relevant areas: + +- **README.md**: Each component has a README within its directory. Ensure your changes are included here. This file is used in our generated documentation site. +- **Comment annotations**: We use comment-based documentation ([JSDocs](https://jsdoc.app/)) so that references are generated automatically where possible. + +Accessible, helpful docs are a huge win for everyone, especially newcomers. + +### Code formatting + +We rely on automated tools like Prettier, ESLint, and Stylelint to enforce style preferences. Setting up these tools in your editor saves time and prevents minor style conflicts from slowing down reviews. + +### Accessibility + +Since this project is used by a diverse audience, the accessibility of our product is of utmost importance. Features will be evaluated for inclusivity by: + +- The use of semantic markup. +- The appropriate [ARIA roles, properties, and states](https://www.w3.org/WAI/ARIA/apg/example-index/) to indicate affordances that are not already indicated via semantic HTML. +- Applying [descriptive labels](https://www.w3.org/WAI/ARIA/apg/practices/names-and-descriptions/). +- The use of the expected [keyboard navigation](https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/). +- Sufficient color contrast as recommended in the [Web Content Accessibility Guidelines (WCAG)](https://www.w3.org/WAI/standards-guidelines/wcag/). + +If you're unsure about an accessibility detail, the [Web Accessibility Initiative (WAI) ARIA Practices Guide (APG)](https://www.w3.org/WAI/ARIA/apg/patterns/) is a good place to start. You can also open a discussion or ask in your PR. + +--- + +## Developing your PR + +### Branch naming + +We use a straightforward branch naming convention: + +- `[username]/[short-description]` (e.g., `alex/fix-dropdown-bug`) +- If referencing a known issue, incorporate the issue number (e.g., `alex/123-fix-dropdown-bug`) + +### Changeset requirements + +For PRs that add or update a component, you must include a changeset to trigger the release train and update the CHANGELOG. + +#### What are changesets? + +Each changeset represents changes that have enough significance to warrant a new version. A changelog represents a single release. A changelog may contain several changesets. + +There are three levels of releases that a changeset can describe, which are described by semantic versioning: + +- **Patch** (1.0.0 → 1.0.1): Bug fixes and non-breaking changes +- **Minor** (1.0.0 → 1.1.0): New features, backwards-compatible +- **Major** (1.0.0 → 2.0.0): Breaking changes requiring user update + +Each change should be categorized under one of these types: + +- **Added**: New features or capabilities +- **Changed**: Changes in existing functionality +- **Deprecated**: Soon-to-be removed features +- **Removed**: Features that have been removed +- **Fixed**: Bug fixes + +#### Writing changesets + +Changesets are different from commit messages. **Commit messages** are used to document the changes for _contributors_. **Changesets** are used to communicate the changes to the _consumers_ of the design system. + +When writing changesets: + +- **Be specific and component-focused**: Reference components by their tag names, include links to the PR, and specify what changed, why, and how users should update their code (if applicable) +- **Document breaking changes**: Clearly mark breaking changes with migration guidance, listing each change on its own line +- **Focus on user impact**: Describe changes from the user's perspective, not implementation details +- **Use past tense**: Write changes in past tense to describe what has been modified + +For detailed examples and best practices, see the [Writing Changesets guide](https://opensource.adobe.com/spectrum-web-components/guides/writing-changesets/#writing-changesets). + +### Conventional commits + +We follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification to make change tracking predictable: + +Format: `type(component?): subject` + +The component is optional but should reference the package you are updating. + +Types include: + +- `feat`: New features or enhancements +- `fix`: Bug fixes +- `docs`: Documentation changes +- `style`: Formatting, linting (not CSS changes) +- `chore`: Build tooling, repo management, dependency updates +- `perf`: Performance improvements +- `test`: Adding or updating tests + +Examples: + +- `feat(sp-card): add shadow styles for theme consistency` +- `fix(sp-action-menu): correct arrow key navigation in nested menus` +- `docs: clarify how to submit bug reports` + +For breaking changes, add a `!` after the type/scope: + +- `feat(sp-button)!: change API for icon placement` + +--- + +## Submitting your PR + +### Pull request template + +When creating a pull request, you'll be presented with our template. Complete all sections to the best of your ability, including: + +- Description of the changes +- Related issues (using proper [GitHub keywords](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/using-keywords-in-issues-and-pull-requests#linking-a-pull-request-to-an-issue) to auto-close issues i.e. `fixes`, `resolves`, or `closes`) +- Type of change in the PR title (bug fix, feature, breaking change) +- Steps you took to test your changes that reviewers can follow to also test them +- Checklist of items completed +- Screenshots/videos for visual changes + +Incomplete templates may delay the review process. + +### Labels for PR authors + +As a PR author, you can use these labels to communicate the status of your pull request: + +- `Status: Ready for review`: PR is ready for maintainer review or re-review +- `Status: WIP`: PR is still being worked on, not ready for review +- `Status: Addressing feedback`: PR owner is addressing review comments. +- `Component: [Name]`: PR affects this component + +For a complete list of labels and their meanings, including reviewer-specific labels, see [Participating in PR reviews](?path=/docs/guides-contributor-guides-participating-in-pr-reviews--docs#labels-and-their-meanings). + +--- + +## Specific requirements by element type + +### New components + +When creating or reviewing new components, ensure: + +#### Documentation + +- README contains a clear description and minimal example +- Inline documentation for all public APIs +- Accessibility documentation that aligns with WCAG patterns + +See [Documenting a component](https://opensource.adobe.com/spectrum-web-components/guides/adding-component/#documenting-the-component) for more information on our documentation standards and structure. + +#### API documentation utilizing JSDocs + +- **Slots**: All slots documented in the element class docblock +- **Events**: All dispatched events documented with `@fires` docblock +- **Class fields**: All public/protected fields have proper docblocks +- **Methods**: All public/protected methods have docblocks with parameters and return types +- **CSS custom properties**: All public CSS custom properties documented +- **CSS shadow parts**: All shadow parts documented + +#### Technical requirements + +- Component follows established patterns and conventions +- Accessibility is thoroughly considered +- Responsive design best practices are followed +- Supported cross-browser compatibility is verified diff --git a/2nd-gen/packages/swc/.storybook/guides/contributor-guides/participating-in-pr-reviews.mdx b/2nd-gen/packages/swc/.storybook/guides/contributor-guides/participating-in-pr-reviews.mdx new file mode 100644 index 00000000000..85b19de2890 --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/guides/contributor-guides/participating-in-pr-reviews.mdx @@ -0,0 +1,101 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + +<Meta title="Contributor guides/Participating in PR reviews" /> + +# Participating in PR reviews + +This document outlines our team's expectations and best practices for reviewing pull requests and participating in the PR review process for Spectrum Web Components. + +## Labels and their meanings + +[See the complete list of labels on Github. ](https://github.com/adobe/spectrum-web-components/labels) + +- `Contribution`: This label denotes the PR is from someone other than the maintainers of SWC. +- `Status: Ready for review`: PR is ready for maintainer review +- `Status: Ready for merge`: PR has two approvals and all tests pass. +- `Status: WIP`: PR is still being worked on, not ready for review +- `Status: Blocked`: PR is blocked for some reason, eg another PR needs to go in first +- `Status: On hold`: PR on hold pending more discussion. +- `Status: Addressing feedback`: PR owner is addressing review comments and will request re-review when ready. +- `Status: Ready for design review`: PR needs to be checked by the Spectrum Design team +- `Breaking`: PR contains changes that break backward compatibility +- `High priority PR review`: PR is related to a SEV 1 issue or other critical work +- `Component: [Name]`: PR affects this component + +Apply labels promptly to help maintainers prioritize and manage the review queue. + +--- + +## Pull request review process + +### Review timing + +- Maintainers aim to review PRs in a timely manner +- If your PR hasn't received attention, feel free to ping the team in the PR comments + +### Review expectations + +Reviewers will check for: + +- Adherence to code style and component patterns +- Proper test coverage +- Documentation completeness +- Accessibility compliance +- Visual regression test coverage +- Performance considerations + +### Review etiquette + +Pull requests are the start of a conversation. During the process, we aim to provide feedback that is constructive, respectful, and actionable. Suggestions will be focused on team coding standards but not on an individual's coding preferences unless there are specific considerations or risks in one approach over another. + +Both reviewers and PR authors should follow these guidelines: + +#### For reviewers + +- **Maintain momentum**: Complete reviews in a timely manner to keep the project moving forward. +- **Provide clear, actionable feedback**: Help contributors succeed by offering specific guidance and explaining the reasoning behind suggested changes. +- **Offer solutions**: When identifying areas for improvement, suggest alternative approaches and use code suggestions to make implementation easier. +- **Seek understanding**: Ask questions to clarify intent and approach, fostering a collaborative environment for learning and improvement. +- **Recognize excellence**: Celebrate well-written code and thoughtful design decisions to encourage continued high-quality contributions. +- **Focus on impact**: Prioritize feedback on architecture, functionality, and performance to ensure the most important aspects are addressed first. +- **Focus on value**: Prioritize feedback that improves code quality and maintainability over personal style preferences. If you make a suggestion that is non-blocking feedback, prepend the comment with `nit:`. +- **Consider context**: Tailor feedback to the PR author's experience level and the scope of changes. +- **Use changes requested thoughtfully**: Reserve the Changes Requested status for instances where critical issues need to be addressed. +- **Review VRTs with care**: Thoroughly examine visual regression test results and communicate approval status to authors. + +#### For PR authors + +- **Self review your PR**: Take a first pass at reviewing and commenting on your own submission. This gives reviewers valuable context and may pre-emptively answer questions that might otherwise arise. +- **Resolve/respond to all comments**: Address each review comment, either with code changes or explanations of your approach. +- **Ask for clarification**: If review feedback is unclear, ask questions to understand the concern. +- **Notify when ready**: After addressing feedback, notify reviewers that the PR is ready for another look either in Slack or by requesting a new review in GitHub. +- **Explain complex changes**: For non-obvious changes, explain your reasoning in the PR description or comments. +- **Break down large PRs**: When possible, split large changes into smaller, more manageable PRs. +- **Test thoroughly**: Before requesting review, ensure your code meets the project's quality standards. + +#### Resolving disagreements + +- **Focus on data**: Back up opinions with data, documentation, or examples where possible. +- **Refer to standards**: Use project conventions and industry best practices to guide decisions. +- **Compromise when appropriate**: Be willing to find middle ground when opinions differ. +- **Escalate respectfully**: If consensus can't be reached, involve a third team member or technical lead for guidance. +- **Document decisions**: Record the reasoning behind significant technical decisions for future reference. + +Remember that code reviews are a collaborative process aimed at improving code quality, knowledge sharing, and maintaining project standards. Approaching reviews with empathy and professionalism benefits everyone involved. + +--- + +## Merge criteria + +A PR is ready to merge when: + +1. It has received approval from two maintainers +2. All CI checks are passing + - Unit tests passing + - Integration tests passing + - Visual regression tests passing (**VRT golden images should not be updated until an approver confirms they look good**) + - Linting checks passing +3. All requested changes have been addressed +4. PR follows conventional commit standards +5. Includes proper changeset (when applicable) +6. Documentation has been updated as needed diff --git a/2nd-gen/packages/swc/.storybook/guides/contributor-guides/patching-dependencies.mdx b/2nd-gen/packages/swc/.storybook/guides/contributor-guides/patching-dependencies.mdx new file mode 100644 index 00000000000..6bdaf9a9031 --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/guides/contributor-guides/patching-dependencies.mdx @@ -0,0 +1,63 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + +<Meta title="Contributor guides/Patching dependencies" /> + +# Patching dependencies + +## About patches + +Sometimes you may need to temporarily patch a dependency to fix a bug or add functionality while waiting for an upstream fix. This project uses **Yarn 4's built-in patching system** instead of external tools like `patch-package`. + +## Creating a patch + +1. **Extract the package** for editing: + + ```bash + yarn patch <package-name> + ``` + + Example: + + ```bash + yarn patch @web/test-runner-playwright + ``` + +2. **Edit the extracted files** in the temporary directory that Yarn creates. Yarn will show you the path where you can make your changes. + +3. **Commit the patch** once you're done editing: + + ```bash + yarn patch-commit -s <temp-folder-path> + ``` + + Example: + + ```bash + yarn patch-commit -s /private/var/folders/.../user + ``` + +## How patches work + +- Patches are automatically stored in `.yarn/patches/` directory +- They are applied automatically during `yarn install` +- Patches are version-specific and will need to be recreated if the dependency version changes +- All patches are committed to the repository so they apply for all contributors + +## Updating existing patches + +To modify an existing patch: + +```bash +yarn patch <package-name> --update +``` + +This will extract the current patched version, allowing you to make additional changes. + +## Best practices + +- **Keep patches minimal**: Only change what's necessary to fix the specific issue +- **Document the reason**: Add comments in your pull request explaining why the patch is needed +- **Plan for removal**: Patches should be temporary until the upstream fix is available +- **Test thoroughly**: Ensure your patch doesn't break other functionality + +For more details, see the [Yarn patching documentation](https://yarnpkg.com/features/patching). diff --git a/2nd-gen/packages/swc/.storybook/guides/contributor-guides/releasing-swc.mdx b/2nd-gen/packages/swc/.storybook/guides/contributor-guides/releasing-swc.mdx new file mode 100644 index 00000000000..cfe0d9376be --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/guides/contributor-guides/releasing-swc.mdx @@ -0,0 +1,169 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + +<Meta title="Contributor guides/Releasing SWC" /> + +# Releasing SWC + +Users with permissions in the `@spectrum-web-components` organization on NPM can follow these steps to create and publish a new version. + +## Prerequisites + +### Main successfully builds + +Merge all pull requests to be included in the release, and wait for the `main` branch to show that it has completed the required Circle CI jobs. + +Check [Circle Ci build for `main`](https://app.circleci.com/pipelines/github/adobe/spectrum-web-components?branch=main) shows a `success` status. 1. If it failed, click `rerun` dropdown and select `rerun from failed`. 2. If it continues to fail, investigate further until you can successfully get the `main` branch building. + +--- + +### The correct version of Node is installed + +This is important to confirm before next step because differing node versions will cause build issues. + +#### Using Node Version Manager + +Run `nvm use` (assumes a Node Version Manager install), and confirm you're on an operable version of Node. + +#### Manually checking + +1. Run `node --version` to see what version you have installed +2. Check `.nvmrc` for node version requirements. +3. If the versions don't match, run `node install [version]` + +#### Troubleshooting + +If you need to install the correct yarn version and/or have issues with `yarn` command not being recognized, run `corepack enabled`. Yarn 4 uses corepack and needs to be enabled to access the commands. + +--- + +### Github Token is set up + +Check you have a GitHub token set up, run `echo $GITHUB_TOKEN`. + +#### Generate a Github token + +1. If you do not have one, set it up in [Github settings > Developer settings > Personal access tokens](https://github.com/settings/personal-access-tokens) + 1. Create a classic token + - Note: SWC changeset release token + - Set the expiration to a year or less + - Scopes: + - `repo (all)` + - `read:user` +2. Add generated token to `~/.zshrc` with `export GITHUB_TOKEN='token'` + - Make sure there isn't another export with the same name +3. Close your terminal to reset your profile, open terminal back up + +--- + +### Logged in to NPM + +Run `npm whoami` ensure that you are logged in with the user account for the public NPM registry. + +If not logged in, run `npm login` to sign in to your account. + +--- + +### NPM 2FA authenticator app + +1. Go to `Account Settings` on NPM +2. Click `Modify 2FA` in the Two-Factor Authentication section +3. Follow the instructions to configure the authenticator app (i.e. Google Authenticator) of your choice + 1. Should be able generate a 6-digit password that updates regularly + +--- + +## Releasing to NPM — the good stuff + +The publishing workflow is handled by a single unified script (`scripts/publish.js`) that automates the entire process: cleaning, building, versioning, publishing, and git operations. + +1. **Prepare your workspace:** + - Run `git checkout main && git fetch && git pull` to ensure you have the latest code + - Confirm the working directory is clean with `git status` +2. **Review changesets:** + - Scan the `.changeset` directory for pending changes + - In your IDE search `': major`, `': minor`, `': patch` to verify the release impact + - Exclude files: `.changeset/README.md` + - The highest level takes precedence (major > minor > patch) + - Confirm the changes match your expectations +3. **Prepare for publishing:** + - Open your authenticator app to have it ready + - You'll need to enter a one-time password twice during the process: + 1. Once for the main SWC packages + 2. Once for the React wrapper packages +4. **Run the publish command:** + - **Regular release:** `yarn publish` + - Creates git tags + - Publishes to npm with `latest` tag + - Commits changes to `main` + - **Snapshot release:** `yarn publish:snapshot` + - No git tags + - Publishes to npm with `snapshot` tag + - No git commits + - **Custom tag release:** `node ./scripts/publish.js --tag beta` + - No git tags + - Publishes to npm with custom tag (e.g., `beta`, `alpha`, `rc`, `nightly`) + - No git commits +5. **What happens during publishing:** + 1. The script cleans all build artifacts and reinstalls dependencies + 2. Builds all packages (1st-gen and 2nd-gen) + 3. Generates custom elements manifests + 4. Versions packages with changesets + 5. Publishes to npm (you'll enter your first OTP here) + 6. Builds React wrapper packages + 7. Publishes React wrappers to npm (you'll enter your second OTP here) + 8. For regular releases: commits changes and creates git tags +6. **Verify the release:** + - For regular releases, confirm the build on `main` passes + - Check the [tags page](https://github.com/adobe/spectrum-web-components/tags) to verify new tags were created + - The docs site will publish automatically if the commit message includes `#publish` and checks pass + +### Troubleshooting + +If publishing fails with an error: + +- Check the [list of tags](https://github.com/adobe/spectrum-web-components/tags) to see if new tags have been released for your publishing attempt. +- If they were, run `yarn publish` again (or the appropriate command for your release type). + +### Custom npm tags + +For special releases like beta, alpha, nightly, or release candidates, you can use custom npm tags with the `--tag` flag: + +```bash +# Beta release +node ./scripts/publish.js --tag beta + +# Alpha release +node ./scripts/publish.js --tag alpha + +# Nightly release +node ./scripts/publish.js --tag nightly + +# Release candidate +node ./scripts/publish.js --tag rc +``` + +Users can then install these versions with: + +```bash +yarn add @spectrum-web-components/button@beta +yarn add @spectrum-web-components/button@alpha +yarn add @spectrum-web-components/button@nightly +yarn add @spectrum-web-components/button@rc +``` + +--- + +## Publishing the documentation site manually + +### From GitHub + +1. Navigate to SWC's [Actions](https://github.com/adobe/spectrum-web-components/actions) and click the `Site publish` workflow. +2. At the top of the table, click the `Run workflow` dropdown — Use workflow from `main` branch, and click the `run workflow` button. + +### From the terminal + +If you have the [GitHub CLI](https://cli.github.com) installed, you can alternatively run `gh workflow run publish.yml --ref main` from the command line. + +### References + +[Running manual workflows](https://docs.github.com/en/actions/managing-workflow-runs/manually-running-a-workflow), GitHub documentation diff --git a/2nd-gen/packages/swc/.storybook/guides/contributor-guides/using-the-issue-tracker.mdx b/2nd-gen/packages/swc/.storybook/guides/contributor-guides/using-the-issue-tracker.mdx new file mode 100644 index 00000000000..f34fb99234d --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/guides/contributor-guides/using-the-issue-tracker.mdx @@ -0,0 +1,159 @@ +import { Meta } from '@storybook/addon-docs/blocks'; +import '@spectrum-web-components/table/elements.js'; + +<Meta title="Contributor guides/Using the issue tracker" /> + +# Using the issue tracker + +We use GitHub Issues for two purposes: + +1. Bug Reports +2. Feature Requests (after initial discussion) + +If you're having a usage issue or need support, do not open an issue. Instead, reference the Community & Support section. This helps us keep issues focused on actual bugs and actionable tasks. + +## Before creating a new issue + +1. Check the [Open Issues](https://github.com/adobe/spectrum-web-components/issues) to see if the problem has already been reported. + - TIP: Apply the component label to make your search process more straightforward. +2. If it has and the issue is still open, add a comment to the existing issue instead of opening a new one. +3. Check if you can reproduce the problem in the latest version of Spectrum Web Components by forking a code example in [Stackblitz](https://stackblitz.com/orgs/custom/SWC-Team/collections/spectrum-web-components). +4. If there are no related open issues and it is reproducible in isolation, then open a [Bug Report](https://github.com/adobe/spectrum-web-components/issues/new?template=bug_report.yaml). + +## Filing a bug report + +When you file a bug, please use the `Bug Report` template provided in GitHub. Include the following information: + +- A concise summary of the problem. +- Relevant components involved in the issue. +- Issue Severity based on our classifications defined below. +- What you expected vs. what actually happened, along with any errors logged in the console. +- Steps to reproduce the issue, preferably in an isolated environment, so that we can narrow down where the bug is originating from, preferably by forking an example from our [Stackblitz project](https://stackblitz.com/orgs/custom/SWC-Team/collections/spectrum-web-components). Be detailed if you write out the steps! +- Relevant environment details (OS, browser, library version). + +Clear bug reports speed up the triage process, help us replicate the issue, and keep the project robust. + +## Classifying issue severity + +Providing the correct issue severity classification helps us adequately assess and prioritize your issue. We reserve the right to adjust the severity of your bug during triage. +Below is our issue severity classification criteria: + +<sp-table size="m"> + <sp-table-head> + <sp-table-head-cell>Severity level</sp-table-head-cell> + <sp-table-head-cell>Description</sp-table-head-cell> + <sp-table-head-cell>Examples</sp-table-head-cell> + </sp-table-head> + <sp-table-body> + <sp-table-row> + <sp-table-cell>🔥 SEV 1</sp-table-cell> + <sp-table-cell> + A critical design or functionality issue that breaks the design + system, causes significant usability problems, or exposes + critical security vulnerabilities. This issue impacts all users + and/or essential workflows, making users unable to complete any + tasks. Requires immediate attention. + </sp-table-cell> + <sp-table-cell> + Broken navigation system, complete unresponsiveness on all + devices, components not rendering, inaccessible primary actions, + security vulnerabilities. + <br /> + <br /> + Accessibility: The end user is not able to complete core tasks + or activities (e.g., key navigational elements not accessible + via keyboard, missing or incorrect form labels that prevent + screen reader users from completing forms or actions, critical + color contrast issues that prevent users from reading or + interacting with essential content). + </sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>🔴 SEV 2</sp-table-cell> + <sp-table-cell> + A significant problem affecting the design, usability, or + functionality of the system or components for a subset of users. + This issue causes major disruptions and prevent users from + completing tasks or workflows. + <br /> + <br /> + Accessibility: Does not conform with WCAG 2.1 Level AA criteria + and blocks core user tasks (no known workaround). + </sp-table-cell> + <sp-table-cell> + Content that is out of view or unreachable by customers, + critical buttons or links not functioning, or actions that + cannot be submitted. Unintentional breaking changes causing + disruptions in production environments. + <br /> + <br /> + Accessibility: Issue with a component or controller with + widespread use and blocks core user tasks (no known workaround). + </sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>🟠 SEV 3</sp-table-cell> + <sp-table-cell> + A design or functionality issue that causes noticeable errors or + minor usability problems for users which either cause confusion + or degrade the user experience, but do not prevent task + completion. + <br /> + <br /> + Accessibility: Does not conform with WCAG 2.1 Level AA criteria + and is either non-blocking for core user tasks or blocking for + non-core user tasks. + </sp-table-cell> + <sp-table-cell> + Misleading labels, inconsistent component behavior, unexpected + interactions, decreases in system performance. + <br /> + <br /> + Accessibility: Workarounds are available and discoverable for + the end user to complete core user tasks, or the end user is not + able to complete non-core user tasks (e.g., inadequate ARIA + labels, improper focus management, insufficient color contrast + for non-critical elements). + </sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>🟡 SEV 4</sp-table-cell> + <sp-table-cell> + A minor design flaw that affects user experience, but doesn't + have a serious impact on overall usability or functionality. + This issue does not prevent users from completing tasks. + <br /> + <br /> + Accessibility: Does not conform with WCAG 2.1 Level AA criteria + but has lower user impact. + </sp-table-cell> + <sp-table-cell> + Minor visual inconsistencies, non-critical content misalignment, + or minor layout issues. + <br /> + <br /> + Accessibility: A WCAG violation is present in areas not + frequently visited by end users, or it has a lower impact on + overall accessibility and usability. + </sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>🟢 SEV 5</sp-table-cell> + <sp-table-cell> + A low-level design inconsistency or minor issue that slightly + affects usability or aesthetics, with minimal impact on users. + </sp-table-cell> + <sp-table-cell> + Slight color deviations, minor typographical errors, or small + spacing inconsistencies that do not impact functionality. + </sp-table-cell> + </sp-table-row> + </sp-table-body> +</sp-table> + +## Requesting a feature or a new component + +Is there something you wish the project did differently? Have a new component in mind? We love hearing new ideas and are eager to collaborate! + +- Start with a discussion: Share your idea in Discussions to gather feedback and see if it aligns with project goals. +- Open a feature request issue: After some positive initial conversation, open an issue using the `Feature Request` or `New Component` template with details and potential use cases. diff --git a/2nd-gen/packages/swc/.storybook/guides/contributor-guides/working-in-the-swc-repo.mdx b/2nd-gen/packages/swc/.storybook/guides/contributor-guides/working-in-the-swc-repo.mdx new file mode 100644 index 00000000000..f284f4abeb7 --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/guides/contributor-guides/working-in-the-swc-repo.mdx @@ -0,0 +1,128 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + +<Meta title="Contributor guides/Working in the SWC repo" /> + +# Working in the SWC repo + +## About this guide + +This guide covers the essential information you need to work effectively in the Spectrum Web Components (SWC) repository. + +## Getting started + +### Prerequisites + +Before you begin, ensure you have the following installed: + +- **Node.js**: Version 20.10.0 or higher (check with `node --version`) +- **Yarn**: Version 4.6.0 or higher (check with `yarn --version`) +- **Git**: For version control (check with `git --version`) + +### Installation + +1. Clone the repository: + +```bash +git clone https://github.com/adobe/spectrum-web-components.git +``` + +2. Install dependencies: + +```bash +cd spectrum-web-components +yarn install +``` + +## Repository structure + +SWC is currently in transition from its first generation (**1st-gen**) to its second generation (**2nd-gen**). + +> This transition is motivated by some important strategic goals. For more information, see [Objectives and Strategy](?path=/docs/project-planning-overview--docs). + +Instead of creating a separate branch or repo for 2nd-gen, we are working on the 1st-gen and 2nd-gen projects side-by-side in this repository, with some core functionality being shared between 1st- and 2nd-gen components. This strategy makes it easier for us to continue actively improving and supporting 1st-gen even as we devote much of our attention to defining and building 2nd-gen. + +Reflecting the side-by-side strategy, the repository is organized into two top-level workspaces: + +- **`1st-gen/`** contains all of the 1st-gen packages, tooling, and supporting materials. + + Most of what lives here will be left behind in the transition to 2nd-gen; the core component functionality we'll carry forward is gradually being moved into the `2nd-gen` workspace. + + While we'll continue doing work in `1st-gen` as needed to accomplish our goals, we expect this work to decrease steadily toward none. + +- **`2nd-gen/`** is a new workspace that we're building from the ground up to serve as a clean foundation for our future work. It includes: + - A Core library (`packages/core/`), which contains the functionality shared between 1st- and 2nd-gen + + - The 2nd-gen SWC library (`packages/swc/`). + +During this transition, depending on what you're trying to accomplish, you may end up working in `1st-gen`, `2nd-gen`, or both. If you have any questions, [please ask](?path=/docs/guides-contributor-guides-getting-involved--docs#community--support)—we're happy to help. + +## Development workflow + +The project's top-level `package.json` file defines [several commands](#command-reference) that can be run from the repository root, covering the most important parts of the development workflow. + +> By default, each command is run in both the 1st-gen and 2nd-gen workspaces, but you can add a `:1st-gen` or `:2nd-gen` suffix to any command to run it for only one workspace. + +### Developing + +We use Storybook to interact with and test components as we develop them, as well as to document components and demonstrate usage patterns for our customers. There are separate Storybooks for 1st- and 2nd-gen. + +**To start Storybook:** + +```bash +yarn start +``` + +This command launches Storybook for both 1st- and 2nd-gen and opens a browser tab for each. + +### Testing + +**To run all tests:** + +```bash +yarn test +``` + +### Linting + +The linter runs before each commit, but you can also run it manually. + +**To check for linting issues:** + +```bash +yarn lint +``` + +### Building + +You should rarely need to trigger build explicitly, but you can do so as necessary. + +**To build all packages:** + +```bash +yarn build +``` + +## Command reference + +Here are the most frequently used commands available from the repository root: + +| Command | Description | +| -------------------- | -------------------------------------------- | +| `yarn start` | Start Storybook for both 1st-gen and 2nd-gen | +| `yarn start:1st-gen` | Start Storybook for 1st-gen only | +| `yarn start:2nd-gen` | Start Storybook for 2nd-gen only | +| `yarn test` | Run tests for both 1st-gen and 2nd-gen | +| `yarn test:1st-gen` | Run tests for 1st-gen only | +| `yarn test:2nd-gen` | Run tests for 2nd-gen only | +| `yarn test:a11y` | Run accessibility tests (both generations) | +| `yarn test:a11y:1st` | Run accessibility tests for 1st-gen only | +| `yarn test:a11y:2nd` | Run accessibility tests for 2nd-gen only | +| `yarn test:a11y:ui` | Interactive accessibility test UI | +| `yarn lint` | Check for linting issues (staged files) | +| `yarn lint:1st-gen` | Check for linting issues in 1st-gen only | +| `yarn lint:2nd-gen` | Check for linting issues in 2nd-gen only | +| `yarn build` | Build all packages (2nd-gen then 1st-gen) | +| `yarn build:1st-gen` | Build 1st-gen packages only | +| `yarn build:2nd-gen` | Build 2nd-gen packages only | + +For more specific workflows and advanced topics, refer to the other contributor guides, especially [Accessibility testing](?path=/docs/guides-contributor-guides-accessibility-testing--docs) for detailed information about writing and running accessibility tests. diff --git a/2nd-gen/packages/swc/.storybook/guides/project-planning.mdx b/2nd-gen/packages/swc/.storybook/guides/project-planning.mdx deleted file mode 100644 index d5a87b28c36..00000000000 --- a/2nd-gen/packages/swc/.storybook/guides/project-planning.mdx +++ /dev/null @@ -1,15 +0,0 @@ -import { Meta } from '@storybook/addon-docs/blocks'; - -<Meta title="Project planning" /> - -# Project planning - -This guide will help you understand the project planning for SWC. - -## What is the project planning? - -The project planning is a set of rules that help you write code that is consistent with the SWC style. - -## What are the rules? - -The rules are: diff --git a/2nd-gen/packages/swc/.storybook/guides/project-planning/components.mdx b/2nd-gen/packages/swc/.storybook/guides/project-planning/components.mdx new file mode 100644 index 00000000000..f1248be2b54 --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/guides/project-planning/components.mdx @@ -0,0 +1,7 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + +<Meta title="Project planning/Components" /> + +# Components + +(Content to be added) diff --git a/CONTRIBUTOR-DOCS/03_project-planning/04_milestones/README.md b/2nd-gen/packages/swc/.storybook/guides/project-planning/milestones.mdx similarity index 75% rename from CONTRIBUTOR-DOCS/03_project-planning/04_milestones/README.md rename to 2nd-gen/packages/swc/.storybook/guides/project-planning/milestones.mdx index 8e41d57b090..b4634f883a3 100644 --- a/CONTRIBUTOR-DOCS/03_project-planning/04_milestones/README.md +++ b/2nd-gen/packages/swc/.storybook/guides/project-planning/milestones.mdx @@ -1,22 +1,9 @@ -<!-- Generated breadcrumbs - DO NOT EDIT --> +import { Meta } from '@storybook/addon-docs/blocks'; -[CONTRIBUTOR-DOCS](../../README.md) / [Project planning](../README.md) / Milestones - -<!-- Document title (editable) --> +<Meta title="Project planning/Milestones" /> # Milestones -<!-- Generated TOC - DO NOT EDIT --> - -<details open> -<summary><strong>In this doc</strong></summary> - -- [Barebones](#barebones) - -</details> - -<!-- Document content (editable) --> - Project milestones represent significant checkpoints in our work, typically marking the completion of a major phase or the achievement of a strategic goal. ## Barebones diff --git a/CONTRIBUTOR-DOCS/03_project-planning/01_objectives-and-strategy.md b/2nd-gen/packages/swc/.storybook/guides/project-planning/overview.mdx similarity index 85% rename from CONTRIBUTOR-DOCS/03_project-planning/01_objectives-and-strategy.md rename to 2nd-gen/packages/swc/.storybook/guides/project-planning/overview.mdx index e0b23e0a05f..e74a0fb2701 100644 --- a/CONTRIBUTOR-DOCS/03_project-planning/01_objectives-and-strategy.md +++ b/2nd-gen/packages/swc/.storybook/guides/project-planning/overview.mdx @@ -1,29 +1,22 @@ -<!-- Generated breadcrumbs - DO NOT EDIT --> +import { Meta } from '@storybook/addon-docs/blocks'; -[CONTRIBUTOR-DOCS](../README.md) / [Project planning](README.md) / Objectives and strategy +<Meta title="Project planning/Overview" /> -<!-- Document title (editable) --> +# Overview -# Objectives and strategy - -<!-- Generated TOC - DO NOT EDIT --> +This section contains strategic planning documentation for the Spectrum Web Components project, including objectives, workstreams, component roadmaps, and milestones. -<details open> -<summary><strong>In this doc</strong></summary> +The documentation here helps us: -- [Current objectives](#current-objectives) - - [Unify Spectrum CSS & Spectrum Web Components](#unify-spectrum-css--spectrum-web-components) - - [Build a clean foundation for future work](#build-a-clean-foundation-for-future-work) - - [Enable Spectrum 2 adoption](#enable-spectrum-2-adoption) - - [Improve accessibility](#improve-accessibility) - - [Continually improve components](#continually-improve-components) -- [Strategy](#strategy) - - [Disruptive vs. non-disruptive change](#disruptive-vs-non-disruptive-change) - - [Side-by-side development of 1st-gen and 2nd-gen](#side-by-side-development-of-1st-gen-and-2nd-gen) +- Understand the strategic context and goals driving our work +- Track progress across multiple workstreams +- Coordinate efforts that span multiple components +- Monitor individual component roadmaps and status +- Define and track project milestones -</details> +Together, these views help us manage the project roadmap, ensuring we make progress on strategic objectives while maintaining clarity about the state and evolution of individual components. -<!-- Document content (editable) --> +# Objectives and strategy ## Current objectives diff --git a/2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/1st-gen-spectrum-2-enhancements.mdx b/2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/1st-gen-spectrum-2-enhancements.mdx new file mode 100644 index 00000000000..ea3dc307d4a --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/1st-gen-spectrum-2-enhancements.mdx @@ -0,0 +1,7 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + +<Meta title="Project planning/Workstreams/1st-gen Spectrum 2 Enhancements" /> + +# 1st-gen Spectrum 2 Enhancements + +Ongoing refinement of the `spectrum-two` theme in 1st-gen as needed to deliver production-quality Spectrum 2 support for customers using 1st-gen components. diff --git a/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/02_step-by-step/04_implement-2nd-gen-component.md b/2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-component-migration/add-2nd-gen-swc-component.mdx similarity index 69% rename from CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/02_step-by-step/04_implement-2nd-gen-component.md rename to 2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-component-migration/add-2nd-gen-swc-component.mdx index e2ac26999f5..e33aa09706c 100644 --- a/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/02_step-by-step/04_implement-2nd-gen-component.md +++ b/2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-component-migration/add-2nd-gen-swc-component.mdx @@ -1,13 +1,9 @@ -<!-- Generated breadcrumbs - DO NOT EDIT --> +import { Meta } from '@storybook/addon-docs/blocks'; -[CONTRIBUTOR-DOCS](../../../../README.md) / [Project planning](../../../README.md) / [Workstreams](../../README.md) / [2nd-gen Component Migration](../README.md) / Step By Step / Add 2nd-gen SWC component - -<!-- Document title (editable) --> +<Meta title="Project planning/Workstreams/2nd-gen component migration/Add 2nd-gen SWC component" /> # Add 2nd-gen SWC component -<!-- Document content (editable) --> - - Create directory structure: `2nd-gen/packages/swc/components/[component]/` - Create `[Component].ts` file extending from `[Component]Base` - Import S2-specific types and constants from `[Component].types.ts` diff --git a/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/02_step-by-step/06_add-stories-for-2nd-gen-component.md b/2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-component-migration/add-stories-for-2nd-gen-swc-component.mdx similarity index 69% rename from CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/02_step-by-step/06_add-stories-for-2nd-gen-component.md rename to 2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-component-migration/add-stories-for-2nd-gen-swc-component.mdx index e546240abba..8228e9a6db9 100644 --- a/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/02_step-by-step/06_add-stories-for-2nd-gen-component.md +++ b/2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-component-migration/add-stories-for-2nd-gen-swc-component.mdx @@ -1,13 +1,9 @@ -<!-- Generated breadcrumbs - DO NOT EDIT --> +import { Meta } from '@storybook/addon-docs/blocks'; -[CONTRIBUTOR-DOCS](../../../../README.md) / [Project planning](../../../README.md) / [Workstreams](../../README.md) / [2nd-gen Component Migration](../README.md) / Step By Step / Add stories for 2nd-gen component - -<!-- Document title (editable) --> +<Meta title="Project planning/Workstreams/2nd-gen component migration/Add stories for 2nd-gen component" /> # Add stories for 2nd-gen component -<!-- Document content (editable) --> - - Create `stories/[component].stories.ts` file - Add section headers: METADATA, STORIES, HELPER FUNCTIONS (if needed) - In METADATA section: diff --git a/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/02_step-by-step/01_factor-rendering-out-of-1st-gen-component.md b/2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-component-migration/factor-rendering-out-of-1st-gen-component.mdx similarity index 72% rename from CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/02_step-by-step/01_factor-rendering-out-of-1st-gen-component.md rename to 2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-component-migration/factor-rendering-out-of-1st-gen-component.mdx index d66da29bee2..512300f7533 100644 --- a/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/02_step-by-step/01_factor-rendering-out-of-1st-gen-component.md +++ b/2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-component-migration/factor-rendering-out-of-1st-gen-component.mdx @@ -1,13 +1,9 @@ -<!-- Generated breadcrumbs - DO NOT EDIT --> +import { Meta } from '@storybook/addon-docs/blocks'; -[CONTRIBUTOR-DOCS](../../../../README.md) / [Project planning](../../../README.md) / [Workstreams](../../README.md) / [2nd-gen Component Migration](../README.md) / Step By Step / Factor rendering out of 1st-gen component - -<!-- Document title (editable) --> +<Meta title="Project planning/Workstreams/2nd-gen component migration/Factor rendering out of 1st-gen component" /> # Factor rendering out of 1st-gen component -<!-- Document content (editable) --> - - Use `git mv` to rename `[Component].ts` to `[Component].base.ts` - Create a new `[Component].ts` file - In `[Component].base.ts`, edit the component definition to make it an abstract class named `[Component]Base` diff --git a/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/02_step-by-step/03_formalize-spectrum-data-model.md b/2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-component-migration/formalize-spectrum-data-model.mdx similarity index 73% rename from CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/02_step-by-step/03_formalize-spectrum-data-model.md rename to 2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-component-migration/formalize-spectrum-data-model.mdx index 72089ac19f4..43b3b87500f 100644 --- a/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/02_step-by-step/03_formalize-spectrum-data-model.md +++ b/2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-component-migration/formalize-spectrum-data-model.mdx @@ -1,13 +1,9 @@ -<!-- Generated breadcrumbs - DO NOT EDIT --> +import { Meta } from '@storybook/addon-docs/blocks'; -[CONTRIBUTOR-DOCS](../../../../README.md) / [Project planning](../../../README.md) / [Workstreams](../../README.md) / [2nd-gen Component Migration](../README.md) / Step By Step / Formalize Spectrum data model - -<!-- Document title (editable) --> +<Meta title="Project planning/Workstreams/2nd-gen component migration/Formalize Spectrum data model" /> # Formalize Spectrum data model -<!-- Document content (editable) --> - - Create a `[Component].types.ts` file in the `core/components/[component]` directory - Define shared constants (e.g., semantic variants, size values) - Define S1-specific constants and type unions diff --git a/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/02_step-by-step/05_migrate-rendering-and-styles.md b/2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-component-migration/migrate-rendering-and-styles-from-spectrum-css.mdx similarity index 89% rename from CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/02_step-by-step/05_migrate-rendering-and-styles.md rename to 2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-component-migration/migrate-rendering-and-styles-from-spectrum-css.mdx index 8cfeb7a373c..835c5a19680 100644 --- a/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/02_step-by-step/05_migrate-rendering-and-styles.md +++ b/2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-component-migration/migrate-rendering-and-styles-from-spectrum-css.mdx @@ -1,24 +1,9 @@ -<!-- Generated breadcrumbs - DO NOT EDIT --> +import { Meta } from '@storybook/addon-docs/blocks'; -[CONTRIBUTOR-DOCS](../../../../README.md) / [Project planning](../../../README.md) / [Workstreams](../../README.md) / [2nd-gen Component Migration](../README.md) / Step By Step / Migrate rendering & styles from Spectrum CSS - -<!-- Document title (editable) --> +<Meta title="Project planning/Workstreams/2nd-gen component migration/Migrate rendering & styles from Spectrum CSS" /> # Migrate rendering & styles from Spectrum CSS -<!-- Generated TOC - DO NOT EDIT --> - -<details open> -<summary><strong>In this doc</strong></summary> - -- [[ TODO: Integrate this content ]](#-todo-integrate-this-content-) -- [Bring over styles from Spectrum CSS](#bring-over-styles-from-spectrum-css) -- [Update styles in the 2nd-generation component](#update-styles-in-the-2nd-generation-component) - -</details> - -<!-- Document content (editable) --> - ## [ TODO: Integrate this content ] The following bits from the top-level migration guide outline need to be integrated into this doc: diff --git a/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/02_step-by-step/02_move-base-class-to-2nd-gen-core.md b/2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-component-migration/move-base-class-to-2nd-gen-code.mdx similarity index 58% rename from CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/02_step-by-step/02_move-base-class-to-2nd-gen-core.md rename to 2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-component-migration/move-base-class-to-2nd-gen-code.mdx index 3335f5e4bfc..653005b2db8 100644 --- a/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/02_step-by-step/02_move-base-class-to-2nd-gen-core.md +++ b/2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-component-migration/move-base-class-to-2nd-gen-code.mdx @@ -1,13 +1,9 @@ -<!-- Generated breadcrumbs - DO NOT EDIT --> +import { Meta } from '@storybook/addon-docs/blocks'; -[CONTRIBUTOR-DOCS](../../../../README.md) / [Project planning](../../../README.md) / [Workstreams](../../README.md) / [2nd-gen Component Migration](../README.md) / Step By Step / Move base class to 2nd-gen core - -<!-- Document title (editable) --> +<Meta title="Project planning/Workstreams/2nd-gen component migration/Move base class to 2nd-gen core" /> # Move base class to 2nd-gen core -<!-- Document content (editable) --> - - Create a directory for the component under `core/components` - Move `[Component].base.ts` file from 1st-gen - Add `index.ts` file diff --git a/2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-component-migration/overview.mdx b/2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-component-migration/overview.mdx new file mode 100644 index 00000000000..de2dd3fb36b --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-component-migration/overview.mdx @@ -0,0 +1,642 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + +<Meta title="Project planning/Workstreams/2nd-gen component migration/Overview" /> + +# Overview + +The tactical process of migrating individual components to the multi-generation architecture: + +- Refactoring 1st-gen components to separate core functionality from generation-specific rendering +- Moving base classes into 2nd-gen Core +- Building corresponding 2nd-gen implementations +- Migrating styles from the Spectrum CSS repository + +Because our 1st-gen components vary in complexity and quality—some have known issues (a11y and otherwise) that we believe will require substantial changes or rewrites—we will add classes to 2nd-gen Core incrementally, based on component-specific roadmaps we'll build in parallel with spinning up the 2nd-gen project. + +## Status + +<sp-table size="m"> + <sp-table-head> + <sp-table-head-cell>Component</sp-table-head-cell> + <sp-table-head-cell>Factor component</sp-table-head-cell> + <sp-table-head-cell>Move to core</sp-table-head-cell> + <sp-table-head-cell>Add data model</sp-table-head-cell> + <sp-table-head-cell>Add 2nd-gen</sp-table-head-cell> + <sp-table-head-cell>Render & style</sp-table-head-cell> + <sp-table-head-cell>Add stories</sp-table-head-cell> + </sp-table-head> + <sp-table-body> + <sp-table-row> + <sp-table-cell>Accordion</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Action Bar</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Action Button</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Action Group</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Action Menu</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Alert Banner</sp-table-cell> + <sp-table-cell>✓</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Alert Dialog</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Asset</sp-table-cell> + <sp-table-cell>✓</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Avatar</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Badge</sp-table-cell> + <sp-table-cell>✓</sp-table-cell> + <sp-table-cell>✓</sp-table-cell> + <sp-table-cell>✓</sp-table-cell> + <sp-table-cell>✓</sp-table-cell> + <sp-table-cell>✓</sp-table-cell> + <sp-table-cell>✓</sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Breadcrumbs</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Button</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Button Group</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Card</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Checkbox</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Clear Button</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Close Button</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Coachmark</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Color Area</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Color Field</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Color Handle</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Color Loupe</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Color Slider</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Color Wheel</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Combobox</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Contextual Help</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Dialog</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Divider</sp-table-cell> + <sp-table-cell>✓</sp-table-cell> + <sp-table-cell>✓</sp-table-cell> + <sp-table-cell>✓</sp-table-cell> + <sp-table-cell>✓</sp-table-cell> + <sp-table-cell>✓</sp-table-cell> + <sp-table-cell>✓</sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Dropzone</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Field Group</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Field Label</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Help Text</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Icon</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Icons</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Icons UI</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Icons Workflow</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Iconset</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Illustrated Message</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Infield Button</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Link</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Menu</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Meter</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Modal</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Number Field</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Overlay</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Picker</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Picker Button</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Popover</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Progress Bar</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Progress Circle</sp-table-cell> + <sp-table-cell>✓</sp-table-cell> + <sp-table-cell>✓</sp-table-cell> + <sp-table-cell>✓</sp-table-cell> + <sp-table-cell>✓</sp-table-cell> + <sp-table-cell>✓</sp-table-cell> + <sp-table-cell>✓</sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Radio</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Search</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Sidenav</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Slider</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Split View</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Status Light</sp-table-cell> + <sp-table-cell>✓</sp-table-cell> + <sp-table-cell>✓</sp-table-cell> + <sp-table-cell>✓</sp-table-cell> + <sp-table-cell>✓</sp-table-cell> + <sp-table-cell>✓</sp-table-cell> + <sp-table-cell>✓</sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Swatch</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Switch</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Table</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Tabs</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Tags</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Textfield</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Thumbnail</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Toast</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Tooltip</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Top Nav</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Tray</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + <sp-table-row> + <sp-table-cell>Underlay</sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + <sp-table-cell></sp-table-cell> + </sp-table-row> + </sp-table-body> +</sp-table> diff --git a/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/01_2nd-gen-definition-and-development/README.md b/2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-defnition-and-development.mdx similarity index 62% rename from CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/01_2nd-gen-definition-and-development/README.md rename to 2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-defnition-and-development.mdx index 1647600920e..dc8864c4af2 100644 --- a/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/01_2nd-gen-definition-and-development/README.md +++ b/2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/2nd-gen-defnition-and-development.mdx @@ -1,12 +1,8 @@ -<!-- Generated breadcrumbs - DO NOT EDIT --> +import { Meta } from '@storybook/addon-docs/blocks'; -[CONTRIBUTOR-DOCS](../../../README.md) / [Project planning](../../README.md) / [Workstreams](../README.md) / 2nd-gen Definition and Development +<Meta title="Project planning/Workstreams/2nd-gen definition and development" /> -<!-- Document title (editable) --> - -# 2nd-gen Definition and Development - -<!-- Document content (editable) --> +# 2nd-gen definition and development Building the 2nd-gen project from the ground up as a clean foundation for future work. This workstream encompasses multiple parallel efforts: diff --git a/2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/about-workstreams.mdx b/2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/about-workstreams.mdx new file mode 100644 index 00000000000..4c9aa97075d --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/about-workstreams.mdx @@ -0,0 +1,23 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + +<Meta title="Project planning/Workstreams/About workstreams" /> + +# About workstreams + +Workstreams represent our strategic objectives translated into actionable work. Each workstream defines a coherent body of work toward a specific goal, with its own scope, approach, and priorities. + +This section of the contributor docs contains detailed information about each of our active workstreams. + +For more on how Workstreams (this section) and [Components](?path=/docs/project-planning-components--docs) provide complementary views of our work, see the [Project Planning overview](?path=/docs/project-planning-overview--docs). + +## Active workstreams + +- **[2nd-gen Definition and Development](?path=/docs/project-planning-workstreams-2nd-gen-definition-and-development--docs)** - Building the 2nd-gen project from the ground up, including rendering layer, tooling, infrastructure, tests, Storybook, and documentation. + +- **[2nd-gen Component Migration](?path=/docs/project-planning-workstreams-2nd-gen-component-migration-overview--docs)** - Tactical process of migrating individual components to enable core functionality sharing between 1st-gen and 2nd-gen. + +- **[Accessibility Improvements](?path=/docs/project-planning-workstreams-accessibility-improvements--docs)** - Systematic work to maximize accessibility through expanded documentation, comprehensive audits, and issue remediation. + +- **[Component Improvements](?path=/docs/project-planning-workstreams-component-improvements--docs)** - Ongoing enhancements including bug fixes, feature additions, API improvements, and refactoring. + +- **[1st-gen Spectrum 2 Enhancements](?path=/docs/project-planning-workstreams-1st-gen-spectrum-2-enhancements--docs)** - Ongoing refinement of the `spectrum-two` theme for 1st-gen customers. diff --git a/2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/accessibility-improvements.mdx b/2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/accessibility-improvements.mdx new file mode 100644 index 00000000000..f490145df36 --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/accessibility-improvements.mdx @@ -0,0 +1,11 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + +<Meta title="Project planning/Workstreams/Accessibility Improvements" /> + +# Accessibility Improvements + +Systematic work to maximize accessibility across all components: + +- Expanding documentation and examples +- Conducting comprehensive accessibility audits +- Addressing identified issues diff --git a/2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/component-improvements.mdx b/2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/component-improvements.mdx new file mode 100644 index 00000000000..ea5a2b7c5c7 --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/guides/project-planning/workstreams/component-improvements.mdx @@ -0,0 +1,12 @@ +import { Meta } from '@storybook/addon-docs/blocks'; + +<Meta title="Project planning/Workstreams/Component Improvements" /> + +# Component Improvements + +Ongoing enhancements to components: + +- Bug fixes +- Feature additions +- API clarity and consistency improvements +- Major refactoring or replacement as needed diff --git a/2nd-gen/packages/swc/.storybook/preview.ts b/2nd-gen/packages/swc/.storybook/preview.ts index 52564c3a35e..834ed8ba623 100644 --- a/2nd-gen/packages/swc/.storybook/preview.ts +++ b/2nd-gen/packages/swc/.storybook/preview.ts @@ -55,8 +55,8 @@ const preview = { page: DocumentTemplate, toc: { contentsSelector: '.sbdocs-content', - headingSelector: 'h2:not(.demo), h3:not(.demo), h4:not(.demo)', - ignoreSelector: '.sbdocs-subtitle', + headingSelector: 'h2, h3, h4', + ignoreSelector: '.sbdocs-subtitle, .sbdocs-preview', disable: false, unsafeTocbotOptions: { // orderedList: false, @@ -78,9 +78,42 @@ const preview = { 'Guides', [ 'Getting started guide', - 'Contributor guide', + 'Contributor guides', + [ + 'Getting involved', + 'Using the issue tracker', + 'Working in the SWC repo', + 'Making a pull request', + 'Participating in PR reviews', + 'Releasing SWC', + 'Authoring SWC guides', + 'Patching dependencies', + 'Accessibility testing', + ], 'Style guide', 'Project planning', + [ + 'Overview', + 'Components', + 'Milestones', + 'Workstreams', + [ + 'About workstreams', + '2nd-gen definition and development', + '2nd-gen component migration', + [ + 'Overview', + 'Factor rendering out of 1st-gen component', + 'Move base class to 2nd-gen core', + 'Formalize Spectrum data model', + 'Add 2nd-gen component', + 'Migrate rendering and styles', + ], + 'Accessibility improvements', + 'Component improvements', + '1st-gen Spectrum 2 enhancements', + ], + ], 'Accessibility guides', [ 'Overview', diff --git a/2nd-gen/packages/swc/components/badge/stories/badge.usage.mdx b/2nd-gen/packages/swc/components/badge/stories/badge.usage.mdx index c1ccaeebaf9..761f6819b4c 100644 --- a/2nd-gen/packages/swc/components/badge/stories/badge.usage.mdx +++ b/2nd-gen/packages/swc/components/badge/stories/badge.usage.mdx @@ -104,7 +104,7 @@ When a badge's label is too long for the available horizontal space, it wraps to The badge component implements several accessibility feature: -- **Color Meaning**: Colors are used in combination with text labels to ensure that status information is not conveyed through color alone. +- **Labeling**: Uses the `label` attribute value as `aria-label` #### Best Practices diff --git a/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/01_status.md b/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/01_status.md deleted file mode 100644 index cfe71e7e797..00000000000 --- a/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/01_status.md +++ /dev/null @@ -1,80 +0,0 @@ -<!-- Generated breadcrumbs - DO NOT EDIT --> - -[CONTRIBUTOR-DOCS](../../../README.md) / [Project planning](../../README.md) / [Workstreams](../README.md) / [2nd-gen Component Migration](README.md) / Status - -<!-- Document title (editable) --> - -# Status - -<!-- Document content (editable) --> - -| Component | [Factor Component](02_step-by-step/01_factor-rendering-out-of-1st-gen-component.md) | [Move to Core](02_step-by-step/02_move-base-class-to-2nd-gen-core.md) | [Add Data Model](02_step-by-step/03_formalize-spectrum-data-model.md) | [Add 2nd-Gen](02_step-by-step/04_implement-2nd-gen-component.md) | [Render & Style](02_step-by-step/05_migrate-rendering-and-styles.md) | [Add Stories](02_step-by-step/06_add-stories-for-2nd-gen-component.md) | -| ------------------- | ----------------------------------------------------------------------------------- | --------------------------------------------------------------------- | --------------------------------------------------------------------- | ---------------------------------------------------------------- | -------------------------------------------------------------------- | ---------------------------------------------------------------------- | -| Accordion | | | | | | | -| Action Bar | | | | | | | -| Action Button | | | | | | | -| Action Group | | | | | | | -| Action Menu | | | | | | | -| Alert Banner | ✓ | | | | | | -| Alert Dialog | | | | | | | -| Asset | ✓ | | | | | | -| Avatar | | | | | | | -| Badge | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | -| Breadcrumbs | | | | | | | -| Button | | | | | | | -| Button Group | | | | | | | -| Card | | | | | | | -| Checkbox | | | | | | | -| Clear Button | | | | | | | -| Close Button | | | | | | | -| Coachmark | | | | | | | -| Color Area | | | | | | | -| Color Field | | | | | | | -| Color Handle | | | | | | | -| Color Loupe | | | | | | | -| Color Slider | | | | | | | -| Color Wheel | | | | | | | -| Combobox | | | | | | | -| Contextual Help | | | | | | | -| Dialog | | | | | | | -| Divider | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | -| Dropzone | | | | | | | -| Field Group | | | | | | | -| Field Label | | | | | | | -| Help Text | | | | | | | -| Icon | | | | | | | -| Icons | | | | | | | -| Icons UI | | | | | | | -| Icons Workflow | | | | | | | -| Iconset | | | | | | | -| Illustrated Message | | | | | | | -| Infield Button | | | | | | | -| Link | | | | | | | -| Menu | | | | | | | -| Meter | | | | | | | -| Modal | | | | | | | -| Number Field | | | | | | | -| Overlay | | | | | | | -| Picker | | | | | | | -| Picker Button | | | | | | | -| Popover | | | | | | | -| Progress Bar | | | | | | | -| Progress Circle | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | -| Radio | | | | | | | -| Search | | | | | | | -| Sidenav | | | | | | | -| Slider | | | | | | | -| Split View | | | | | | | -| Status Light | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | -| Swatch | | | | | | | -| Switch | | | | | | | -| Table | | | | | | | -| Tabs | | | | | | | -| Tags | | | | | | | -| Textfield | | | | | | | -| Thumbnail | | | | | | | -| Toast | | | | | | | -| Tooltip | | | | | | | -| Top Nav | | | | | | | -| Tray | | | | | | | -| Underlay | | | | | | | diff --git a/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/README.md b/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/README.md deleted file mode 100644 index a37f2ef264b..00000000000 --- a/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/README.md +++ /dev/null @@ -1,34 +0,0 @@ -<!-- Generated breadcrumbs - DO NOT EDIT --> - -[CONTRIBUTOR-DOCS](../../../README.md) / [Project planning](../../README.md) / [Workstreams](../README.md) / 2nd-gen Component Migration - -<!-- Document title (editable) --> - -# 2nd-gen Component Migration - -<!-- Generated TOC - DO NOT EDIT --> - -<details open> -<summary><strong>Beneath this doc</strong></summary> - -- [Status](01_status.md) -- Step By Step - - [Factor rendering out of 1st-gen component](02_step-by-step/01_factor-rendering-out-of-1st-gen-component.md) - - [Move base class to 2nd-gen core](02_step-by-step/02_move-base-class-to-2nd-gen-core.md) - - [Formalize Spectrum data model](02_step-by-step/03_formalize-spectrum-data-model.md) - - [Add 2nd-gen SWC component](02_step-by-step/04_implement-2nd-gen-component.md) - - [Migrate rendering & styles from Spectrum CSS](02_step-by-step/05_migrate-rendering-and-styles.md) - - [Add stories for 2nd-gen component](02_step-by-step/06_add-stories-for-2nd-gen-component.md) - -</details> - -<!-- Document content (editable) --> - -The tactical process of migrating individual components to the multi-generation architecture: - -- Refactoring 1st-gen components to separate core functionality from generation-specific rendering -- Moving base classes into 2nd-gen Core -- Building corresponding 2nd-gen implementations -- Migrating styles from the Spectrum CSS repository - -Because our 1st-gen components vary in complexity and quality—some have known issues (a11y and otherwise) that we believe will require substantial changes or rewrites—we will add classes to 2nd-gen Core incrementally, based on component-specific roadmaps we'll build in parallel with spinning up the 2nd-gen project. diff --git a/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/03_accessibility-improvements/README.md b/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/03_accessibility-improvements/README.md deleted file mode 100644 index 9d831c237d5..00000000000 --- a/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/03_accessibility-improvements/README.md +++ /dev/null @@ -1,15 +0,0 @@ -<!-- Generated breadcrumbs - DO NOT EDIT --> - -[CONTRIBUTOR-DOCS](../../../README.md) / [Project planning](../../README.md) / [Workstreams](../README.md) / Accessibility Improvements - -<!-- Document title (editable) --> - -# Accessibility Improvements - -<!-- Document content (editable) --> - -Systematic work to maximize accessibility across all components: - -- Expanding documentation and examples -- Conducting comprehensive accessibility audits -- Addressing identified issues diff --git a/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/04_component-improvements/README.md b/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/04_component-improvements/README.md deleted file mode 100644 index 92b366b1bfa..00000000000 --- a/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/04_component-improvements/README.md +++ /dev/null @@ -1,16 +0,0 @@ -<!-- Generated breadcrumbs - DO NOT EDIT --> - -[CONTRIBUTOR-DOCS](../../../README.md) / [Project planning](../../README.md) / [Workstreams](../README.md) / Component Improvements - -<!-- Document title (editable) --> - -# Component Improvements - -<!-- Document content (editable) --> - -Ongoing enhancements to components: - -- Bug fixes -- Feature additions -- API clarity and consistency improvements -- Major refactoring or replacement as needed diff --git a/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/05_1st-gen-spectrum-2-enhancements/README.md b/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/05_1st-gen-spectrum-2-enhancements/README.md deleted file mode 100644 index 2e40cb29b5c..00000000000 --- a/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/05_1st-gen-spectrum-2-enhancements/README.md +++ /dev/null @@ -1,11 +0,0 @@ -<!-- Generated breadcrumbs - DO NOT EDIT --> - -[CONTRIBUTOR-DOCS](../../../README.md) / [Project planning](../../README.md) / [Workstreams](../README.md) / 1st-gen Spectrum 2 Enhancements - -<!-- Document title (editable) --> - -# 1st-gen Spectrum 2 Enhancements - -<!-- Document content (editable) --> - -Ongoing refinement of the `spectrum-two` theme in 1st-gen as needed to deliver production-quality Spectrum 2 support for customers using 1st-gen components. diff --git a/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/README.md b/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/README.md deleted file mode 100644 index aa788467cb7..00000000000 --- a/CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/README.md +++ /dev/null @@ -1,52 +0,0 @@ -<!-- Generated breadcrumbs - DO NOT EDIT --> - -[CONTRIBUTOR-DOCS](../../README.md) / [Project planning](../README.md) / Workstreams - -<!-- Document title (editable) --> - -# Workstreams - -<!-- Generated TOC - DO NOT EDIT --> - -<details open> -<summary><strong>In this doc</strong></summary> - -- [About workstreams](#about-workstreams) -- [Active workstreams](#active-workstreams) - -</details> - -<details open> -<summary><strong>Beneath this doc</strong></summary> - -- [2nd-gen Definition and Development](01_2nd-gen-definition-and-development/README.md) -- [2nd-gen Component Migration](02_2nd-gen-component-migration/README.md) - - [Status](02_2nd-gen-component-migration/01_status.md) - - Step By Step -- [Accessibility Improvements](03_accessibility-improvements/README.md) -- [Component Improvements](04_component-improvements/README.md) -- [1st-gen Spectrum 2 Enhancements](05_1st-gen-spectrum-2-enhancements/README.md) - -</details> - -<!-- Document content (editable) --> - -## About workstreams - -Workstreams represent our strategic objectives translated into actionable work. Each workstream defines a coherent body of work toward a specific goal, with its own scope, approach, and priorities. - -This section of the contributor docs contains detailed information about each of our active workstreams. - -For more on how Workstreams (this section) and [Components](../03_components/README.md) provide complementary views of our work, see the [Project Planning overview](../README.md). - -## Active workstreams - -- **[2nd-gen Definition and Development](./01_2nd-gen-definition-and-development/README.md)** - Building the 2nd-gen project from the ground up, including rendering layer, tooling, infrastructure, tests, Storybook, and documentation. - -- **[2nd-gen Component Migration](./02_2nd-gen-component-migration/README.md)** - Tactical process of migrating individual components to enable core functionality sharing between 1st-gen and 2nd-gen. - -- **[Accessibility Improvements](./03_accessibility-improvements/README.md)** - Systematic work to maximize accessibility through expanded documentation, comprehensive audits, and issue remediation. - -- **[Component Improvements](./04_component-improvements/README.md)** - Ongoing enhancements including bug fixes, feature additions, API improvements, and refactoring. - -- **[1st-gen Spectrum 2 Enhancements](./05_1st-gen-spectrum-2-enhancements/README.md)** - Ongoing refinement of the `spectrum-two` theme for 1st-gen customers. diff --git a/CONTRIBUTOR-DOCS/03_project-planning/03_components/README.md b/CONTRIBUTOR-DOCS/03_project-planning/03_components/README.md deleted file mode 100644 index 158eded19c3..00000000000 --- a/CONTRIBUTOR-DOCS/03_project-planning/03_components/README.md +++ /dev/null @@ -1,11 +0,0 @@ -<!-- Generated breadcrumbs - DO NOT EDIT --> - -[CONTRIBUTOR-DOCS](../../README.md) / [Project planning](../README.md) / Components - -<!-- Document title (editable) --> - -# Components - -<!-- Document content (editable) --> - -(Content to be added) diff --git a/CONTRIBUTOR-DOCS/03_project-planning/README.md b/CONTRIBUTOR-DOCS/03_project-planning/README.md deleted file mode 100644 index d81428d75b6..00000000000 --- a/CONTRIBUTOR-DOCS/03_project-planning/README.md +++ /dev/null @@ -1,55 +0,0 @@ -<!-- Generated breadcrumbs - DO NOT EDIT --> - -[CONTRIBUTOR-DOCS](../README.md) / Project planning - -<!-- Document title (editable) --> - -# Project planning - -<!-- Generated TOC - DO NOT EDIT --> - -<details open> -<summary><strong>In this doc</strong></summary> - -- [Contents](#contents) - -</details> - -<details open> -<summary><strong>Beneath this doc</strong></summary> - -- [Objectives and strategy](01_objectives-and-strategy.md) -- [Workstreams](02_workstreams/README.md) - - [2nd-gen Definition and Development](02_workstreams/01_2nd-gen-definition-and-development/README.md) - - [2nd-gen Component Migration](02_workstreams/02_2nd-gen-component-migration/README.md) - - [Accessibility Improvements](02_workstreams/03_accessibility-improvements/README.md) - - [Component Improvements](02_workstreams/04_component-improvements/README.md) - - [1st-gen Spectrum 2 Enhancements](02_workstreams/05_1st-gen-spectrum-2-enhancements/README.md) -- [Components](03_components/README.md) -- [Milestones](04_milestones/README.md) - -</details> - -<!-- Document content (editable) --> - -This section contains strategic planning documentation for the Spectrum Web Components project, including objectives, workstreams, component roadmaps, and milestones. - -The documentation here helps us: - -- Understand the strategic context and goals driving our work -- Track progress across multiple workstreams -- Coordinate efforts that span multiple components -- Monitor individual component roadmaps and status -- Define and track project milestones - -## Contents - -- **[Objectives and Strategy](./01_objectives-and-strategy.md)** - Strategic context for the 1st-gen-to-2nd-gen transition, including our goals and approach. - -- **[Workstreams](./02_workstreams/README.md)** - Detailed information about our active workstreams, offering a workstream-centric view of cross-cutting work affecting many or all components. - -- **[Components](./03_components/README.md)** - Component-specific planning and status information, offering a component-centric view of how individual components are affected by multiple workstreams. - -- **[Milestones](./04_milestones/README.md)** - Information about project milestones and their goals. - -Together, these views help us manage the project roadmap, ensuring we make progress on strategic objectives while maintaining clarity about the state and evolution of individual components. From 9843253e8494eb789d5eaae98483aebcb1c89187 Mon Sep 17 00:00:00 2001 From: Nikki Massaro <5090492+nikkimk@users.noreply.github.com> Date: Wed, 10 Dec 2025 17:50:10 -0500 Subject: [PATCH 07/11] docs: updated docs, decorators, and cursor rules (#5931) * chore: two doc blocks to get custom docs added to the template * chore: clean upa few things * chore: usage stories and descriptions for custom doc blocks * chore: streamlining tags in stories and created capitalize utility * chore: review fixes * chore: updated tags in stories to new pattern * chore: styling sturf and starting decorators * chore: all kinds of improvements * chore: working on static primary story but got smart links working * chore: clean up format and doc blocks * chore: migrated all 2nd gen to new format, made rules, working on styles * chore: removed tag from testing * chore: remove console logs * docs: updates rules for stories to include sections in the prescribed order * docs: updated rules to remove "demo" class recommendations for headings * docs: update exclusions for TOC headings in previews * docs: added rule to require that all stories are accessible * docs: status-light updates stories based on revised rules * docs: added additional styling parameters to flex layout decorator * docs: updated preview for better source code in docs * docs(status-light): updated status light based on new rules * docs(badge): updated docs according to updated rules * docs: updated flex-layout decorator for addtional styling options * docs: added a static colors decorator that displays both satic colors as a single story * docs: added a static colors decorator that displays both satic colors as a single story * docs: update rules to include static colors decorator * docs(divider): updated divider based on updated rules * docs: added a simple static colors exmaple to rules * docs(progress-circle): updated progress circle docs according to updated rules * docs(divider): simplified static colors story for divder and updated rules --------- Co-authored-by: Casey Eickhoff <ceickhoff@adobe.com> --- .cursor/rules/component-documentation.mdc | 798 ++++++++++++++++++ .cursor/rules/stories-format.mdc | 747 ++++++++++++++++ .vscode/extensions.json | 5 +- .vscode/local-extensions/README.md | 9 + ...ner.jsdoc-markdown-highlighting-0.0.1.vsix | Bin 0 -> 26689 bytes .../progress-circle/ProgressCircle.base.ts | 1 + 2nd-gen/packages/core/shared/base/version.ts | 1 - .../swc/.storybook/DocumentTemplate.mdx | 39 +- .../packages/swc/.storybook/assets/404.html | 178 ++++ .../swc/.storybook/assets/favicon.png | Bin 0 -> 551 bytes .../.storybook/assets/images/adobe_logo.svg | 5 + .../.storybook/assets/images/example-ava.png | Bin 0 -> 9444 bytes .../assets/images/example-ava@2x.png | Bin 0 -> 32462 bytes .../.storybook/assets/images/github_logo.svg | 5 + .../images/gradient-background-dark.png | Bin 0 -> 38078 bytes .../images/gradient-background-light.png | Bin 0 -> 49861 bytes .../assets/images/gray_migration-guide.png | Bin 0 -> 70498 bytes .../swc/.storybook/assets/images/npm_logo.svg | 11 + .../swc/.storybook/assets/images/wc_logo.svg | 28 + .../packages/swc/.storybook/assets/logo.svg | 34 + .../swc/.storybook/assets/manager.css | 102 +++ .../swc/.storybook/assets/preview.css | 72 ++ .../swc/.storybook/blocks/GettingStarted.tsx | 48 ++ .../swc/.storybook/blocks/SpectrumDocs.tsx | 12 +- .../swc/.storybook/blocks/SpectrumStories.tsx | 20 +- .../.storybook/blocks/StaticPrimaryStory.tsx | 86 ++ .../packages/swc/.storybook/blocks/index.ts | 4 + .../swc/.storybook/decorators/flex-layout.ts | 49 ++ .../swc/.storybook/decorators/index.ts | 3 + .../decorators/static-color-background.ts | 14 +- .../.storybook/decorators/static-colors.ts | 66 ++ .../packages/swc/.storybook/helpers/README.md | 92 ++ .../helpers/format-component-name.ts | 18 + .../packages/swc/.storybook/helpers/index.ts | 18 + .../helpers/static-color-wrapper.ts | 126 +++ .../swc/.storybook/loaders/font-loader.ts | 11 + 2nd-gen/packages/swc/.storybook/main.ts | 17 +- .../packages/swc/.storybook/manager-head.html | 46 + 2nd-gen/packages/swc/.storybook/manager.ts | 67 ++ .../packages/swc/.storybook/preview-head.html | 119 ++- 2nd-gen/packages/swc/.storybook/preview.ts | 43 +- .../swc/components/asset/DOC-COMPARISON.md | 161 ++++ .../components/asset/stories/asset.stories.ts | 70 +- .../components/asset/stories/asset.usage.mdx | 62 +- .../swc/components/badge/DOC-COMPARISON.md | 138 +++ .../components/badge/stories/badge.stories.ts | 294 ++++--- .../components/badge/stories/badge.usage.mdx | 116 +-- .../swc/components/divider/DOC-COMPARISON.md | 182 ++++ .../divider/stories/divider.stories.ts | 218 +++-- .../divider/stories/divider.usage.mdx | 78 +- .../stories/progress-circle.stories.ts | 370 +++----- .../stories/progress-circle.usage.mdx | 100 +-- .../components/status-light/DOC-COMPARISON.md | 152 ++++ .../stories/status-light.stories.ts | 225 +++-- .../stories/status-light.usage.mdx | 76 +- 2nd-gen/packages/swc/package.json | 1 + yarn.lock | 208 +++++ 57 files changed, 4392 insertions(+), 953 deletions(-) create mode 100644 .cursor/rules/component-documentation.mdc create mode 100644 .cursor/rules/stories-format.mdc create mode 100644 .vscode/local-extensions/README.md create mode 100644 .vscode/local-extensions/bierner.jsdoc-markdown-highlighting-0.0.1.vsix create mode 100644 2nd-gen/packages/swc/.storybook/assets/404.html create mode 100644 2nd-gen/packages/swc/.storybook/assets/favicon.png create mode 100644 2nd-gen/packages/swc/.storybook/assets/images/adobe_logo.svg create mode 100644 2nd-gen/packages/swc/.storybook/assets/images/example-ava.png create mode 100644 2nd-gen/packages/swc/.storybook/assets/images/example-ava@2x.png create mode 100644 2nd-gen/packages/swc/.storybook/assets/images/github_logo.svg create mode 100644 2nd-gen/packages/swc/.storybook/assets/images/gradient-background-dark.png create mode 100644 2nd-gen/packages/swc/.storybook/assets/images/gradient-background-light.png create mode 100644 2nd-gen/packages/swc/.storybook/assets/images/gray_migration-guide.png create mode 100644 2nd-gen/packages/swc/.storybook/assets/images/npm_logo.svg create mode 100644 2nd-gen/packages/swc/.storybook/assets/images/wc_logo.svg create mode 100644 2nd-gen/packages/swc/.storybook/assets/logo.svg create mode 100644 2nd-gen/packages/swc/.storybook/assets/manager.css create mode 100644 2nd-gen/packages/swc/.storybook/assets/preview.css create mode 100644 2nd-gen/packages/swc/.storybook/blocks/GettingStarted.tsx create mode 100644 2nd-gen/packages/swc/.storybook/blocks/StaticPrimaryStory.tsx create mode 100644 2nd-gen/packages/swc/.storybook/blocks/index.ts create mode 100644 2nd-gen/packages/swc/.storybook/decorators/flex-layout.ts create mode 100644 2nd-gen/packages/swc/.storybook/decorators/index.ts create mode 100644 2nd-gen/packages/swc/.storybook/decorators/static-colors.ts create mode 100644 2nd-gen/packages/swc/.storybook/helpers/README.md create mode 100644 2nd-gen/packages/swc/.storybook/helpers/format-component-name.ts create mode 100644 2nd-gen/packages/swc/.storybook/helpers/index.ts create mode 100644 2nd-gen/packages/swc/.storybook/helpers/static-color-wrapper.ts create mode 100644 2nd-gen/packages/swc/.storybook/loaders/font-loader.ts create mode 100644 2nd-gen/packages/swc/.storybook/manager-head.html create mode 100644 2nd-gen/packages/swc/.storybook/manager.ts create mode 100644 2nd-gen/packages/swc/components/asset/DOC-COMPARISON.md create mode 100644 2nd-gen/packages/swc/components/badge/DOC-COMPARISON.md create mode 100644 2nd-gen/packages/swc/components/divider/DOC-COMPARISON.md create mode 100644 2nd-gen/packages/swc/components/status-light/DOC-COMPARISON.md diff --git a/.cursor/rules/component-documentation.mdc b/.cursor/rules/component-documentation.mdc new file mode 100644 index 00000000000..d6406f877de --- /dev/null +++ b/.cursor/rules/component-documentation.mdc @@ -0,0 +1,798 @@ +--- +globs: 2nd-gen/packages/swc/components/*/stories/** +alwaysApply: false +--- +# Component documentation standards + +Enforce comprehensive and consistent component documentation across 1st-gen and 2nd-gen implementations. + +## Scope + +Apply to component documentation in: + +- `1st-gen/packages/*/README.md` +- `2nd-gen/packages/swc/components/*/stories/*.stories.ts` +- `2nd-gen/packages/swc/components/*/stories/*.usage.mdx` + +## Documentation completeness requirements + +### Section order + +Document sections in this order (skip sections that don't apply): + +1. **Installation** - How to install and import (may be centralized) +2. **Anatomy** - Component structure and key parts +3. **Options** - Variants, sizes, styles, and configuration + - Sizes + - Variants + - Quiet/subtle/emphasized + - Outline + - Static color + - Positioning (e.g., fixed) + - Other options as applicable +4. **States** - Different states in this order: + - Default + - Selected + - Active + - Disabled + - Readonly + - Error (valid, invalid, etc.) + - Loading/pending/indeterminate + - Other states as applicable +5. **Behaviors** - Built-in functionality: + - Automatic behaviors (text wrapping, truncation, interactivity) + - Methods + - Events +6. **Accessibility** - A11y features and best practices: + - Features (keyboard navigation, ARIA states, roles, properties) + - Best practices + +### Essential sections + +Every component must document: + +1. **Anatomy** - Component structure and key parts +2. **Options** - Variants, sizes, styles, and configuration +3. **Accessibility** - A11y features and best practices + +### Accessibility requirements for all stories + +**All stories must follow accessibility best practices.** Stories serve as examples for consumers, so they must demonstrate proper accessible usage: + +- **Include descriptive labels**: If a component requires a label (e.g., `label`, `aria-label`, slot content), every story must include it +- **Use meaningful text content**: Avoid placeholder text - use realistic, descriptive content +- **Demonstrate proper ARIA usage**: Show correct ARIA attributes when applicable +- **Never demonstrate inaccessible patterns**: Stories should not show examples that would fail accessibility audits + +### Conditional sections + +Include if applicable: + +4. **Installation** - How to install and import (may be centralized) +5. **States** - Different states (disabled, loading, error, etc.) +6. **Behaviors** - Interactive behaviors, text wrapping, methods, events + +## Installation documentation + +**Note**: Installation is documented directly in usage.mdx, not as a Storybook story. + +### Required content + +- Package name and npm install command +- Import statements +- Basic usage example + +### Example format (in usage.mdx) + +```mdx +## Installation + +Install the component package: + +```bash +npm install @spectrum-web-components/component-name +``` + +Import the component: + +```javascript +import '@spectrum-web-components/component-name/sp-component-name.js'; +``` +``` + +## Anatomy documentation + +### Required content + +- List of component parts/slots +- Visual examples showing structure +- Explanation of required vs optional elements + +**Consolidation rule**: Combine all slotted content combinations into a **single Anatomy story** to make it easier for consumers to view all variations at once. + +### Example format + +```typescript +/** + * A component-name consists of: + * + * - Primary element description + * - Secondary element description (optional) + * - Additional elements + * + * Components can contain X, Y, or both. + * All combinations are shown below for comparison. + */ +export const Anatomy: Story = { + render: (args) => html` + ${template({ ...args, /* text only */ })} + ${template({ ...args, /* icon only */ })} + ${template({ ...args, /* text + icon */ })} + `, + tags: ['anatomy'], +}; +``` + +### Common elements to document + +- Text/label slots +- Icon slots +- Required attributes +- Optional visual elements + +## Options documentation + +Document options in this order (skip subsections that don't apply): + +1. Sizes +2. Semantic variants +3. Non-semantic variants +4. Quiet/subtle/emphasized +5. Outline +6. Static color +7. Positioning (e.g., fixed) +8. Other options as applicable + +**Consolidation rules**: Combine related options into single stories for easier comparison: +- All sizes → single `Sizes` story +- All semantic variants → single `SemanticVariants` story +- All non-semantic variants → single `NonSemanticVariants` story + +### Size options + +If component has sizes, document all sizes in a **single Sizes story**: + +- All available sizes (s, m, l, xl if supported) +- Default size +- Use cases for each size +- Visual hierarchy guidance + +**Example**: + +```typescript +/** + * Components come in [X] sizes to fit various contexts: + * + * - **Small**: Used for [specific use case] + * - **Medium**: Default size, used for [typical use case] + * - **Large**: Used for [prominent use case] + * + * All sizes shown below for comparison. + */ +export const Sizes: Story = { + render: (args) => html` + ${template({ ...args, size: 's' })} + ${template({ ...args, size: 'm' })} + ${template({ ...args, size: 'l' })} + `, + tags: ['options'], +}; +``` + +### Variant options + +#### Semantic variants + +Document all semantic variants in a **single SemanticVariants story** with clear use case guidance: + +```typescript +/** + * Semantic variants provide meaning through color: + * + * - **Positive**: approved, complete, success, new, purchased, licensed + * - **Informative**: active, in use, live, published + * - **Negative**: error, alert, rejected, failed + * - **Neutral**: archived, deleted, paused, draft, not started, ended + * - **Notice**: needs approval, pending, scheduled + * + * All semantic variants shown below for comparison. + */ +export const SemanticVariants: Story = { + render: (args) => html` + ${template({ ...args, variant: 'positive' })} + ${template({ ...args, variant: 'informative' })} + ${template({ ...args, variant: 'negative' })} + ${template({ ...args, variant: 'neutral' })} + ${template({ ...args, variant: 'notice' })} + `, + tags: ['options'], +}; +``` + +#### Non-semantic variants + +Document all non-semantic variants in a **single NonSemanticVariants story**: + +```typescript +/** + * When components are for color-coded categories, they use non-semantic colors. + * Non-semantic variants are ideally used for when there are 8 categories or less. + * + * All non-semantic variants shown below for comparison. + */ +export const NonSemanticVariants: Story = { + render: (args) => html` + ${template({ ...args, variant: 'seafoam' })} + ${template({ ...args, variant: 'indigo' })} + ${/* ... other colors */ ''} + `, + tags: ['options'], +}; +``` + +### Quiet/subtle/emphasized options + +Document visual prominence modifiers: + +```typescript +/** + * - **Quiet**: Reduced visual prominence for less important actions + * - **Subtle**: Even more reduced prominence + * - **Emphasized**: Increased visual prominence for primary actions + */ +``` + +### Outline options + +Document outline style (typically semantic only): + +```typescript +/** + * The `outline` style provides a bordered appearance. + * Note: Outline style is only available with semantic variants. + */ +``` + +### Static color pattern + +For components with static-color support, implement the three-story pattern using the static color decorators: + +1. **`StaticBlack`** - Individual story with `static-color="black"` +2. **`StaticWhite`** - Individual story with `static-color="white"` +3. **`StaticColors`** - Combined story showing both variants side-by-side + +Two decorators handle static color backgrounds: + +**`withStaticColorBackground`** (automatic): +- Automatically detects `static-color` arg and applies appropriate gradient background +- Used for individual `StaticBlack` and `StaticWhite` stories + +**`staticColorsDemo`** (opt-in): +- Enable with `parameters.staticColorsDemo = true` +- Displays two variants side-by-side with appropriate backgrounds +- First child: dark gradient (for `static-color="white"`) +- Last child: light gradient (for `static-color="black"`) + +#### Simple pattern (preferred) + +Map over the static color values and use story-level args for common properties: + +```typescript +/** + * When displaying over images or colored backgrounds, use the `static-color` attribute for better contrast, + * e.g. `static-color="white"` on a dark background or `static-color="black"` on a light background. + */ +export const StaticColors: Story = { + render: (args) => html` + ${['white', 'black'].map((color) => html`${template({ ...args, 'static-color': color })}`)} + `, + args: { + progress: 60, + label: 'Loading', + }, + tags: ['options', '!test'], + parameters: { + flexLayout: false, + staticColorsDemo: true, + }, +}; +``` + +#### Contextual pattern + +Use when components need additional descriptive content around them (e.g., dividers with surrounding text): + +```typescript +/** + * When displaying over images or colored backgrounds, use the `static-color` attribute for better contrast, + * e.g. `static-color="white"` on a dark background or `static-color="black"` on a light background. + */ +export const StaticColors: Story = { + render: (args) => html` + ${['white', 'black'].map( + (color) => html` + <div> + <h4>Dashboard settings</h4> + ${template({ ...args, 'static-color': color })} + <p>Configure your dashboard preferences and layout options.</p> + </div>` + )} + `, + args: { + size: 'm', + }, + parameters: { + flexLayout: false, + staticColorsDemo: true, + }, + tags: ['options', '!test'], +}; +``` + +### Positioning options + +Document positioning modifiers like fixed: + +```typescript +/** + * The `fixed` attribute positions the component relative to the viewport. + * Use for components that should remain visible during scrolling. + */ +``` + +## States documentation + +### Required for components with states + +**Consolidation rule**: Combine all states into a **single States story** (or minimal stories when states are complex) to make it easier for consumers to compare variations. + +Document states in this order (skip states that don't apply): + +1. Default - Normal/initial state +2. Selected - When item is chosen +3. Active - During interaction +4. Disabled - When unavailable +5. Readonly - When not editable +6. Error - Validation states (valid, invalid, etc.) +7. Loading/pending/indeterminate - Async states +8. Other states as applicable + +**Example**: + +```typescript +/** + * Components can exist in various states. + * All states shown below for comparison. + */ +export const States: Story = { + render: (args) => html` + ${template({ ...args, /* default */ })} + ${template({ ...args, selected: true })} + ${template({ ...args, disabled: true })} + ${template({ ...args, readonly: true })} + ${template({ ...args, invalid: true })} + `, + tags: ['states'], +}; +``` + +If a state requires complex demonstration (e.g., animated indeterminate progress), it may warrant a separate story. + +### Default state template + +```typescript +/** + * The default state represents the component in its normal, interactive state. + */ +``` + +### Selected state template + +```typescript +/** + * The selected state indicates that the item has been chosen or activated. + */ +``` + +### Active state template + +```typescript +/** + * The active state represents the component during user interaction (e.g., mouse down, touch). + */ +``` + +### Disabled state template + +```typescript +/** + * A component in a disabled state shows that [functionality] exists, but is not available in that circumstance. + * This can be used to maintain layout continuity and communicate that [functionality] may become available later. + */ +``` + +Include ARIA support documentation: + +``` +- **ARIA support**: When disabled, the component automatically sets `aria-disabled="true"` +``` + +### Readonly state template + +```typescript +/** + * A readonly component displays its value but cannot be modified by the user. + * Unlike disabled, readonly components can still receive focus and be read by assistive technologies. + */ +``` + +### Error state template + +```typescript +/** + * Error states communicate validation status: + * + * - **Valid**: Input meets all requirements + * - **Invalid**: Input fails validation with appropriate error messaging + */ +``` + +### Loading/pending/indeterminate state template + +```typescript +/** + * Loading states indicate asynchronous operations: + * + * - **Loading**: Data is being fetched or processed + * - **Pending**: Action is awaiting completion + * - **Indeterminate**: Progress cannot be determined + */ +``` + +## Behaviors documentation + +### Required for components with behaviors + +Document behaviors in this order (skip subsections that don't apply): + +1. Automatic behaviors - Built-in functionality that can't be modified via properties or attributes +2. Methods - Public methods available on the component +3. Events - Events dispatched by the component + +### Automatic behaviors + +Document built-in functionality like: + +- Text wrapping and truncation +- Overflow handling +- Focus management +- Interactivity patterns + +```typescript +/** + * ### Text handling + * + * - Long text automatically wraps to multiple lines + * - Text truncates with ellipsis when space is constrained + * + * ### Focus behavior + * + * - Focus is trapped within the component when open + * - Focus returns to trigger element on close + */ +``` + +### Methods + +Document public methods: + +```typescript +/** + * ### Methods + * + * - `open()`: Opens the component programmatically + * - `close()`: Closes the component programmatically + * - `toggle()`: Toggles the open/closed state + */ +``` + +### Events + +Document dispatched events: + +```typescript +/** + * ### Events + * + * - `change`: Dispatched when the value changes + * - `input`: Dispatched during user input + * - `sp-opened`: Dispatched when the component opens + * - `sp-closed`: Dispatched when the component closes + */ +``` + +## Accessibility documentation + +### Required structure + +Every component must have comprehensive accessibility documentation with two subsections: + +1. **Features** - Built-in accessibility features (keyboard navigation, ARIA states, roles, properties) +2. **Best practices** - Guidelines for proper usage + +### Features template + +```typescript +/** + * ### Features + * + * The `<sp-component-name>` element implements several accessibility features: + * + * 1. **Keyboard navigation**: Description of keyboard interactions + * 2. **ARIA role**: Automatically sets appropriate role + * 3. **ARIA states**: Manages aria-disabled, aria-expanded, etc. + * 4. **ARIA properties**: Sets aria-label, aria-labelledby, etc. + * + * ### Best practices + * + * - Specific, actionable guidance + * - Another best practice + * - Consider X for Y scenarios + */ +``` + +### Common accessibility features to document + +#### Keyboard navigation + +Document keyboard interactions first: + +``` +#### Keyboard navigation + +- <kbd>Tab</kbd>: Description of tab behavior +- <kbd>Space</kbd> or <kbd>Enter</kbd>: Description of activation +- <kbd>Arrow keys</kbd>: Description of navigation +- <kbd>Escape</kbd>: Description of dismiss behavior +``` + +#### ARIA attributes + +- **ARIA role**: Document automatic role assignment +- **ARIA labels**: Document labeling mechanism (aria-label, aria-labelledby) +- **ARIA states**: Document state attributes (aria-disabled, aria-valuenow, etc.) +- **ARIA properties**: Document other ARIA properties +- **ARIA orientation**: Document for components with orientation + +**Examples**: + +``` +- **ARIA role**: Automatically sets `role="progressbar"` for proper semantic meaning +- **Labeling**: Uses the `label` attribute value as `aria-label` +- **Status communication**: Screen readers announce progress updates +``` + +#### Color meaning + +For components using color to convey information: + +``` +- **Color meaning**: Colors are used in combination with text labels to ensure that status information is not conveyed through color alone +``` + +### Best practices format + +Use bullet points with clear, actionable guidance: + +``` +- Use semantic variants when the status has specific meaning +- Always provide a descriptive `label` that explains what the component represents +- Ensure sufficient color contrast between the component and its background +- Avoid using for critical actions; use appropriate interactive components instead +``` + +## Cross-reference: 1st-gen to 2nd-gen migration + +### Content to preserve from 1st-gen + +When migrating or enhancing 2nd-gen documentation, check 1st-gen for: + +1. **Size options** - Verify all sizes (especially xl) are documented +2. **Variant lists** - Ensure all variants are listed (check for accent, etc.) +3. **States** - Check for disabled, loading, or other states +4. **Behavioral details** - Text wrapping, truncation, tooltip integration +5. **Keyboard interactions** - If documented in 1st-gen +6. **Do/Don't tables** - Valuable guidance often in 1st-gen +7. **Advanced examples** - Tooltips, containers, complex layouts +8. **Specific color contrast guidance** - Especially for static-color variants + +### Common gaps to check + +Compare 2nd-gen against 1st-gen README.md for: + +- [ ] Missing installation instructions +- [ ] Missing size options (xl is common) +- [ ] Missing semantic variants (accent is common) +- [ ] Undocumented disabled state +- [ ] Missing readonly state documentation +- [ ] Missing ARIA disabled documentation +- [ ] Lack of tooltip integration examples +- [ ] Missing icon-only accessibility guidance +- [ ] No keyboard navigation documentation +- [ ] Missing static-color contrast guidance +- [ ] No text truncation/wrapping behavior explanation +- [ ] Missing methods documentation +- [ ] Missing events documentation + +### Enhancement opportunities + +Areas where 2nd-gen often improves on 1st-gen: + +- Better structured accessibility sections +- Clearer story organization +- More comprehensive anatomy sections +- Better visual comparisons (e.g., static colors side-by-side) +- Improved testability + +## Documentation quality checklist + +### For each component + +Sections in correct order: +- [ ] Playground story set to most common use case (used as docs page preview) +- [ ] Installation section written directly in usage.mdx (if applicable) +- [ ] Anatomy story combining all slotted content variations +- [ ] Options section with consolidated stories: + - [ ] Single Sizes story with all sizes for comparison + - [ ] Single SemanticVariants story with all semantic variants (if applicable) + - [ ] Single NonSemanticVariants story with all non-semantic variants (if applicable) + - [ ] Quiet/subtle/emphasized documented (if applicable) + - [ ] Outline documented (if applicable) + - [ ] Static color with three-story pattern using `staticColorsDemo` decorator + - [ ] Positioning documented (if applicable) +- [ ] States section with consolidated story: + - [ ] Single States story combining all states for comparison + - [ ] Separate stories only for complex states (e.g., animated indeterminate) +- [ ] Behaviors section (if applicable) with subsections: + - [ ] Automatic behaviors (text wrapping, truncation, interactivity) + - [ ] Methods documented + - [ ] Events documented +- [ ] Accessibility section with subsections: + - [ ] Features (keyboard navigation, ARIA states, roles, properties) + - [ ] Best practices with actionable guidance + +Content quality: +- [ ] Semantic variants have usage examples +- [ ] Non-semantic variants note 8-category limit +- [ ] Color meaning documented for status indicators +- [ ] Label requirements clearly stated +- [ ] Do/don't guidance present + +Accessibility in all stories: +- [ ] **All stories include required accessibility attributes** (labels, aria-label, text content) +- [ ] **All stories use meaningful, descriptive content** (not placeholder text) +- [ ] **No stories demonstrate inaccessible patterns** + +## Writing style standards + +### Capitalization + +- Use sentence case for headings and descriptions +- Capitalize proper nouns and technical terms (JavaScript, CSS, ARIA, etc.) +- Use proper capitalization for semantic meaning (Positive, Negative, etc.) + +### Formatting + +- Use `**bold**` for emphasis and term introductions +- Use `code formatting` for attributes, values, and code references +- Use bullet lists for multiple related items +- Use numbered lists for sequential features or steps + +### Tone + +- Be clear and concise +- Use present tense +- Be prescriptive for best practices +- Explain "why" not just "what" + +## Example documentation levels + +### Minimal (inadequate) + +```typescript +/** + * Component with variants. + */ +export const Variants: Story = { /* ... */ }; +``` + +❌ Too brief, no context or guidance + +### Adequate + +```typescript +/** + * Badges come in semantic and non-semantic variants for different use cases. + */ +export const Variants: Story = { /* ... */ }; +``` + +⚠️ Basic information but lacks detail + +### Excellent + +```typescript +/** + * Semantic variants allow you to render the badge with a descriptive name that maps to a design-system-aligned color. + * This is the preferred way to assign color to a badge because it will align more consistently with other components in your UI with the same meaning. + * + * Use these variants for the following statuses: + * - **Positive**: approved, complete, success, new, purchased, licensed + * - **Informative**: active, in use, live, published + * - **Negative**: error, alert, rejected, failed + * - **Neutral**: archived, deleted, paused, draft, not started, ended + */ +export const SemanticVariants: Story = { /* ... */ }; +``` + +✅ Comprehensive explanation with use cases and guidance + +## Reference implementations + +### Exemplary migrations + +- **Asset**: 2nd-gen improves on minimal 1st-gen with better structure +- **Progress circle**: Clean reference implementation +- **Divider**: Maintains comprehensive 1st-gen content with improved organization + +### Components needing enhancement + +Check DOC-COMPARISON.md files in each component directory for: + +- Identified gaps vs 1st-gen +- Priority recommendations +- Specific missing content areas + +## Using documentation comparison reports + +Each migrated component has a `DOC-COMPARISON.md` file: + +``` +2nd-gen/packages/swc/components/[component-name]/DOC-COMPARISON.md +``` + +These reports identify: + +- **Missing content areas** - Critical gaps and nice-to-have additions +- **Content depth differences** - Where 1st-gen or 2nd-gen excels +- **Recommendations by priority** - High, medium, low priority enhancements +- **Content quality assessment** - Table comparing specific areas +- **Overall assessment** - Completeness score and summary + +Use these reports when: + +- Enhancing existing 2nd-gen documentation +- Creating new component documentation +- Reviewing documentation completeness +- Prioritizing documentation work + +## Continuous improvement + +When updating component documentation: + +1. Review DOC-COMPARISON.md for identified gaps +2. Check 1st-gen README.md for any additional details +3. Ensure all sections in this standard are addressed +4. Test examples in Storybook +5. Verify accessibility claims with actual implementation +6. Update DOC-COMPARISON.md if gaps are addressed diff --git a/.cursor/rules/stories-format.mdc b/.cursor/rules/stories-format.mdc new file mode 100644 index 00000000000..0329f7e48a2 --- /dev/null +++ b/.cursor/rules/stories-format.mdc @@ -0,0 +1,747 @@ +--- +description: 2nd-gen/packages/swc/components/*/stories/** +alwaysApply: false +--- +# Storybook stories format standards + +Enforce consistent formatting and structure for Storybook stories files in 2nd-gen components. + +## Scope + +Apply to all `.stories.ts` and `.usage.mdx` files in: + +- `2nd-gen/packages/swc/components/*/stories/` + +## File structure requirements + +### Stories file (`.stories.ts`) + +Every component must have a `.stories.ts` file with the following structure: + +1. **Copyright header** (lines 1-11) +2. **Imports section** +3. **METADATA section** with visual separator +4. **AUTODOCS STORY section** with visual separator +5. **ANATOMY STORIES section** with visual separator (if applicable) +6. **OPTIONS STORIES section** with visual separator +7. **STATES STORIES section** with visual separator (if applicable) +8. **BEHAVIORS STORIES section** with visual separator (if applicable) +9. **ACCESSIBILITY STORIES section** with visual separator +10. **HELPER FUNCTIONS section** with visual separator (if needed, e.g., size label mappers) + +**Note**: Installation documentation is handled separately in usage.mdx, not as a story. + +### Usage file (`.usage.mdx`) + +Every component must have a `.usage.mdx` file with simplified structure: + +```mdx +import { SpectrumStories } from '../../../.storybook/blocks'; + +## Installation + +Installation content is written directly in MDX (not a story). Include package name, npm install command, and import statements. + +## Anatomy + +<SpectrumStories tag="anatomy" hideTitle /> + +## Options + +<SpectrumStories tag="options" /> + +## States + +<SpectrumStories tag="states" /> + +## Behaviors + +<SpectrumStories tag="behaviors" /> + +## Accessibility + +<SpectrumStories tag="a11y" hideTitle /> +``` + +**Note**: Only include sections that have corresponding stories (except Installation, which is written directly in MDX). Follow this section order, skipping inapplicable sections. + +## Section formatting + +### Visual separators + +Use consistent visual separators for major sections: + +```typescript +// ──────────────── +// METADATA +// ──────────────── + +// ──────────────────── +// AUTODOCS STORY +// ──────────────────── + +// ────────────────────────── +// ANATOMY STORIES +// ────────────────────────── + +// ────────────────────────── +// OPTIONS STORIES +// ────────────────────────── + +// ────────────────────────── +// STATES STORIES +// ────────────────────────── + +// ────────────────────────────── +// BEHAVIORS STORIES +// ────────────────────────────── + +// ──────────────────────────────── +// ACCESSIBILITY STORIES +// ──────────────────────────────── + +// ──────────────────────── +// HELPER FUNCTIONS +// ──────────────────────── +``` + +**Note**: Installation documentation is written directly in usage.mdx, not as a story. + +## Meta configuration + +### Required fields + +The meta object must include: + +```typescript +const meta: Meta = { + title: 'Component name', // Required + component: 'swc-component-name', // Required + args, // Required + argTypes, // Required + render: (args) => template(args), // Required + parameters: { + actions: { + handles: events, // If events exist + }, + docs: { + subtitle: `Component description`, // Required + }, + design: { // Optional but recommended + type: 'figma', + url: 'https://www.figma.com/...', + }, + stackblitz: { // Optional but recommended + url: 'https://stackblitz.com/...', + }, + }, + tags: ['migrated'], // Required +}; +``` + +### JSDoc for meta + +Include comprehensive JSDoc comment above the meta object explaining what the component does: + +```typescript +/** + * Component description explaining its purpose and key features. + * Can be multiple paragraphs if needed. + */ +const meta: Meta = { + // ... +}; +``` + +## Accessibility requirements for all stories + +**All stories must follow accessibility best practices.** Stories serve as examples for consumers, so they must demonstrate proper accessible usage. + +### Required accessibility practices + +1. **Include descriptive labels**: If a component requires a label for accessibility (e.g., `label`, `aria-label`, slot content), every story must include it +2. **Use meaningful text content**: Avoid placeholder text like "Lorem ipsum" - use realistic, descriptive content +3. **Demonstrate proper ARIA usage**: Show correct ARIA attributes when applicable +4. **Never demonstrate inaccessible patterns**: Stories should not show examples that would fail accessibility audits + +### Common accessibility requirements by component type + +| Component type | Required accessibility | +| -------------- | ---------------------- | +| Progress indicators | `label` attribute describing what is loading | +| Buttons/actions | Visible text or `aria-label` for icon-only | +| Form fields | Associated `<label>` or `aria-label` | +| Status indicators | Text content describing the status | +| Images/icons | `alt` text or `aria-label` | +| Interactive elements | Keyboard accessibility, focus indicators | + +### Example: accessible story + +```typescript +// ✅ Good: Includes descriptive label +export const Sizes: Story = { + render: (args) => html` + ${template({ ...args, size: 's', label: 'Uploading file' })} + ${template({ ...args, size: 'm', label: 'Processing request' })} + ${template({ ...args, size: 'l', label: 'Loading dashboard' })} + `, + tags: ['options'], +}; + +// ❌ Bad: Missing required label +export const Sizes: Story = { + render: (args) => html` + ${template({ ...args, size: 's' })} + ${template({ ...args, size: 'm' })} + ${template({ ...args, size: 'l' })} + `, + tags: ['options'], +}; +``` + +## Story organization and tagging + +### Playground story + +Required first story after meta. Do NOT include JSDoc comment above Playground story. + +**Important**: Set the Playground args to the *simplest or most common use case** for the component, as this story is also used as the preview at the top of the documentation page. + +```typescript +export const Playground: Story = { + args: { + // Set to the default args or args for the most common use case - this appears as the docs page preview + }, + tags: ['autodocs', 'dev'], +}; +``` + +### Anatomy stories + +Stories demonstrating component structure. **Combine all slotted content combinations into a single Anatomy story** to make it easier for consumers to view all variations at once. + +```typescript +/** + * Description of the component's anatomy and key parts. + * Explain what makes up the component. + * + * Show all combinations of slotted content in a single story. + */ +export const Anatomy: Story = { + render: (args) => html` + ${template({ ...args, /* text only */ })} + ${template({ ...args, /* icon only */ })} + ${template({ ...args, /* text + icon */ })} + `, + tags: ['anatomy'], + args: {}, +}; +``` + +### Options stories + +Stories demonstrating variants, sizes, styles. **Consolidate related options into single stories** to make it easier for consumers to compare variations: + +- **Sizes**: Combine all sizes into a single `Sizes` story +- **Semantic variants**: Combine all semantic variants into a single `SemanticVariants` story +- **Non-semantic variants**: Combine all non-semantic variants into a single `NonSemanticVariants` story +- **Quiet/subtle/emphasized**: Combine into a single story if multiple apply +- **Outline**: Can be shown alongside variants or as a separate story +- **Static color**: Use the three-story pattern (see Static color pattern section) +- **Positioning**: Combine positioning options into a single story + +```typescript +/** + * Components come in [X] sizes to fit various contexts. + * Show all sizes in a single story for easy comparison. + */ +export const Sizes: Story = { + render: (args) => html` + ${template({ ...args, size: 's' })} + ${template({ ...args, size: 'm' })} + ${template({ ...args, size: 'l' })} + `, + tags: ['options'], +}; + +/** + * Semantic variants provide meaning through color. + * Show all semantic variants in a single story for easy comparison. + */ +export const SemanticVariants: Story = { + render: (args) => html` + ${template({ ...args, variant: 'positive' })} + ${template({ ...args, variant: 'informative' })} + ${template({ ...args, variant: 'negative' })} + ${template({ ...args, variant: 'notice' })} + ${template({ ...args, variant: 'neutral' })} + `, + tags: ['options'], +}; + +/** + * Non-semantic variants use color-coded categories. + * Show all non-semantic variants in a single story for easy comparison. + */ +export const NonSemanticVariants: Story = { + render: (args) => html` + ${template({ ...args, variant: 'seafoam' })} + ${template({ ...args, variant: 'indigo' })} + ${/* ... other colors */ ''} + `, + tags: ['options'], +}; +``` + +### States stories + +Stories demonstrating different states (if applicable). **Combine all states into a single States story** (or minimal stories when states are complex) to make it easier for consumers to compare: + +```typescript +/** + * Components can exist in various states. + * Show all states in a single story for easy comparison. + */ +export const States: Story = { + render: (args) => html` + ${template({ ...args, /* default */ })} + ${template({ ...args, selected: true })} + ${template({ ...args, disabled: true })} + ${template({ ...args, readonly: true })} + ${template({ ...args, invalid: true })} + `, + tags: ['states'], + args: {}, +}; +``` + +If a state requires more complex demonstration (e.g., indeterminate progress with animation), it may warrant a separate story: + +```typescript +/** + * Indeterminate state shows unknown progress. + */ +export const Indeterminate: Story = { + tags: ['states'], + args: { + indeterminate: true, + }, +}; +``` + +### Behaviors stories + +Stories demonstrating built-in functionality (if applicable). Order subsections as follows (skip inapplicable): + +- Automatic behaviors (text wrapping, truncation, interactivity) +- Methods +- Events + +```typescript +/** + * Description of this behavior. + */ +export const BehaviorName: Story = { + render: (args) => html` + ${template({ ...args /* behavior example */ })} + `, + tags: ['behaviors'], + args: {}, +}; +``` + +### Accessibility story + +Required accessibility demonstration: + +```typescript +/** + * ### Features + * + * The `<sp-component-name>` element implements several accessibility features: + * + * 1. **Feature name**: Description (e.g., keyboard navigation, ARIA states, roles, properties) + * 2. **Feature name**: Description + * + * ### Best practices + * + * - Best practice one + * - Best practice two + */ +export const Accessibility: Story = { + render: () => html` + ${/* accessibility examples */} + `, + tags: ['a11y'], +}; +``` + +## Tag usage requirements + +### Required tags + +- `'autodocs'` - Only on Playground story +- `'dev'` - Only on Playground story +- `'anatomy'` - For anatomy stories +- `'options'` - For variant, size, and style stories +- `'states'` - For state demonstration stories (if component has states) +- `'behaviors'` - For behavior stories (methods, events, automatic behaviors) +- `'a11y'` - For accessibility demonstration story + +**Note**: Installation documentation is written directly in usage.mdx, not as a tagged story. + +### Exclusion tags + +- `'!test'` - Exclude from test runs (e.g., complex static color stories) +- `'!dev'` - Exclude from dev Storybook + +### Migration tag + +- `'migrated'` - On the meta object to indicate refined format + +## JSDoc requirements + +### Above each story export + +Every story export must have a JSDoc comment explaining: + +- What it demonstrates +- Any important context or usage notes +- Best practices if relevant + +**Exception**: Do NOT add JSDoc comments above the Playground story. + +Use markdown formatting within JSDoc: + +- `**Bold**` for emphasis +- Bullet lists for multiple points +- Code formatting with backticks + +Example: + +```typescript +/** + * Semantic variants allow you to render the badge with a descriptive name that maps to a design-system-aligned color. + * + * Use these variants for the following statuses: + * - **Positive**: approved, complete, success, new, purchased, licensed + * - **Informative**: active, in use, live, published + * - **Negative**: error, alert, rejected, failed + */ +export const SemanticVariants: Story = { + // ... +}; +``` + +## Static color pattern + +For components with `static-color` attribute, implement the three-story pattern: + +1. **`StaticBlack`** - Individual story with `static-color="black"` (auto-background via `withStaticColorBackground`) +2. **`StaticWhite`** - Individual story with `static-color="white"` (auto-background via `withStaticColorBackground`) +3. **`StaticColors`** - Combined story showing both variants side-by-side (via `staticColorsDemo` decorator) + +### Individual static color stories + +The `withStaticColorBackground` decorator automatically detects the `static-color` arg and applies the appropriate gradient background: + +```typescript +// Individual color stories - JSDoc only on StaticBlack to introduce the pattern +/** + * When displaying over images or colored backgrounds, use the `static-color` attribute for better contrast, + * e.g. `static-color="white"` on a dark background or `static-color="black"` on a light background. + */ +export const StaticBlack: Story = { + args: { + 'static-color': 'black', + }, + render: (args) => html` + <p>Content above the component on a light background</p> + ${template({ ...args })} + <p>Content below the component</p> + `, + parameters: { + flexLayout: false, + styles: { + color: 'black', + }, + }, +}; + +export const StaticWhite: Story = { + args: { + 'static-color': 'white', + }, + render: (args) => html` + <p>Content above the component on a dark background</p> + ${template({ ...args })} + <p>Content below the component</p> + `, + parameters: { + flexLayout: false, + styles: { + color: 'white', + }, + }, +}; +``` + +### Combined static colors story + +The `StaticColors` story uses the `staticColorsDemo` decorator to display both variants side-by-side. Use the **simple pattern** (preferred) for most components, or the **contextual pattern** when additional descriptive content is needed. + +#### Simple pattern (preferred) + +Map over the static color values and use story-level args for common properties. The decorator automatically applies the appropriate gradient backgrounds: + +```typescript +/** + * When displaying over images or colored backgrounds, use the `static-color` attribute for better contrast, + * e.g. `static-color="white"` on a dark background or `static-color="black"` on a light background. + */ +export const StaticColors: Story = { + render: (args) => html` + ${['white', 'black'].map((color) => html`${template({ ...args, 'static-color': color })}`)} + `, + args: { + progress: 60, + label: 'Loading', + }, + tags: ['options', '!test'], + parameters: { + flexLayout: false, + staticColorsDemo: true, + }, +}; +``` + +#### Contextual pattern + +Use when components need additional descriptive content around them (e.g., dividers with surrounding text): + +```typescript +/** + * When displaying over images or colored backgrounds, use the `static-color` attribute for better contrast, + * e.g. `static-color="white"` on a dark background or `static-color="black"` on a light background. + */ +export const StaticColors: Story = { + render: (args) => html` + ${['white', 'black'].map( + (color) => html` + <div> + <h4>Dashboard settings</h4> + ${template({ ...args, 'static-color': color })} + <p>Configure your dashboard preferences and layout options.</p> + </div>` + )} + `, + args: { + size: 'm', + }, + parameters: { + flexLayout: false, + staticColorsDemo: true, + }, + tags: ['options', '!test'], +}; +``` + +### How the static color decorators work + +**`withStaticColorBackground`** (automatic): +- Detects `static-color` arg value ('white' or 'black') +- Applies the appropriate gradient background image automatically +- No configuration needed - works automatically when `static-color` arg is set + +**`staticColorsDemo`** (opt-in): +- Enable with `parameters.staticColorsDemo = true` +- Wraps story content in a flex container with two background zones +- **First child**: Gets a dark gradient background (for `static-color="white"` components) +- **Last child**: Gets a light gradient background (for `static-color="black"` components) +- Uses CSS custom properties: `--spectrum-examples-gradient-static-white` and `--spectrum-examples-gradient-static-black` + +## Decorators and layout + +Three global decorators are available for story layout: + +1. **`withFlexLayout`** - Provides consistent flex container spacing (enabled by default) +2. **`withStaticColorBackground`** - Automatically applies gradient background when `static-color` arg is set (automatic) +3. **`staticColors`** - Displays static color variants side-by-side with appropriate backgrounds (opt-in via `staticColorsDemo: true`) + +### Using the flex-layout decorator + +The `withFlexLayout` decorator is applied globally and provides consistent spacing for stories. By default, it applies: + +```typescript +{ display: 'flex', gap: '24px', alignItems: 'center' } +``` + +### Customizing layout with parameters.styles + +For stories that need custom layout (e.g., wrapping, max-width constraints), use `parameters.styles`: + +```typescript +// Define reusable parameters at the top of your stories file +const parameters = { + flexLayout: true, + styles: { + display: 'flex', + gap: 'var(--spectrum-spacing-200)', + 'flex-wrap': 'wrap', + 'justify-content': 'center', + 'max-inline-size': '80ch', + }, +}; + +// Apply to individual stories +export const Sizes: Story = { + render: () => html` + ${Component.VALID_SIZES.map((size) => html` + <swc-component size="${size}">${sizeLabel(size)}</swc-component> + `)} + `, + parameters: parameters, + tags: ['options'], +}; +``` + +### Disabling flex layout + +To disable the flex layout decorator for a specific story: + +```typescript +export const SingleComponent: Story = { + parameters: { + flexLayout: false, + }, +}; +``` + +### Using the staticColorsDemo decorator + +The `staticColorsDemo` decorator is opt-in and displays static color variants side-by-side with appropriate gradient backgrounds. Enable it by setting `parameters.staticColorsDemo = true`. + +**Important**: When using `staticColorsDemo`, set `flexLayout: false` to avoid conflicting layouts. + +```typescript +export const StaticColors: Story = { + render: () => html` + <div> + <!-- Content for static-color="white" (displayed on dark background) --> + </div> + <div> + <!-- Content for static-color="black" (displayed on light background) --> + </div> + `, + parameters: { + flexLayout: false, + staticColorsDemo: true, + }, + tags: ['options', '!test'], +}; +``` + +## Usage.mdx requirements + +### Minimal structure + +Keep usage.mdx files minimal and use `<SpectrumStories />` component: + +```mdx +import { SpectrumStories } from '../../../.storybook/blocks'; + +## Installation + +Installation content is written directly in MDX (not a story). Include: +- Package name and npm install command +- Import statements +- Basic usage example + +## Anatomy + +<SpectrumStories tag="anatomy" hideTitle /> + +## Options + +<SpectrumStories tag="options" /> + +## States + +<SpectrumStories tag="states" /> + +## Behaviors + +<SpectrumStories tag="behaviors" /> + +## Accessibility + +<SpectrumStories tag="a11y" hideTitle /> +``` + +### Section rules + +- Installation content is written directly in MDX (not as a story) +- Use `hideTitle` for Anatomy and Accessibility sections +- Do NOT use `hideTitle` for Options, States, and Behaviors sections +- Only include sections that have corresponding stories (except Installation) +- Use consistent section heading capitalization (sentence case) +- Follow the prescribed section order: Installation → Anatomy → Options → States → Behaviors → Accessibility + +## Common violations + +### ❌ Don't + +- Use old Canvas/Story imports from '@storybook/addon-docs/blocks' +- Write verbose examples directly in usage.mdx +- Forget JSDoc comments on story exports (except Playground) +- Add JSDoc comment to Playground story +- Use inconsistent section separators +- Tag stories incorrectly (e.g., 'usage' instead of 'options') +- Forget to include subtitle in meta parameters +- Use 'usage' tag (deprecated in refined format) +- Omit required accessibility attributes (labels, aria-label, etc.) +- Use placeholder text instead of meaningful, descriptive content +- Demonstrate inaccessible patterns in story examples + +### ✅ Do + +- Use SpectrumStories component in usage.mdx +- Include comprehensive JSDoc for each story (except Playground) +- Keep Playground story without JSDoc comment +- Use consistent visual separators +- Tag stories with proper semantic tags +- Include subtitle in meta.parameters.docs +- Keep usage.mdx minimal and maintainable +- Use 'anatomy', 'options', 'states', 'behaviors', 'a11y' tags (Installation is MDX-only, no tag) +- Include all required accessibility attributes in every story (labels, aria-label, etc.) +- Use meaningful, descriptive text content that reflects real-world usage +- Demonstrate accessible patterns that consumers should follow + +## Checklist for new/migrated stories + +- [ ] Copyright header present (2025 year) +- [ ] All required sections with visual separators +- [ ] Meta has title, component, args, argTypes, render, parameters.docs.subtitle, tags +- [ ] Playground story with 'autodocs' and 'dev' tags, set to default or most common use case (no JSDoc comment) +- [ ] Installation section written directly in usage.mdx (not a story) +- [ ] Anatomy story combining all slotted content variations with 'anatomy' tag and JSDoc +- [ ] Sizes story combining all sizes with 'options' tag and JSDoc +- [ ] SemanticVariants story combining all semantic variants with 'options' tag and JSDoc (if applicable) +- [ ] NonSemanticVariants story combining all non-semantic variants with 'options' tag and JSDoc (if applicable) +- [ ] States story combining all states with 'states' tag and JSDoc (if applicable) +- [ ] Behaviors stories with 'behaviors' tag and JSDoc (if applicable; subsections: automatic behaviors, methods, events) +- [ ] Accessibility story with 'a11y' tag and comprehensive JSDoc (subsections: features, best practices) +- [ ] All story exports have JSDoc comments (except Playground) +- [ ] Playground story does NOT have JSDoc comment +- [ ] Usage.mdx uses SpectrumStories component +- [ ] Usage.mdx only includes relevant sections in correct order +- [ ] Static color pattern implemented correctly using `staticColorsDemo` decorator (if applicable) +- [ ] Custom layout uses `parameters.styles` with flex-layout decorator +- [ ] Static color stories use `flexLayout: false` with `staticColorsDemo: true` +- [ ] **All stories include required accessibility attributes** (labels, aria-label, text content) +- [ ] **All stories use meaningful, descriptive content** (not placeholder text) +- [ ] **No stories demonstrate inaccessible patterns** + +## Reference implementation + +See [`progress-circle`](/Users/ceickhoff/Desktop/Code/spectrum-web-components-2/2nd-gen/packages/swc/components/progress-circle/stories) for the canonical refined format implementation. diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 9b01c8e2744..2906306e0bc 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,3 +1,6 @@ { - "recommendations": ["runem.lit-plugin"] + "recommendations": [ + "runem.lit-plugin", + "bierner.jsdoc-markdown-highlighting" + ] } diff --git a/.vscode/local-extensions/README.md b/.vscode/local-extensions/README.md new file mode 100644 index 00000000000..53f7fbb9d9b --- /dev/null +++ b/.vscode/local-extensions/README.md @@ -0,0 +1,9 @@ +# Installing local extensions in Cursor + +The extensions in this directory are not available in Cursor but are in VSCode. The `vsix` file can be uploaded to Cursor locally to install the extension for usage. + +The following steps will get you started: + +1. Go to cursor, hit Cmd + Shift + P +2. Search for “Extensions: Install from VSIX…” +3. Select the extension file from this directory and download diff --git a/.vscode/local-extensions/bierner.jsdoc-markdown-highlighting-0.0.1.vsix b/.vscode/local-extensions/bierner.jsdoc-markdown-highlighting-0.0.1.vsix new file mode 100644 index 0000000000000000000000000000000000000000..e8eb4cac7c45cbb93d67e3233cc752acc94261d3 GIT binary patch literal 26689 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 literal 0 HcmV?d00001 diff --git a/2nd-gen/packages/core/components/progress-circle/ProgressCircle.base.ts b/2nd-gen/packages/core/components/progress-circle/ProgressCircle.base.ts index a56e68518e8..1777635784f 100644 --- a/2nd-gen/packages/core/components/progress-circle/ProgressCircle.base.ts +++ b/2nd-gen/packages/core/components/progress-circle/ProgressCircle.base.ts @@ -90,6 +90,7 @@ export abstract class ProgressCircleBase extends SizedMixin(SpectrumElement, { * Accessible label for the progress circle. * * Used to provide context about what is loading or progressing. + * @required for accessibility */ @property({ type: String }) public label = ''; diff --git a/2nd-gen/packages/core/shared/base/version.ts b/2nd-gen/packages/core/shared/base/version.ts index cb9e28ff658..2177cdd7401 100644 --- a/2nd-gen/packages/core/shared/base/version.ts +++ b/2nd-gen/packages/core/shared/base/version.ts @@ -9,6 +9,5 @@ * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ - // Generated by genversion. export const version = '1.10.0'; diff --git a/2nd-gen/packages/swc/.storybook/DocumentTemplate.mdx b/2nd-gen/packages/swc/.storybook/DocumentTemplate.mdx index 383a8b82650..f5692e38167 100644 --- a/2nd-gen/packages/swc/.storybook/DocumentTemplate.mdx +++ b/2nd-gen/packages/swc/.storybook/DocumentTemplate.mdx @@ -7,25 +7,56 @@ import { ArgTypes, Description, Subtitle, + useOf, } from '@storybook/addon-docs/blocks'; -import { SpectrumDocs } from './blocks/SpectrumDocs'; -import { SpectrumStories } from './blocks/SpectrumStories'; +import { + GettingStarted, + SpectrumDocs, + SpectrumStories, + StaticPrimaryStory, +} from './blocks'; import '@spectrum-web-components/tabs/sp-tabs.js'; import '@spectrum-web-components/tabs/sp-tab.js'; import '@spectrum-web-components/tabs/sp-tab-panel.js'; +export const checkIsSingleStory = () => { + const resolvedOf = useOf('meta', ['meta']); + const { stories } = resolvedOf.csfFile; + const visibleStories = Object.values(stories).filter((story) => + story.tags?.includes('autodocs' || 'dev') + ); + return visibleStories.length === 1; +}; + +export const SingleStoryDescription = () => { + const isSingleStory = checkIsSingleStory(); + + return (isSingleStory ? <Description of="story" /> : null) + +} + +export const AdvancedExamplesStories = () => { + const isSingleStory = checkIsSingleStory(); + + return (isSingleStory ? null : <Stories includePrimary={false} />) + +} + <Meta isTemplate /> <Title /> <Subtitle /> -<Primary /> - +<Description /> +<SingleStoryDescription /> +<StaticPrimaryStory /> +<GettingStarted /> <SpectrumDocs tag="usage" /> ## API <Primary /> <Controls /> +<AdvancedExamplesStories /> ## Feedback diff --git a/2nd-gen/packages/swc/.storybook/assets/404.html b/2nd-gen/packages/swc/.storybook/assets/404.html new file mode 100644 index 00000000000..a8b801668d4 --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/assets/404.html @@ -0,0 +1,178 @@ +<!doctype html> +<html lang="en"> + <head> + <meta charset="utf-8" /> + <title>Page not found + + + + + + + + + + +
+ +
+
+

404: Page not found

+
+ An abstract illustrated image with a whimsical color palette +

It's not you. It's us.

+

+ We've made a lot of improvements to the Spectrum CSS + documentation site, including consolidating all of the + documentation and moving it to a single location within + Storybook. +

+

+ If you're looking for information on Spectrum CSS + components, let's get you back to + our landing page. From there, experiment with all of our components to your + heart's content! +

+
+
+ + diff --git a/2nd-gen/packages/swc/.storybook/assets/favicon.png b/2nd-gen/packages/swc/.storybook/assets/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..988b1143327f6c5c3916d78902121a4641b0e47a GIT binary patch literal 551 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!j01c^T>t<7pGP9#IP)(Gs9m5W z$S;^dK*7KvAfcdP!h#J4EV{Y6NsvN4=Ry>Y;t?VGj_>=QN z%0oLj1}^3)77KiN47M69_%!L}p@t)jnp_ppp}+Z#oSbFeQ@F zPw0y)H{;rao(sAeeAax}B*GNb{CC&7?CDMpnG-6q;>8{qbfpD5Ib?j$yuGZY;lhF$ zO{QEM{(lj0I&e*4_r<-;A=@hItPiZ&vbnWk<-u21E7&7kmP{4cP`BwtnB~`oS6l9H z7k$M4VCkz^PR7L{tEv-a%^eE$9ampCSgLq^!$h?L-g5_TZ1~H#+p*apTh2=jPV#qqm>oz1#XtnTI61@)A?Nb_FsE9<$+MtlprS>iMp! z!ujIfoxP&%Vii*F%CfT~m>X`2CAn68vyydNre9J0pJCDDT-_7DitK?=$KdJe=d#Wz Gp$P!xa_Z0k literal 0 HcmV?d00001 diff --git a/2nd-gen/packages/swc/.storybook/assets/images/adobe_logo.svg b/2nd-gen/packages/swc/.storybook/assets/images/adobe_logo.svg new file mode 100644 index 00000000000..bde5a6cd3f7 --- /dev/null +++ b/2nd-gen/packages/swc/.storybook/assets/images/adobe_logo.svg @@ -0,0 +1,5 @@ + diff --git a/2nd-gen/packages/swc/.storybook/assets/images/example-ava.png b/2nd-gen/packages/swc/.storybook/assets/images/example-ava.png new file mode 100644 index 0000000000000000000000000000000000000000..d77edcca8db907341b90dac3da7ee66fcc32ceeb GIT binary patch literal 9444 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
  • vB_y>xxA+RB$!S~trYZ8nmsw`&5Sd_>* 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