@ds-mo/ui 12.1.0 → 12.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -3
- package/dist/.build-stamp +1 -1
- package/dist/agent-patterns.json +8 -7
- package/dist/agent.json +837 -66
- package/dist/angular/ds-avatar.d.ts +1 -1
- package/dist/angular/ds-avatar.js +3 -3
- package/dist/angular/ds-bar-title.d.ts +7 -1
- package/dist/angular/ds-bar-title.js +7 -4
- package/dist/angular/ds-bar-workflow.d.ts +28 -0
- package/dist/angular/ds-bar-workflow.js +48 -0
- package/dist/angular/ds-breadcrumb.d.ts +19 -0
- package/dist/angular/ds-breadcrumb.js +42 -0
- package/dist/angular/ds-card-data-viz-bar.d.ts +18 -0
- package/dist/angular/ds-card-data-viz-bar.js +42 -0
- package/dist/angular/ds-card-data-viz-line.d.ts +18 -0
- package/dist/angular/ds-card-data-viz-line.js +42 -0
- package/dist/angular/ds-chart-bar-stacked.d.ts +12 -0
- package/dist/angular/ds-chart-bar-stacked.js +38 -0
- package/dist/angular/ds-chart-legend.d.ts +1 -1
- package/dist/angular/ds-chart-legend.js +3 -3
- package/dist/angular/ds-conversation-list.d.ts +1 -1
- package/dist/angular/ds-conversation-list.js +4 -3
- package/dist/angular/ds-scroll-overlay.d.ts +19 -0
- package/dist/angular/ds-scroll-overlay.js +43 -0
- package/dist/angular/ds-shell-page.d.ts +1 -1
- package/dist/angular/ds-shell-page.js +3 -3
- package/dist/angular/index.d.ts +1 -1
- package/dist/angular/index.js +6 -0
- package/dist/angular/proxies.d.ts +6 -0
- package/dist/angular/proxies.js +6 -0
- package/dist/components/ds-agent-activity.js +1 -1
- package/dist/components/ds-agent-response.js +1 -1
- package/dist/components/ds-agent-source-list.js +1 -1
- package/dist/components/ds-agent-tool-call.js +1 -1
- package/dist/components/ds-attachment-list.js +1 -1
- package/dist/components/ds-avatar.js +1 -1
- package/dist/components/ds-avatar.js.map +1 -1
- package/dist/components/ds-badge.js +1 -1
- package/dist/components/ds-bar-nav.js +1 -1
- package/dist/components/ds-bar-nav.js.map +1 -1
- package/dist/components/ds-bar-title.js +1 -1
- package/dist/components/ds-bar-title.js.map +1 -1
- package/dist/components/ds-bar-workflow.d.ts +11 -0
- package/dist/components/ds-bar-workflow.js +2 -0
- package/dist/components/ds-bar-workflow.js.map +1 -0
- package/dist/components/ds-breadcrumb.d.ts +11 -0
- package/dist/components/ds-breadcrumb.js +2 -0
- package/dist/components/ds-breadcrumb.js.map +1 -0
- package/dist/components/ds-button-filled.js +1 -1
- package/dist/components/ds-button-unfilled.js +1 -1
- package/dist/components/ds-card-data-viz-bar.d.ts +11 -0
- package/dist/components/ds-card-data-viz-bar.js +2 -0
- package/dist/components/ds-card-data-viz-bar.js.map +1 -0
- package/dist/components/ds-card-data-viz-donut.js +1 -1
- package/dist/components/ds-card-data-viz-line.d.ts +11 -0
- package/dist/components/ds-card-data-viz-line.js +2 -0
- package/dist/components/ds-card-data-viz-line.js.map +1 -0
- package/dist/components/ds-card-setting.js +1 -1
- package/dist/components/ds-card-shell-data-viz.js +1 -1
- package/dist/components/ds-chart-bar-stacked.d.ts +11 -0
- package/dist/components/ds-chart-bar-stacked.js +2 -0
- package/dist/components/ds-chart-bar-stacked.js.map +1 -0
- package/dist/components/ds-chart-bar.js +1 -1
- package/dist/components/ds-chart-bar.js.map +1 -1
- package/dist/components/ds-chart-donut.js +1 -1
- package/dist/components/ds-chart-legend.js +1 -1
- package/dist/components/ds-chart-legend.js.map +1 -1
- package/dist/components/ds-chart-line.js +1 -1
- package/dist/components/ds-chart-line.js.map +1 -1
- package/dist/components/ds-checkbox.js +1 -1
- package/dist/components/ds-chip.js +1 -1
- package/dist/components/ds-chip.js.map +1 -1
- package/dist/components/ds-code-block.js +1 -1
- package/dist/components/ds-conversation-list-item.js +1 -1
- package/dist/components/ds-conversation-list-item.js.map +1 -1
- package/dist/components/ds-conversation-list-section.js +1 -1
- package/dist/components/ds-conversation-list-section.js.map +1 -1
- package/dist/components/ds-conversation-list.js +1 -1
- package/dist/components/ds-conversation-list.js.map +1 -1
- package/dist/components/ds-divider.js +1 -1
- package/dist/components/ds-empty-state.js +1 -1
- package/dist/components/ds-field.js +1 -1
- package/dist/components/ds-input.js +1 -1
- package/dist/components/ds-input.js.map +1 -1
- package/dist/components/ds-markdown.js +1 -1
- package/dist/components/ds-menu.js +1 -1
- package/dist/components/ds-message-bubble.js +1 -1
- package/dist/components/ds-message-bubble.js.map +1 -1
- package/dist/components/ds-message-composer.js +1 -1
- package/dist/components/ds-message-scroller.js +1 -1
- package/dist/components/ds-message-scroller.js.map +1 -1
- package/dist/components/ds-message.js +1 -1
- package/dist/components/ds-modal.js +1 -1
- package/dist/components/ds-panel-nav.js +1 -1
- package/dist/components/ds-panel-sub-nav.js +1 -1
- package/dist/components/ds-panel-sub-nav.js.map +1 -1
- package/dist/components/ds-panel-tool-header.js +1 -1
- package/dist/components/ds-panel-tool-search.js +1 -1
- package/dist/components/ds-panel-tools.js +1 -1
- package/dist/components/ds-radio.js +1 -1
- package/dist/components/ds-radio.js.map +1 -1
- package/dist/components/ds-scroll-overlay.d.ts +11 -0
- package/dist/components/ds-scroll-overlay.js +2 -0
- package/dist/components/ds-scroll-overlay.js.map +1 -0
- package/dist/components/ds-select-multi.js +1 -1
- package/dist/components/ds-select-multi.js.map +1 -1
- package/dist/components/ds-select.js +1 -1
- package/dist/components/ds-select.js.map +1 -1
- package/dist/components/ds-shell-app.js +1 -1
- package/dist/components/ds-shell-gradient-picker.js +1 -1
- package/dist/components/ds-shell-gradient-swatch.js +1 -1
- package/dist/components/ds-shell-gradient-swatch.js.map +1 -1
- package/dist/components/ds-shell-page.js +1 -1
- package/dist/components/ds-shell-page.js.map +1 -1
- package/dist/components/ds-skeleton.js +1 -1
- package/dist/components/ds-slider.js +1 -1
- package/dist/components/ds-slider.js.map +1 -1
- package/dist/components/ds-swatch-picker.js +1 -1
- package/dist/components/ds-switch.js +1 -1
- package/dist/components/ds-tab-group.js +1 -1
- package/dist/components/ds-tab-group.js.map +1 -1
- package/dist/components/ds-tag.js +1 -1
- package/dist/components/ds-tag.js.map +1 -1
- package/dist/components/ds-text.js +1 -1
- package/dist/components/ds-toast.js +1 -1
- package/dist/components/ds-tooltip-data-viz.js +1 -1
- package/dist/components/ds-tooltip.js +1 -1
- package/dist/components/ds-typing-indicator.js +1 -1
- package/dist/components/ds-typing-indicator.js.map +1 -1
- package/dist/components/{p-B9jvSGid.js → p-9dQQSgwT.js} +2 -2
- package/dist/components/p-B3rbhRAk.js +2 -0
- package/dist/components/p-B3rbhRAk.js.map +1 -0
- package/dist/components/{p-BWUTr_XN.js → p-BJMRBHKW.js} +2 -2
- package/dist/components/p-BJMRBHKW.js.map +1 -0
- package/dist/components/p-BVV_rlIP.js +2 -0
- package/dist/components/p-BVV_rlIP.js.map +1 -0
- package/dist/components/p-BhxwpOH8.js +2 -0
- package/dist/components/{p-DpyTrZa2.js.map → p-BhxwpOH8.js.map} +1 -1
- package/dist/components/p-Bi_bxbih.js +2 -0
- package/dist/components/{p-Dqwcw1-m.js.map → p-Bi_bxbih.js.map} +1 -1
- package/dist/components/p-BtEjlcB9.js +2 -0
- package/dist/components/{p-DABj3qTX.js.map → p-BtEjlcB9.js.map} +1 -1
- package/dist/components/{p-Bs6SS34m.js → p-BwGnhInj.js} +2 -2
- package/dist/components/p-BwGnhInj.js.map +1 -0
- package/dist/components/p-C0NPJ0h2.js +2 -0
- package/dist/components/p-C0NPJ0h2.js.map +1 -0
- package/dist/components/{p-BkwBtZs3.js → p-C7bZ-jiU.js} +2 -2
- package/dist/components/p-CH3w-P2H.js +2 -0
- package/dist/components/p-CH3w-P2H.js.map +1 -0
- package/dist/components/{p-DxeHimqk.js → p-CH6cNXXF.js} +2 -2
- package/dist/components/p-CWlh7HAg.js +2 -0
- package/dist/components/p-CWlh7HAg.js.map +1 -0
- package/dist/components/p-CY19gMiz.js +2 -0
- package/dist/components/p-CY19gMiz.js.map +1 -0
- package/dist/components/p-C_ewSXTT.js +2 -0
- package/dist/components/p-C_ewSXTT.js.map +1 -0
- package/dist/components/{p-tDXHTAJh.js → p-Ce52yVXF.js} +2 -2
- package/dist/components/p-CoYFJD-w.js +2 -0
- package/dist/components/{p-webARv8d.js.map → p-CoYFJD-w.js.map} +1 -1
- package/dist/components/{p-BzsITTZa.js → p-Cuw2Lo2g.js} +2 -2
- package/dist/components/p-CydY-v7X.js +2 -0
- package/dist/components/p-CydY-v7X.js.map +1 -0
- package/dist/components/{p-LFGbdi7Y.js → p-D-xttdpn.js} +2 -2
- package/dist/components/{p-DfIch2Dk.js → p-D3DYxbC5.js} +2 -2
- package/dist/components/{p-CR7yMitN.js → p-DC7yOUQx.js} +2 -2
- package/dist/components/{p-liMPkhUP.js → p-DSa0Hnd3.js} +2 -2
- package/dist/components/p-DXewjzkM.js +2 -0
- package/dist/components/p-DXewjzkM.js.map +1 -0
- package/dist/components/p-DYqReipj.js +2 -0
- package/dist/components/{p-Dy_sZ-dI.js.map → p-DYqReipj.js.map} +1 -1
- package/dist/components/p-DbpfpeQT.js +2 -0
- package/dist/components/p-DbpfpeQT.js.map +1 -0
- package/dist/components/{p-DszI94sZ.js → p-DjPZxzIG.js} +2 -2
- package/dist/components/{p-DszI94sZ.js.map → p-DjPZxzIG.js.map} +1 -1
- package/dist/components/{p-CTV_QWC5.js → p-J6xK6Ihq.js} +2 -2
- package/dist/components/{p-Dfxnxx7L.js → p-jCWtxthA.js} +2 -2
- package/dist/docs/components.json +2137 -743
- package/dist/lib/utils/anchored-popup.d.ts +5 -1
- package/dist/lib/utils/index.js +3 -1
- package/dist/lib/utils/index.js.map +2 -2
- package/dist/mcp/cli.js +142 -18
- package/dist/mcp-data/registry/agent-response.json +9 -4
- package/dist/mcp-data/registry/agent-source-list.json +1 -1
- package/dist/mcp-data/registry/avatar.json +26 -7
- package/dist/mcp-data/registry/bar-title.json +76 -37
- package/dist/mcp-data/registry/bar-workflow.json +368 -0
- package/dist/mcp-data/registry/breadcrumb.json +205 -0
- package/dist/mcp-data/registry/button-filled.json +1 -1
- package/dist/mcp-data/registry/button-unfilled.json +1 -1
- package/dist/mcp-data/registry/card-data-viz-bar.json +212 -0
- package/dist/mcp-data/registry/card-data-viz-line.json +206 -0
- package/dist/mcp-data/registry/card-shell-data-viz.json +7 -0
- package/dist/mcp-data/registry/chart-bar-stacked.json +225 -0
- package/dist/mcp-data/registry/chart-bar.json +9 -2
- package/dist/mcp-data/registry/chart-legend.json +29 -3
- package/dist/mcp-data/registry/chart-line.json +4 -2
- package/dist/mcp-data/registry/checkbox.json +1 -1
- package/dist/mcp-data/registry/conversation-list-item.json +2 -2
- package/dist/mcp-data/registry/conversation-list-section.json +2 -2
- package/dist/mcp-data/registry/conversation-list.json +36 -9
- package/dist/mcp-data/registry/markdown.json +15 -10
- package/dist/mcp-data/registry/menu.json +9 -7
- package/dist/mcp-data/registry/message-scroller.json +6 -4
- package/dist/mcp-data/registry/message.json +3 -2
- package/dist/mcp-data/registry/panel-tool-search.json +1 -1
- package/dist/mcp-data/registry/registry.json +863 -74
- package/dist/mcp-data/registry/scroll-overlay.json +183 -0
- package/dist/mcp-data/registry/shell-gradient-swatch.json +1 -1
- package/dist/mcp-data/registry/shell-page.json +40 -19
- package/dist/mcp-data/registry/slider.json +1 -1
- package/dist/mcp-data/registry/switch.json +1 -1
- package/dist/mcp-data/registry/tab-group.json +1 -1
- package/dist/mcp-data/registry/text.json +1 -1
- package/dist/mcp-data/registry/typing-indicator.json +7 -7
- package/dist/react/components.d.ts +6 -0
- package/dist/react/components.js +6 -0
- package/dist/react/ds-bar-title.d.ts +2 -1
- package/dist/react/ds-bar-title.js +1 -0
- package/dist/react/ds-bar-workflow.d.ts +14 -0
- package/dist/react/ds-bar-workflow.js +16 -0
- package/dist/react/ds-breadcrumb.d.ts +12 -0
- package/dist/react/ds-breadcrumb.js +12 -0
- package/dist/react/ds-card-data-viz-bar.d.ts +12 -0
- package/dist/react/ds-card-data-viz-bar.js +12 -0
- package/dist/react/ds-card-data-viz-line.d.ts +12 -0
- package/dist/react/ds-card-data-viz-line.js +12 -0
- package/dist/react/ds-chart-bar-stacked.d.ts +9 -0
- package/dist/react/ds-chart-bar-stacked.js +12 -0
- package/dist/react/ds-scroll-overlay.d.ts +12 -0
- package/dist/react/ds-scroll-overlay.js +12 -0
- package/dist/styles/prose.css +215 -0
- package/dist/types/components/Avatar/Avatar.d.ts +4 -1
- package/dist/types/components/BarTitle/BarTitle.d.ts +14 -5
- package/dist/types/components/BarTitle/bar-title-types.d.ts +0 -1
- package/dist/types/components/BarWorkflow/BarWorkflow.d.ts +37 -0
- package/dist/types/components/BarWorkflow/bar-workflow-types.d.ts +12 -0
- package/dist/types/components/Breadcrumb/Breadcrumb.d.ts +31 -0
- package/dist/types/components/Breadcrumb/breadcrumb-types.d.ts +17 -0
- package/dist/types/components/CardDataVizBar/CardDataVizBar.d.ts +24 -0
- package/dist/types/components/CardDataVizBar/index.d.ts +2 -0
- package/dist/types/components/CardDataVizLine/CardDataVizLine.d.ts +24 -0
- package/dist/types/components/CardDataVizLine/index.d.ts +2 -0
- package/dist/types/components/ChartBarStacked/ChartBarStacked.d.ts +15 -0
- package/dist/types/components/ChartBarStacked/index.d.ts +3 -0
- package/dist/types/components/ChartLegend/ChartLegend.d.ts +3 -0
- package/dist/types/components/ConversationList/ConversationList.d.ts +12 -0
- package/dist/types/components/Menu/Menu.d.ts +1 -2
- package/dist/types/components/MessageScroller/MessageScroller.d.ts +1 -6
- package/dist/types/components/ScrollOverlay/ScrollOverlay.d.ts +28 -0
- package/dist/types/components/ShellPage/ShellPage.d.ts +19 -7
- package/dist/types/components/ShellPage/shell-page-responsive.d.ts +0 -8
- package/dist/types/components/TypingIndicator/TypingIndicator.d.ts +1 -1
- package/dist/types/components.d.ts +572 -26
- package/dist/types/stories/isolated-overlay-docs.d.ts +13 -0
- package/dist/types/utils/anchored-popup.d.ts +5 -1
- package/dist/types/utils/scroll-overlay-controller.d.ts +35 -0
- package/package.json +4 -3
- package/dist/components/p-BWUTr_XN.js.map +0 -1
- package/dist/components/p-BfEjWe8U.js +0 -2
- package/dist/components/p-BfEjWe8U.js.map +0 -1
- package/dist/components/p-Bs6SS34m.js.map +0 -1
- package/dist/components/p-C3Zfn7hz.js +0 -2
- package/dist/components/p-C3Zfn7hz.js.map +0 -1
- package/dist/components/p-CUik7PCi.js +0 -2
- package/dist/components/p-CUik7PCi.js.map +0 -1
- package/dist/components/p-CzBnvtcz.js +0 -2
- package/dist/components/p-CzBnvtcz.js.map +0 -1
- package/dist/components/p-DABj3qTX.js +0 -2
- package/dist/components/p-DpyTrZa2.js +0 -2
- package/dist/components/p-Dqwcw1-m.js +0 -2
- package/dist/components/p-Dy3Skua8.js +0 -2
- package/dist/components/p-Dy3Skua8.js.map +0 -1
- package/dist/components/p-Dy_sZ-dI.js +0 -2
- package/dist/components/p-l6PmnW_P.js +0 -2
- package/dist/components/p-l6PmnW_P.js.map +0 -1
- package/dist/components/p-webARv8d.js +0 -2
- /package/dist/components/{p-B9jvSGid.js.map → p-9dQQSgwT.js.map} +0 -0
- /package/dist/components/{p-BkwBtZs3.js.map → p-C7bZ-jiU.js.map} +0 -0
- /package/dist/components/{p-DxeHimqk.js.map → p-CH6cNXXF.js.map} +0 -0
- /package/dist/components/{p-tDXHTAJh.js.map → p-Ce52yVXF.js.map} +0 -0
- /package/dist/components/{p-BzsITTZa.js.map → p-Cuw2Lo2g.js.map} +0 -0
- /package/dist/components/{p-LFGbdi7Y.js.map → p-D-xttdpn.js.map} +0 -0
- /package/dist/components/{p-DfIch2Dk.js.map → p-D3DYxbC5.js.map} +0 -0
- /package/dist/components/{p-CR7yMitN.js.map → p-DC7yOUQx.js.map} +0 -0
- /package/dist/components/{p-liMPkhUP.js.map → p-DSa0Hnd3.js.map} +0 -0
- /package/dist/components/{p-CTV_QWC5.js.map → p-J6xK6Ihq.js.map} +0 -0
- /package/dist/components/{p-Dfxnxx7L.js.map → p-jCWtxthA.js.map} +0 -0
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
3
|
+
"name": "bar-workflow",
|
|
4
|
+
"title": "BarWorkflow",
|
|
5
|
+
"description": "Compact bold-brand create/edit workflow chrome with Exit, controlled previous and next step navigation, and a final Save or Submit action.",
|
|
6
|
+
"type": "registry:ui",
|
|
7
|
+
"meta": {
|
|
8
|
+
"library": "@ds-mo/ui",
|
|
9
|
+
"distribution": "npm",
|
|
10
|
+
"storybook": "https://zainadeel.github.io/compomo/?path=/story/bar-workflow",
|
|
11
|
+
"source": "src/wc/components/BarWorkflow/BarWorkflow.tsx",
|
|
12
|
+
"intentStatus": "complete",
|
|
13
|
+
"intent": {
|
|
14
|
+
"audience": "general",
|
|
15
|
+
"status": "stable",
|
|
16
|
+
"summary": "Compact bold-brand create/edit workflow chrome with Exit, controlled previous and next step navigation, and a final Save or Submit action.",
|
|
17
|
+
"useWhen": [
|
|
18
|
+
"A create or edit flow needs persistent page-level Exit and step navigation.",
|
|
19
|
+
"A single-step form needs the same compact workflow chrome and final Save or Submit action.",
|
|
20
|
+
"Next or Submit must remain visible while the application owns validation and the current step."
|
|
21
|
+
],
|
|
22
|
+
"avoidWhen": [
|
|
23
|
+
"The header identifies a routed page, list, or detail view; use BarTitle instead.",
|
|
24
|
+
"The steps must be visibly enumerated or expose progress; BarWorkflow uses steps only to resolve its navigation controls.",
|
|
25
|
+
"The header belongs to a PanelTools drawer or fullscreen pane; use PanelToolHeader through PanelTools instead.",
|
|
26
|
+
"The interaction is a local wizard inside page content rather than page-level workflow chrome."
|
|
27
|
+
],
|
|
28
|
+
"alternatives": [
|
|
29
|
+
{
|
|
30
|
+
"when": "A routed page needs responsive title, section, Back, and page-action presentations.",
|
|
31
|
+
"component": "component:ds-bar-title",
|
|
32
|
+
"reason": "BarTitle owns page identity and capacity variants rather than workflow progression."
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"when": "The workflow belongs to a tool drawer or fullscreen tool pane.",
|
|
36
|
+
"component": "component:ds-panel-tool-header",
|
|
37
|
+
"reason": "PanelToolHeader owns tool-pane navigation and actions within PanelTools."
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
"commonlyComposedWith": [
|
|
41
|
+
"component:ds-shell-page",
|
|
42
|
+
"component:ds-button-filled",
|
|
43
|
+
"component:ds-button-unfilled",
|
|
44
|
+
"component:ds-text",
|
|
45
|
+
"component:ds-tooltip"
|
|
46
|
+
],
|
|
47
|
+
"patterns": [],
|
|
48
|
+
"accessibility": [
|
|
49
|
+
"Provide one concise workflow heading; BarWorkflow renders exactly one h1 and appends the controlled current-step count as heading · X/N only for multi-step workflows.",
|
|
50
|
+
"Provide a workflow-specific Exit accessible name that describes the consequence or destination.",
|
|
51
|
+
"Give every step a stable id and concise label even though step labels are not rendered as visible progress.",
|
|
52
|
+
"Previous is omitted on the first step; it appears from step two onward. Next remains visible on intermediate steps and becomes the final labeled Check action on the last step.",
|
|
53
|
+
"Use submitAction.type=submit inside a form so the final action preserves native submission semantics."
|
|
54
|
+
],
|
|
55
|
+
"states": [
|
|
56
|
+
"BarWorkflow always renders compact 48px bold-brand chrome and has no expanded, constrained, or responsive variant.",
|
|
57
|
+
"An unrecognized value resolves navigation from the first step without mutating the controlled value.",
|
|
58
|
+
"The first step omits Previous. Intermediate steps show Previous and Next. The last step replaces Next with the Check Save or Submit action.",
|
|
59
|
+
"The default empty steps array is a single-step flow with the plain heading, no Previous control, and the final action visible. An explicit one-step array behaves the same way.",
|
|
60
|
+
"isNextInactive blocks forward navigation while preserving the Next control; the target step's isInactive state also blocks entry.",
|
|
61
|
+
"submitAction owns the final label, native button type, inactive state, and loading state."
|
|
62
|
+
],
|
|
63
|
+
"responsiveBehavior": [
|
|
64
|
+
"BarWorkflow does not expose a presentation variant and never collapses its navigation actions.",
|
|
65
|
+
"The heading truncates before Exit, Previous, and Next or Submit lose their complete hit targets.",
|
|
66
|
+
"When slotted into ShellPage, BarWorkflow remains compact while ShellPage continues to provide sticky placement."
|
|
67
|
+
],
|
|
68
|
+
"frameworkCaveats": {
|
|
69
|
+
"customElements": [
|
|
70
|
+
"Assign steps and submitAction as JavaScript properties and replace their identities when controlled state changes.",
|
|
71
|
+
"Update value after dsStepChange, handle dsExit in the workflow owner, and use dsSubmit only when product behavior supplements native form submission."
|
|
72
|
+
],
|
|
73
|
+
"react": [
|
|
74
|
+
"Pass steps and submitAction directly to DsBarWorkflow and keep value controlled in the workflow route.",
|
|
75
|
+
"Place DsBarWorkflow in DsShellPage with slot=header when sticky page placement is required."
|
|
76
|
+
],
|
|
77
|
+
"angular": [
|
|
78
|
+
"Bind steps and submitAction on the standalone DsBarWorkflow adapter and update value from dsStepChange.",
|
|
79
|
+
"Place ds-bar-workflow in ds-shell-page with slot=header and keep the form or router outlet in ShellPage content."
|
|
80
|
+
]
|
|
81
|
+
},
|
|
82
|
+
"references": [
|
|
83
|
+
{
|
|
84
|
+
"label": "Workflow states and controlled navigation",
|
|
85
|
+
"path": "src/wc/components/BarWorkflow/BarWorkflow.stories.ts"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"label": "Cross-browser workflow behavior",
|
|
89
|
+
"path": "tests/e2e/bar-workflow.spec.ts"
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
},
|
|
93
|
+
"api": {
|
|
94
|
+
"props": {
|
|
95
|
+
"exitAriaLabel": {
|
|
96
|
+
"type": "string",
|
|
97
|
+
"resolvedType": "string",
|
|
98
|
+
"attribute": "exit-aria-label",
|
|
99
|
+
"default": "'Exit workflow'",
|
|
100
|
+
"required": false,
|
|
101
|
+
"mutable": false,
|
|
102
|
+
"description": "Workflow-specific accessible name for Exit."
|
|
103
|
+
},
|
|
104
|
+
"exitLabel": {
|
|
105
|
+
"type": "string",
|
|
106
|
+
"resolvedType": "string",
|
|
107
|
+
"attribute": "exit-label",
|
|
108
|
+
"default": "'Exit'",
|
|
109
|
+
"required": false,
|
|
110
|
+
"mutable": false,
|
|
111
|
+
"description": "Concise tooltip label for the Exit control."
|
|
112
|
+
},
|
|
113
|
+
"heading": {
|
|
114
|
+
"type": "string",
|
|
115
|
+
"resolvedType": "string",
|
|
116
|
+
"attribute": "heading",
|
|
117
|
+
"required": true,
|
|
118
|
+
"mutable": false,
|
|
119
|
+
"description": "The workflow's single visible h1."
|
|
120
|
+
},
|
|
121
|
+
"isNextInactive": {
|
|
122
|
+
"type": "boolean",
|
|
123
|
+
"resolvedType": "boolean",
|
|
124
|
+
"attribute": "is-next-inactive",
|
|
125
|
+
"default": "false",
|
|
126
|
+
"required": false,
|
|
127
|
+
"mutable": false,
|
|
128
|
+
"description": "Prevent advancing while the current step is incomplete or invalid."
|
|
129
|
+
},
|
|
130
|
+
"nextLabel": {
|
|
131
|
+
"type": "string",
|
|
132
|
+
"resolvedType": "string",
|
|
133
|
+
"attribute": "next-label",
|
|
134
|
+
"default": "'Next step'",
|
|
135
|
+
"required": false,
|
|
136
|
+
"mutable": false,
|
|
137
|
+
"description": "Tooltip and accessible name for the next-step control."
|
|
138
|
+
},
|
|
139
|
+
"previousLabel": {
|
|
140
|
+
"type": "string",
|
|
141
|
+
"resolvedType": "string",
|
|
142
|
+
"attribute": "previous-label",
|
|
143
|
+
"default": "'Previous step'",
|
|
144
|
+
"required": false,
|
|
145
|
+
"mutable": false,
|
|
146
|
+
"description": "Tooltip and accessible name for the previous-step control."
|
|
147
|
+
},
|
|
148
|
+
"steps": {
|
|
149
|
+
"type": "BarWorkflowStep[]",
|
|
150
|
+
"resolvedType": "BarWorkflowStep[]",
|
|
151
|
+
"default": "[]",
|
|
152
|
+
"required": false,
|
|
153
|
+
"mutable": false,
|
|
154
|
+
"description": "Ordered workflow steps. Step state is controlled by the application."
|
|
155
|
+
},
|
|
156
|
+
"submitAction": {
|
|
157
|
+
"type": "BarWorkflowSubmitAction",
|
|
158
|
+
"resolvedType": "BarWorkflowSubmitAction",
|
|
159
|
+
"default": "{\n label: 'Save',\n type: 'submit',\n }",
|
|
160
|
+
"required": false,
|
|
161
|
+
"mutable": false,
|
|
162
|
+
"description": "The final-step Save or Submit action."
|
|
163
|
+
},
|
|
164
|
+
"value": {
|
|
165
|
+
"type": "string",
|
|
166
|
+
"resolvedType": "string",
|
|
167
|
+
"attribute": "value",
|
|
168
|
+
"default": "''",
|
|
169
|
+
"required": false,
|
|
170
|
+
"mutable": false,
|
|
171
|
+
"description": "Id of the current workflow step. Falls back to the first step."
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
"events": [
|
|
175
|
+
{
|
|
176
|
+
"name": "dsExit",
|
|
177
|
+
"detail": "MouseEvent",
|
|
178
|
+
"bubbles": true,
|
|
179
|
+
"cancelable": true,
|
|
180
|
+
"composed": true,
|
|
181
|
+
"description": "Emitted when Exit is activated."
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
"name": "dsStepChange",
|
|
185
|
+
"detail": "string",
|
|
186
|
+
"bubbles": true,
|
|
187
|
+
"cancelable": true,
|
|
188
|
+
"composed": true,
|
|
189
|
+
"description": "Emitted with the target previous or next step id. The component never mutates value."
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"name": "dsSubmit",
|
|
193
|
+
"detail": "MouseEvent",
|
|
194
|
+
"bubbles": true,
|
|
195
|
+
"cancelable": true,
|
|
196
|
+
"composed": true,
|
|
197
|
+
"description": "Emitted when the final Save or Submit control is activated."
|
|
198
|
+
}
|
|
199
|
+
],
|
|
200
|
+
"methods": [],
|
|
201
|
+
"slots": []
|
|
202
|
+
},
|
|
203
|
+
"props": {
|
|
204
|
+
"exitAriaLabel": {
|
|
205
|
+
"type": "string",
|
|
206
|
+
"resolvedType": "string",
|
|
207
|
+
"attribute": "exit-aria-label",
|
|
208
|
+
"default": "'Exit workflow'",
|
|
209
|
+
"required": false,
|
|
210
|
+
"mutable": false,
|
|
211
|
+
"description": "Workflow-specific accessible name for Exit."
|
|
212
|
+
},
|
|
213
|
+
"exitLabel": {
|
|
214
|
+
"type": "string",
|
|
215
|
+
"resolvedType": "string",
|
|
216
|
+
"attribute": "exit-label",
|
|
217
|
+
"default": "'Exit'",
|
|
218
|
+
"required": false,
|
|
219
|
+
"mutable": false,
|
|
220
|
+
"description": "Concise tooltip label for the Exit control."
|
|
221
|
+
},
|
|
222
|
+
"heading": {
|
|
223
|
+
"type": "string",
|
|
224
|
+
"resolvedType": "string",
|
|
225
|
+
"attribute": "heading",
|
|
226
|
+
"required": true,
|
|
227
|
+
"mutable": false,
|
|
228
|
+
"description": "The workflow's single visible h1."
|
|
229
|
+
},
|
|
230
|
+
"isNextInactive": {
|
|
231
|
+
"type": "boolean",
|
|
232
|
+
"resolvedType": "boolean",
|
|
233
|
+
"attribute": "is-next-inactive",
|
|
234
|
+
"default": "false",
|
|
235
|
+
"required": false,
|
|
236
|
+
"mutable": false,
|
|
237
|
+
"description": "Prevent advancing while the current step is incomplete or invalid."
|
|
238
|
+
},
|
|
239
|
+
"nextLabel": {
|
|
240
|
+
"type": "string",
|
|
241
|
+
"resolvedType": "string",
|
|
242
|
+
"attribute": "next-label",
|
|
243
|
+
"default": "'Next step'",
|
|
244
|
+
"required": false,
|
|
245
|
+
"mutable": false,
|
|
246
|
+
"description": "Tooltip and accessible name for the next-step control."
|
|
247
|
+
},
|
|
248
|
+
"previousLabel": {
|
|
249
|
+
"type": "string",
|
|
250
|
+
"resolvedType": "string",
|
|
251
|
+
"attribute": "previous-label",
|
|
252
|
+
"default": "'Previous step'",
|
|
253
|
+
"required": false,
|
|
254
|
+
"mutable": false,
|
|
255
|
+
"description": "Tooltip and accessible name for the previous-step control."
|
|
256
|
+
},
|
|
257
|
+
"steps": {
|
|
258
|
+
"type": "BarWorkflowStep[]",
|
|
259
|
+
"resolvedType": "BarWorkflowStep[]",
|
|
260
|
+
"default": "[]",
|
|
261
|
+
"required": false,
|
|
262
|
+
"mutable": false,
|
|
263
|
+
"description": "Ordered workflow steps. Step state is controlled by the application."
|
|
264
|
+
},
|
|
265
|
+
"submitAction": {
|
|
266
|
+
"type": "BarWorkflowSubmitAction",
|
|
267
|
+
"resolvedType": "BarWorkflowSubmitAction",
|
|
268
|
+
"default": "{\n label: 'Save',\n type: 'submit',\n }",
|
|
269
|
+
"required": false,
|
|
270
|
+
"mutable": false,
|
|
271
|
+
"description": "The final-step Save or Submit action."
|
|
272
|
+
},
|
|
273
|
+
"value": {
|
|
274
|
+
"type": "string",
|
|
275
|
+
"resolvedType": "string",
|
|
276
|
+
"attribute": "value",
|
|
277
|
+
"default": "''",
|
|
278
|
+
"required": false,
|
|
279
|
+
"mutable": false,
|
|
280
|
+
"description": "Id of the current workflow step. Falls back to the first step."
|
|
281
|
+
}
|
|
282
|
+
},
|
|
283
|
+
"events": [
|
|
284
|
+
{
|
|
285
|
+
"name": "dsExit",
|
|
286
|
+
"detail": "MouseEvent",
|
|
287
|
+
"bubbles": true,
|
|
288
|
+
"cancelable": true,
|
|
289
|
+
"composed": true,
|
|
290
|
+
"description": "Emitted when Exit is activated."
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
"name": "dsStepChange",
|
|
294
|
+
"detail": "string",
|
|
295
|
+
"bubbles": true,
|
|
296
|
+
"cancelable": true,
|
|
297
|
+
"composed": true,
|
|
298
|
+
"description": "Emitted with the target previous or next step id. The component never mutates value."
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
"name": "dsSubmit",
|
|
302
|
+
"detail": "MouseEvent",
|
|
303
|
+
"bubbles": true,
|
|
304
|
+
"cancelable": true,
|
|
305
|
+
"composed": true,
|
|
306
|
+
"description": "Emitted when the final Save or Submit control is activated."
|
|
307
|
+
}
|
|
308
|
+
],
|
|
309
|
+
"methods": [],
|
|
310
|
+
"slots": [],
|
|
311
|
+
"exports": {
|
|
312
|
+
"customElement": "ds-bar-workflow",
|
|
313
|
+
"react": "DsBarWorkflow",
|
|
314
|
+
"angular": "DsBarWorkflow"
|
|
315
|
+
},
|
|
316
|
+
"consumption": {
|
|
317
|
+
"install": "npm install @ds-mo/ui @ds-mo/tokens @ds-mo/icons",
|
|
318
|
+
"cssSetup": "import '@ds-mo/tokens';\nimport '@ds-mo/tokens/reset';\nimport '@ds-mo/tokens/globals';",
|
|
319
|
+
"customElements": {
|
|
320
|
+
"import": "import '@ds-mo/ui/dist/components/ds-bar-workflow.js';",
|
|
321
|
+
"example": "<ds-bar-workflow></ds-bar-workflow>"
|
|
322
|
+
},
|
|
323
|
+
"react": {
|
|
324
|
+
"import": "import { DsBarWorkflow } from '@ds-mo/ui/react';",
|
|
325
|
+
"example": "<DsBarWorkflow />"
|
|
326
|
+
},
|
|
327
|
+
"angular": {
|
|
328
|
+
"import": "import { DsBarWorkflow } from '@ds-mo/ui/angular/ds-bar-workflow';",
|
|
329
|
+
"example": "<ds-bar-workflow></ds-bar-workflow>"
|
|
330
|
+
},
|
|
331
|
+
"complexPropertyNote": "Assign these non-primitive values as JavaScript properties: steps, submitAction.",
|
|
332
|
+
"peerDependencies": {
|
|
333
|
+
"required": [
|
|
334
|
+
"@ds-mo/tokens ^3.1.1",
|
|
335
|
+
"@ds-mo/icons ^6.4.0"
|
|
336
|
+
],
|
|
337
|
+
"frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
},
|
|
341
|
+
"dependencies": [
|
|
342
|
+
"@ds-mo/ui",
|
|
343
|
+
"@ds-mo/tokens"
|
|
344
|
+
],
|
|
345
|
+
"registryDependencies": [
|
|
346
|
+
"button-filled",
|
|
347
|
+
"button-unfilled",
|
|
348
|
+
"text",
|
|
349
|
+
"tooltip"
|
|
350
|
+
],
|
|
351
|
+
"files": [
|
|
352
|
+
{
|
|
353
|
+
"path": "src/wc/components/BarWorkflow/BarWorkflow.css",
|
|
354
|
+
"content": "@import '../../utils/control-density.css';\n\n:host {\n display: block;\n min-width: 0;\n box-sizing: border-box;\n background: var(--color-background-bold-brand);\n}\n\n.bar-workflow {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--dimension-space-100);\n height: var(--dimension-size-600);\n min-width: 0;\n padding: var(--dimension-space-100);\n box-sizing: border-box;\n background: var(--color-background-bold-brand);\n}\n\n.bar-workflow__identity {\n display: flex;\n flex: 1 1 auto;\n align-items: center;\n gap: var(--dimension-space-050);\n height: var(--dimension-size-400);\n min-width: 0;\n}\n\n.bar-workflow__heading {\n display: inline-flex;\n flex: 1 1 auto;\n align-items: center;\n width: auto;\n min-width: 0;\n height: var(--dimension-size-400);\n padding-inline: calc(var(--ds-control-padding-inline) + var(--ds-control-label-inset));\n box-sizing: border-box;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n user-select: none;\n}\n\n.bar-workflow__actions {\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n gap: var(--dimension-space-100);\n}\n",
|
|
355
|
+
"type": "registry:ui"
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
"path": "src/wc/components/BarWorkflow/BarWorkflow.tsx",
|
|
359
|
+
"content": "import { Component, Event, EventEmitter, h, Host, Prop } from '@stencil/core';\nimport type { BarWorkflowStep, BarWorkflowSubmitAction } from './bar-workflow-types';\n\n@Component({\n tag: 'ds-bar-workflow',\n styleUrl: 'BarWorkflow.css',\n scoped: true,\n})\nexport class BarWorkflow {\n /** The workflow's single visible h1. */\n @Prop() heading!: string;\n\n /** Ordered workflow steps. Step state is controlled by the application. */\n @Prop() steps: BarWorkflowStep[] = [];\n\n /** Id of the current workflow step. Falls back to the first step. */\n @Prop() value: string = '';\n\n /** Concise tooltip label for the Exit control. */\n @Prop() exitLabel: string = 'Exit';\n\n /** Workflow-specific accessible name for Exit. */\n @Prop() exitAriaLabel: string = 'Exit workflow';\n\n /** Tooltip and accessible name for the previous-step control. */\n @Prop() previousLabel: string = 'Previous step';\n\n /** Tooltip and accessible name for the next-step control. */\n @Prop() nextLabel: string = 'Next step';\n\n /** The final-step Save or Submit action. */\n @Prop() submitAction: BarWorkflowSubmitAction = {\n label: 'Save',\n type: 'submit',\n };\n\n /** Prevent advancing while the current step is incomplete or invalid. */\n @Prop() isNextInactive: boolean = false;\n\n /** Emitted when Exit is activated. */\n @Event() dsExit!: EventEmitter<MouseEvent>;\n\n /** Emitted with the target previous or next step id. The component never mutates value. */\n @Event() dsStepChange!: EventEmitter<string>;\n\n /** Emitted when the final Save or Submit control is activated. */\n @Event() dsSubmit!: EventEmitter<MouseEvent>;\n\n private get currentIndex(): number {\n const index = this.steps.findIndex(step => step.id === this.value);\n return index >= 0 ? index : 0;\n }\n\n private get previousStep(): BarWorkflowStep | null {\n return this.steps[this.currentIndex - 1] ?? null;\n }\n\n private get nextStep(): BarWorkflowStep | null {\n return this.steps[this.currentIndex + 1] ?? null;\n }\n\n private get isLastStep(): boolean {\n return this.steps.length <= 1 || this.currentIndex === this.steps.length - 1;\n }\n\n private get resolvedHeading(): string {\n if (this.steps.length <= 1) return this.heading;\n return `${this.heading} · ${this.currentIndex + 1}/${this.steps.length}`;\n }\n\n private handlePrevious = () => {\n if (this.previousStep && !this.previousStep.isInactive) {\n this.dsStepChange.emit(this.previousStep.id);\n }\n };\n\n private handleNext = () => {\n if (this.nextStep && !this.isNextInactive && !this.nextStep.isInactive) {\n this.dsStepChange.emit(this.nextStep.id);\n }\n };\n\n render() {\n const submit = this.submitAction;\n return (\n <Host>\n <div class=\"bar-workflow\">\n <div class=\"bar-workflow__identity\">\n <ds-tooltip label={this.exitLabel} side=\"bottom\" size=\"sm\">\n <ds-button-unfilled\n class=\"bar-workflow__exit\"\n variant=\"icon\"\n icon=\"Cross\"\n aria-label={this.exitAriaLabel}\n size=\"md\"\n background=\"bold\"\n activeFill={false}\n hasBorder={false}\n onDsClick={(event: CustomEvent<MouseEvent>) => this.dsExit.emit(event.detail)}\n />\n </ds-tooltip>\n <ds-text\n class=\"bar-workflow__heading ds-control--md\"\n variant=\"text-title-small\"\n emphasis\n color=\"on-bold\"\n as=\"h1\"\n lineTruncation={1}\n >\n {this.resolvedHeading}\n </ds-text>\n </div>\n\n <div class=\"bar-workflow__actions\">\n {this.previousStep ? (\n <ds-tooltip label={this.previousLabel} side=\"bottom\" size=\"sm\">\n <ds-button-unfilled\n class=\"bar-workflow__previous\"\n variant=\"icon\"\n icon=\"ChevronLeft\"\n aria-label={this.previousLabel}\n size=\"md\"\n background=\"bold\"\n activeFill={false}\n hasBorder={false}\n isInactive={this.previousStep.isInactive}\n onDsClick={this.handlePrevious}\n />\n </ds-tooltip>\n ) : null}\n\n {this.isLastStep ? (\n <ds-tooltip label={submit.label} side=\"bottom\" size=\"sm\">\n <ds-button-filled\n class=\"bar-workflow__submit\"\n variant=\"icon\"\n icon=\"Check\"\n label={submit.label}\n aria-label={submit.label}\n intent=\"brand\"\n contrast=\"faint\"\n background=\"bold\"\n size=\"md\"\n type={submit.type ?? 'submit'}\n isInactive={submit.isInactive}\n isLoading={submit.isLoading}\n onDsClick={(event: CustomEvent<MouseEvent>) => this.dsSubmit.emit(event.detail)}\n />\n </ds-tooltip>\n ) : (\n <ds-tooltip label={this.nextLabel} side=\"bottom\" size=\"sm\">\n <ds-button-filled\n class=\"bar-workflow__next\"\n variant=\"icon\"\n icon=\"ChevronRight\"\n label={this.nextLabel}\n aria-label={this.nextLabel}\n intent=\"brand\"\n contrast=\"faint\"\n background=\"bold\"\n size=\"md\"\n type=\"button\"\n isInactive={this.isNextInactive || this.nextStep?.isInactive}\n onDsClick={this.handleNext}\n />\n </ds-tooltip>\n )}\n </div>\n </div>\n </Host>\n );\n }\n}\n",
|
|
360
|
+
"type": "registry:ui"
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
"path": "src/wc/components/BarWorkflow/bar-workflow-types.ts",
|
|
364
|
+
"content": "export interface BarWorkflowStep {\n id: string;\n label: string;\n isInactive?: boolean;\n}\n\nexport interface BarWorkflowSubmitAction {\n label: string;\n type?: 'button' | 'submit' | 'reset';\n isInactive?: boolean;\n isLoading?: boolean;\n}\n",
|
|
365
|
+
"type": "registry:ui"
|
|
366
|
+
}
|
|
367
|
+
]
|
|
368
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
3
|
+
"name": "breadcrumb",
|
|
4
|
+
"title": "Breadcrumb",
|
|
5
|
+
"description": "Compact hierarchical page navigation with native links or application-owned selection, optional current-page semantics, and slash separators.",
|
|
6
|
+
"type": "registry:ui",
|
|
7
|
+
"meta": {
|
|
8
|
+
"library": "@ds-mo/ui",
|
|
9
|
+
"distribution": "npm",
|
|
10
|
+
"storybook": "https://zainadeel.github.io/compomo/?path=/story/breadcrumb",
|
|
11
|
+
"source": "src/wc/components/Breadcrumb/Breadcrumb.tsx",
|
|
12
|
+
"intentStatus": "complete",
|
|
13
|
+
"intent": {
|
|
14
|
+
"audience": "general",
|
|
15
|
+
"status": "stable",
|
|
16
|
+
"summary": "Compact hierarchical page navigation with native links or application-owned selection, optional current-page semantics, and slash separators.",
|
|
17
|
+
"useWhen": [
|
|
18
|
+
"A page needs to expose its hierarchical ancestors above the current page title.",
|
|
19
|
+
"Users need to move directly to a broader page in the current route hierarchy.",
|
|
20
|
+
"BarTitle expanded presentation needs an ancestor path instead of a directional Back button."
|
|
21
|
+
],
|
|
22
|
+
"avoidWhen": [
|
|
23
|
+
"The navigation represents primary application destinations; use PanelNav or BarNav.",
|
|
24
|
+
"The choices switch peer views within the current page; use TabGroup or the BarTitle section selector.",
|
|
25
|
+
"Only a directional return command is needed in compact chrome; use the owning header's Back action.",
|
|
26
|
+
"The path would repeat the same current-page label already communicated by a nearby h1 without adding useful ancestors."
|
|
27
|
+
],
|
|
28
|
+
"alternatives": [
|
|
29
|
+
{
|
|
30
|
+
"when": "The title and breadcrumb belong to responsive page chrome with page-level actions.",
|
|
31
|
+
"component": "component:ds-bar-title",
|
|
32
|
+
"reason": "BarTitle composes Breadcrumb in expanded mode and preserves compact Back behavior."
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"when": "A small set of peer content views should remain directly selectable.",
|
|
36
|
+
"component": "component:ds-tab-group",
|
|
37
|
+
"reason": "TabGroup communicates peer selection rather than route ancestry."
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
"commonlyComposedWith": [
|
|
41
|
+
"component:ds-bar-title",
|
|
42
|
+
"component:ds-text",
|
|
43
|
+
"component:ds-shell-page"
|
|
44
|
+
],
|
|
45
|
+
"accessibility": [
|
|
46
|
+
"The component renders a named navigation landmark containing an ordered list.",
|
|
47
|
+
"Provide href for native navigation or handle dsSelect when the application router owns navigation.",
|
|
48
|
+
"Mark at most one item current; it renders without interaction and exposes aria-current=page.",
|
|
49
|
+
"Visible caption labels use secondary foreground and slash separators are decorative and hidden from assistive technology.",
|
|
50
|
+
"Every interactive item remains keyboard reachable and receives the shared focus ring."
|
|
51
|
+
],
|
|
52
|
+
"states": [
|
|
53
|
+
"Items with href render native anchors; items without href render buttons and emit the same dsSelect detail.",
|
|
54
|
+
"Preventing dsSelect cancels native anchor navigation.",
|
|
55
|
+
"A current item is static text and never emits selection.",
|
|
56
|
+
"Links have no resting underline and add a quaternary-foreground solid underline on hover; focus remains communicated by the shared focus ring."
|
|
57
|
+
],
|
|
58
|
+
"responsiveBehavior": [
|
|
59
|
+
"The path stays on one caption line and truncates long labels within the available width.",
|
|
60
|
+
"Width is protected newest-to-oldest: the oldest ancestor collapses to a literal ellipsis before the next ancestor yields width, and the current location truncates only after every ancestor reaches its minimum.",
|
|
61
|
+
"A fully collapsed item keeps its complete label available to assistive technology while rendering only the literal ellipsis visually.",
|
|
62
|
+
"Separators remain visible while labels yield width."
|
|
63
|
+
],
|
|
64
|
+
"frameworkCaveats": {
|
|
65
|
+
"customElements": [
|
|
66
|
+
"Assign items as a JavaScript property and replace its array identity when the route changes.",
|
|
67
|
+
"Use relative or absolute href values for native navigation; omit href when the host router handles dsSelect."
|
|
68
|
+
],
|
|
69
|
+
"react": [
|
|
70
|
+
"Pass items to DsBreadcrumb and handle onDsSelect when navigation is application-owned."
|
|
71
|
+
],
|
|
72
|
+
"angular": [
|
|
73
|
+
"Bind items on the standalone DsBreadcrumb adapter and handle dsSelect when navigation is application-owned."
|
|
74
|
+
]
|
|
75
|
+
},
|
|
76
|
+
"references": [
|
|
77
|
+
{
|
|
78
|
+
"label": "Storybook examples",
|
|
79
|
+
"path": "src/wc/components/Breadcrumb/Breadcrumb.stories.ts"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"label": "Expanded page-header composition",
|
|
83
|
+
"path": "src/wc/components/BarTitle/BarTitle.tsx"
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
},
|
|
87
|
+
"api": {
|
|
88
|
+
"props": {
|
|
89
|
+
"ariaLabel": {
|
|
90
|
+
"type": "string",
|
|
91
|
+
"resolvedType": "string",
|
|
92
|
+
"attribute": "aria-label",
|
|
93
|
+
"default": "'Breadcrumb'",
|
|
94
|
+
"required": false,
|
|
95
|
+
"mutable": false,
|
|
96
|
+
"description": "Accessible name for the breadcrumb navigation landmark."
|
|
97
|
+
},
|
|
98
|
+
"items": {
|
|
99
|
+
"type": "BreadcrumbItem[]",
|
|
100
|
+
"resolvedType": "BreadcrumbItem[]",
|
|
101
|
+
"default": "[]",
|
|
102
|
+
"required": false,
|
|
103
|
+
"mutable": false,
|
|
104
|
+
"description": "Ordered path from the broadest ancestor to the nearest page."
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
"events": [
|
|
108
|
+
{
|
|
109
|
+
"name": "dsSelect",
|
|
110
|
+
"detail": "BreadcrumbSelectDetail",
|
|
111
|
+
"bubbles": true,
|
|
112
|
+
"cancelable": true,
|
|
113
|
+
"composed": true,
|
|
114
|
+
"description": "Emitted when an interactive breadcrumb item is activated. Prevent to cancel native navigation."
|
|
115
|
+
}
|
|
116
|
+
],
|
|
117
|
+
"methods": [],
|
|
118
|
+
"slots": []
|
|
119
|
+
},
|
|
120
|
+
"props": {
|
|
121
|
+
"ariaLabel": {
|
|
122
|
+
"type": "string",
|
|
123
|
+
"resolvedType": "string",
|
|
124
|
+
"attribute": "aria-label",
|
|
125
|
+
"default": "'Breadcrumb'",
|
|
126
|
+
"required": false,
|
|
127
|
+
"mutable": false,
|
|
128
|
+
"description": "Accessible name for the breadcrumb navigation landmark."
|
|
129
|
+
},
|
|
130
|
+
"items": {
|
|
131
|
+
"type": "BreadcrumbItem[]",
|
|
132
|
+
"resolvedType": "BreadcrumbItem[]",
|
|
133
|
+
"default": "[]",
|
|
134
|
+
"required": false,
|
|
135
|
+
"mutable": false,
|
|
136
|
+
"description": "Ordered path from the broadest ancestor to the nearest page."
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
"events": [
|
|
140
|
+
{
|
|
141
|
+
"name": "dsSelect",
|
|
142
|
+
"detail": "BreadcrumbSelectDetail",
|
|
143
|
+
"bubbles": true,
|
|
144
|
+
"cancelable": true,
|
|
145
|
+
"composed": true,
|
|
146
|
+
"description": "Emitted when an interactive breadcrumb item is activated. Prevent to cancel native navigation."
|
|
147
|
+
}
|
|
148
|
+
],
|
|
149
|
+
"methods": [],
|
|
150
|
+
"slots": [],
|
|
151
|
+
"exports": {
|
|
152
|
+
"customElement": "ds-breadcrumb",
|
|
153
|
+
"react": "DsBreadcrumb",
|
|
154
|
+
"angular": "DsBreadcrumb"
|
|
155
|
+
},
|
|
156
|
+
"consumption": {
|
|
157
|
+
"install": "npm install @ds-mo/ui @ds-mo/tokens @ds-mo/icons",
|
|
158
|
+
"cssSetup": "import '@ds-mo/tokens';\nimport '@ds-mo/tokens/reset';\nimport '@ds-mo/tokens/globals';",
|
|
159
|
+
"customElements": {
|
|
160
|
+
"import": "import '@ds-mo/ui/dist/components/ds-breadcrumb.js';",
|
|
161
|
+
"example": "<ds-breadcrumb></ds-breadcrumb>"
|
|
162
|
+
},
|
|
163
|
+
"react": {
|
|
164
|
+
"import": "import { DsBreadcrumb } from '@ds-mo/ui/react';",
|
|
165
|
+
"example": "<DsBreadcrumb />"
|
|
166
|
+
},
|
|
167
|
+
"angular": {
|
|
168
|
+
"import": "import { DsBreadcrumb } from '@ds-mo/ui/angular/ds-breadcrumb';",
|
|
169
|
+
"example": "<ds-breadcrumb></ds-breadcrumb>"
|
|
170
|
+
},
|
|
171
|
+
"complexPropertyNote": "Assign these non-primitive values as JavaScript properties: items.",
|
|
172
|
+
"peerDependencies": {
|
|
173
|
+
"required": [
|
|
174
|
+
"@ds-mo/tokens ^3.1.1",
|
|
175
|
+
"@ds-mo/icons ^6.4.0"
|
|
176
|
+
],
|
|
177
|
+
"frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
"dependencies": [
|
|
182
|
+
"@ds-mo/ui",
|
|
183
|
+
"@ds-mo/tokens"
|
|
184
|
+
],
|
|
185
|
+
"registryDependencies": [
|
|
186
|
+
"text"
|
|
187
|
+
],
|
|
188
|
+
"files": [
|
|
189
|
+
{
|
|
190
|
+
"path": "src/wc/components/Breadcrumb/Breadcrumb.css",
|
|
191
|
+
"content": "@import '../../utils/focus-ring.css';\n\n:host {\n position: relative;\n display: block;\n min-width: 0;\n box-sizing: border-box;\n}\n\n.breadcrumb {\n inline-size: 100%;\n min-width: 0;\n}\n\n.breadcrumb__list {\n display: flex;\n align-items: center;\n box-sizing: border-box;\n inline-size: 100%;\n min-width: 0;\n margin: 0;\n padding: 0;\n overflow: hidden;\n list-style: none;\n}\n\n.breadcrumb__item {\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n min-width: 0;\n}\n\n.breadcrumb__separator {\n flex: 0 0 auto;\n margin-inline: var(--dimension-space-050);\n user-select: none;\n}\n\n.breadcrumb__link,\n.breadcrumb__current {\n display: inline-flex;\n flex: 0 0 auto;\n min-width: 0;\n overflow: hidden;\n padding: 0;\n border: 0;\n border-radius: var(--dimension-radius-025);\n background: transparent;\n color: var(--color-foreground-secondary);\n font: inherit;\n text-decoration: none;\n}\n\n.breadcrumb__link {\n cursor: pointer;\n}\n\n.breadcrumb__link:hover .breadcrumb__label {\n text-decoration: underline;\n text-decoration-color: var(--color-foreground-quaternary);\n text-underline-offset: var(--dimension-space-025);\n text-decoration-thickness: var(--dimension-stroke-width-012);\n}\n\n.breadcrumb__label {\n display: inline-block;\n inline-size: var(--breadcrumb-label-width, auto);\n min-width: 0;\n}\n\n.breadcrumb__measurements {\n position: absolute;\n inset: 0 auto auto 0;\n visibility: hidden;\n pointer-events: none;\n white-space: nowrap;\n}\n\n.breadcrumb__measurement {\n display: inline-block;\n inline-size: max-content;\n max-inline-size: none;\n}\n\n.breadcrumb__accessible-label {\n position: absolute;\n /* stylelint-disable declaration-property-value-disallowed-list -- classic visually-hidden clip pattern */\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n /* stylelint-enable declaration-property-value-disallowed-list */\n}\n",
|
|
192
|
+
"type": "registry:ui"
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
"path": "src/wc/components/Breadcrumb/Breadcrumb.tsx",
|
|
196
|
+
"content": "import { Component, Event, EventEmitter, h, Host, Prop, State, Watch } from '@stencil/core';\nimport type { BreadcrumbItem, BreadcrumbSelectDetail } from './breadcrumb-types';\n\n@Component({\n tag: 'ds-breadcrumb',\n styleUrl: 'Breadcrumb.css',\n scoped: true,\n})\nexport class Breadcrumb {\n /** Ordered path from the broadest ancestor to the nearest page. */\n @Prop() items: BreadcrumbItem[] = [];\n\n /** Accessible name for the breadcrumb navigation landmark. */\n @Prop() ariaLabel: string = 'Breadcrumb';\n\n /** Emitted when an interactive breadcrumb item is activated. Prevent to cancel native navigation. */\n @Event({ cancelable: true }) dsSelect!: EventEmitter<BreadcrumbSelectDetail>;\n\n @State() private labelWidths: number[] = [];\n @State() private collapsedLabels: boolean[] = [];\n\n private navElement?: HTMLElement;\n private listElement?: HTMLOListElement;\n private measurementElements: HTMLElement[] = [];\n private separatorElements: HTMLElement[] = [];\n private ellipsisMeasurement?: HTMLElement;\n private resizeObserver?: ResizeObserver;\n private observedElement?: HTMLElement;\n private measurementFrame?: number;\n\n componentDidLoad() {\n this.observeContainer();\n this.scheduleMeasurement();\n void document.fonts?.ready.then(() => this.scheduleMeasurement());\n }\n\n componentDidRender() {\n this.observeContainer();\n this.scheduleMeasurement();\n }\n\n disconnectedCallback() {\n this.resizeObserver?.disconnect();\n this.observedElement = undefined;\n if (this.measurementFrame !== undefined) cancelAnimationFrame(this.measurementFrame);\n }\n\n @Watch('items')\n handleItemsChange() {\n this.labelWidths = [];\n this.collapsedLabels = [];\n this.scheduleMeasurement();\n }\n\n private observeContainer() {\n if (!this.navElement || this.observedElement === this.navElement) return;\n this.resizeObserver ??= new ResizeObserver(() => this.scheduleMeasurement());\n this.resizeObserver.disconnect();\n this.resizeObserver.observe(this.navElement);\n this.observedElement = this.navElement;\n }\n\n private scheduleMeasurement() {\n if (this.measurementFrame !== undefined) return;\n this.measurementFrame = requestAnimationFrame(() => {\n this.measurementFrame = undefined;\n this.measureLabels();\n });\n }\n\n private measureLabels() {\n if (\n !this.navElement ||\n !this.listElement ||\n !this.ellipsisMeasurement ||\n this.items.length === 0\n ) return;\n\n const naturalWidths = this.items.map(\n (_, index) => this.measurementElements[index]?.getBoundingClientRect().width ?? 0\n );\n const ellipsisWidth = this.ellipsisMeasurement.getBoundingClientRect().width;\n if (naturalWidths.some(width => width === 0) || ellipsisWidth === 0) return;\n\n const separatorWidth = this.separatorElements.reduce((total, separator) => {\n const styles = getComputedStyle(separator);\n return (\n total +\n separator.getBoundingClientRect().width +\n Number.parseFloat(styles.marginInlineStart) +\n Number.parseFloat(styles.marginInlineEnd)\n );\n }, 0);\n const availableWidth = Math.max(0, this.navElement.clientWidth - separatorWidth);\n const minimumWidths = naturalWidths.map(width => Math.min(width, ellipsisWidth));\n const nextWidths = [...minimumWidths];\n let remainingWidth = Math.max(\n 0,\n availableWidth - minimumWidths.reduce((total, width) => total + width, 0)\n );\n\n // Protect the current/newest location. Extra width is granted newest-to-oldest,\n // so ancestors collapse in path order as the available space decreases.\n for (let index = naturalWidths.length - 1; index >= 0 && remainingWidth > 0; index -= 1) {\n const extraWidth = Math.min(\n remainingWidth,\n naturalWidths[index] - minimumWidths[index]\n );\n nextWidths[index] += extraWidth;\n remainingWidth -= extraWidth;\n }\n\n const widthsChanged =\n nextWidths.length !== this.labelWidths.length ||\n nextWidths.some(\n (width, index) => Math.abs(width - (this.labelWidths[index] ?? 0)) > 0.25\n );\n const nextCollapsedLabels = nextWidths.map(\n (width, index) =>\n naturalWidths[index] > minimumWidths[index] &&\n Math.abs(width - minimumWidths[index]) <= 0.25\n );\n const collapsedLabelsChanged =\n nextCollapsedLabels.length !== this.collapsedLabels.length ||\n nextCollapsedLabels.some(\n (isCollapsed, index) => isCollapsed !== this.collapsedLabels[index]\n );\n if (widthsChanged) this.labelWidths = nextWidths;\n if (collapsedLabelsChanged) this.collapsedLabels = nextCollapsedLabels;\n }\n\n private handleSelect(item: BreadcrumbItem, originalEvent: MouseEvent) {\n const event = this.dsSelect.emit({ item, originalEvent });\n if (event.defaultPrevented) originalEvent.preventDefault();\n }\n\n private renderItem(item: BreadcrumbItem, index: number) {\n const allocatedWidth = this.labelWidths[index];\n const isCollapsed = this.collapsedLabels[index] ?? false;\n const label = (\n [\n <ds-text\n class=\"breadcrumb__label\"\n as=\"span\"\n variant=\"text-caption\"\n color=\"inherit\"\n lineTruncation={isCollapsed ? 'none' : 1}\n aria-hidden={isCollapsed ? 'true' : undefined}\n style={\n allocatedWidth === undefined\n ? undefined\n : { '--breadcrumb-label-width': `${allocatedWidth}px` }\n }\n >\n {isCollapsed ? '…' : item.label}\n </ds-text>,\n isCollapsed ? <span class=\"breadcrumb__accessible-label\">{item.label}</span> : null,\n ]\n );\n\n if (item.isCurrent) {\n return (\n <span class=\"breadcrumb__current\" aria-current=\"page\" aria-label={item.ariaLabel}>\n {label}\n </span>\n );\n }\n\n if (item.href) {\n return (\n <a\n class=\"breadcrumb__link ds-focus-ring\"\n href={item.href}\n aria-label={item.ariaLabel}\n onClick={(event: MouseEvent) => this.handleSelect(item, event)}\n >\n {label}\n </a>\n );\n }\n\n return (\n <button\n class=\"breadcrumb__link ds-focus-ring\"\n type=\"button\"\n aria-label={item.ariaLabel}\n onClick={(event: MouseEvent) => this.handleSelect(item, event)}\n >\n {label}\n </button>\n );\n }\n\n render() {\n if (this.items.length === 0) return null;\n\n this.measurementElements = [];\n this.separatorElements = [];\n\n return (\n <Host>\n <nav\n class=\"breadcrumb\"\n aria-label={this.ariaLabel}\n ref={element => {\n this.navElement = element;\n }}\n >\n <div class=\"breadcrumb__measurements\" aria-hidden=\"true\">\n {this.items.map((item, index) => (\n <ds-text\n class=\"breadcrumb__measurement\"\n as=\"span\"\n variant=\"text-caption\"\n color=\"inherit\"\n ref={element => {\n if (element) this.measurementElements[index] = element;\n }}\n >\n {item.label}\n </ds-text>\n ))}\n <ds-text\n class=\"breadcrumb__measurement\"\n as=\"span\"\n variant=\"text-caption\"\n color=\"inherit\"\n ref={element => {\n this.ellipsisMeasurement = element;\n }}\n >\n …\n </ds-text>\n </div>\n <ol\n class=\"breadcrumb__list\"\n ref={element => {\n this.listElement = element;\n }}\n >\n {this.items.map((item, index) => (\n <li class=\"breadcrumb__item\" key={item.id}>\n {index > 0 ? (\n <ds-text\n class=\"breadcrumb__separator\"\n as=\"span\"\n variant=\"text-caption\"\n color=\"tertiary\"\n aria-hidden=\"true\"\n ref={element => {\n if (element) this.separatorElements[index - 1] = element;\n }}\n >\n /\n </ds-text>\n ) : null}\n {this.renderItem(item, index)}\n </li>\n ))}\n </ol>\n </nav>\n </Host>\n );\n }\n}\n",
|
|
197
|
+
"type": "registry:ui"
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
"path": "src/wc/components/Breadcrumb/breadcrumb-types.ts",
|
|
201
|
+
"content": "export interface BreadcrumbItem {\n /** Stable value returned from dsSelect. */\n id: string;\n /** Visible caption label. */\n label: string;\n /** Optional accessible name when the visible label is not destination-specific enough. */\n ariaLabel?: string;\n /** Native destination. Omit when the route owner handles dsSelect. */\n href?: string;\n /** Marks this item as the current page and removes its interaction. */\n isCurrent?: boolean;\n}\n\nexport interface BreadcrumbSelectDetail {\n item: BreadcrumbItem;\n originalEvent: MouseEvent;\n}\n",
|
|
202
|
+
"type": "registry:ui"
|
|
203
|
+
}
|
|
204
|
+
]
|
|
205
|
+
}
|