@ds-mo/ui 12.5.0 → 12.6.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/dist/.build-stamp +1 -1
- package/dist/agent-patterns.json +21 -12
- package/dist/agent.json +1536 -1424
- package/dist/angular/ds-bar-workflow.d.ts +1 -1
- package/dist/angular/ds-bar-workflow.js +3 -3
- package/dist/angular/ds-mobile-bar-nav.d.ts +18 -0
- package/dist/angular/{ds-shell-mobile-bar.js → ds-mobile-bar-nav.js} +15 -15
- package/dist/angular/ds-mobile-header.d.ts +23 -0
- package/dist/angular/ds-mobile-header.js +45 -0
- package/dist/angular/ds-mobile-section-switcher.d.ts +18 -0
- package/dist/angular/{ds-shell-mobile-section-nav.js → ds-mobile-section-switcher.js} +15 -15
- package/dist/angular/ds-mobile-sheet-nav.d.ts +20 -0
- package/dist/angular/{ds-shell-mobile-nav.js → ds-mobile-sheet-nav.js} +13 -16
- package/dist/angular/ds-shell-app.d.ts +1 -1
- package/dist/angular/ds-shell-app.js +3 -3
- 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 +4 -3
- package/dist/angular/proxies.d.ts +4 -3
- package/dist/angular/proxies.js +4 -3
- package/dist/components/ds-agent-activity.js +1 -1
- package/dist/components/ds-agent-response.js +1 -1
- package/dist/components/ds-agent-tool-call.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.js +1 -1
- package/dist/components/ds-bar-workflow.js.map +1 -1
- package/dist/components/ds-breadcrumb.js +1 -1
- 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.js +1 -1
- package/dist/components/ds-card-data-viz-donut.js +1 -1
- package/dist/components/ds-card-data-viz-line.js +1 -1
- package/dist/components/ds-card-setting.js +1 -1
- package/dist/components/ds-chart-bar.js +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-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-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-loader.js +1 -1
- package/dist/components/ds-markdown.js +1 -1
- package/dist/components/ds-menu.js +1 -1
- package/dist/components/ds-message-composer.js +1 -1
- package/dist/components/ds-message-composer.js.map +1 -1
- package/dist/components/ds-message-scroller.js +1 -1
- package/dist/components/ds-message.js +1 -1
- package/dist/components/{ds-shell-mobile-nav.d.ts → ds-mobile-bar-nav.d.ts} +4 -4
- package/dist/components/ds-mobile-bar-nav.js +2 -0
- package/dist/components/ds-mobile-bar-nav.js.map +1 -0
- package/dist/components/ds-mobile-header.d.ts +11 -0
- package/dist/components/ds-mobile-header.js +2 -0
- package/dist/components/ds-mobile-header.js.map +1 -0
- package/dist/components/ds-mobile-section-switcher.d.ts +11 -0
- package/dist/components/ds-mobile-section-switcher.js +2 -0
- package/dist/components/ds-mobile-section-switcher.js.map +1 -0
- package/dist/components/{ds-shell-mobile-bar.d.ts → ds-mobile-sheet-nav.d.ts} +4 -4
- package/dist/components/ds-mobile-sheet-nav.js +2 -0
- package/dist/components/ds-mobile-sheet-nav.js.map +1 -0
- package/dist/components/ds-modal.js +1 -1
- package/dist/components/ds-modal.js.map +1 -1
- package/dist/components/ds-panel-nav.js +1 -1
- package/dist/components/ds-panel-nav.js.map +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-tool-search.js.map +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-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-app.js.map +1 -1
- package/dist/components/ds-shell-gradient-picker.js +1 -1
- package/dist/components/ds-shell-gradient-picker.js.map +1 -1
- package/dist/components/ds-shell-gradient-swatch.js +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-shell-tools.js +1 -1
- package/dist/components/ds-shell-tools.js.map +1 -1
- package/dist/components/ds-skeleton.js +1 -1
- package/dist/components/ds-skeleton.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-tag.js +1 -1
- package/dist/components/ds-tag.js.map +1 -1
- package/dist/components/ds-toast.js +1 -1
- package/dist/components/ds-toast.js.map +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/p--bSkr_yn.js +2 -0
- package/dist/components/p--bSkr_yn.js.map +1 -0
- package/dist/components/p-46nk9-RO.js +2 -0
- package/dist/components/p-46nk9-RO.js.map +1 -0
- package/dist/components/{p-9dQQSgwT.js → p-BHYrsGBw.js} +2 -2
- package/dist/components/p-BY0PzkUp.js +2 -0
- package/dist/components/p-BgGP65Nn.js +2 -0
- package/dist/components/p-BgGP65Nn.js.map +1 -0
- package/dist/components/p-BkAMkjIR.js +2 -0
- package/dist/components/{p-Co8hD3P-.js.map → p-BkAMkjIR.js.map} +1 -1
- package/dist/components/p-BrusnEYP.js.map +1 -1
- package/dist/components/p-C2ym_Ich.js +2 -0
- package/dist/components/{p-Biz6xo-z.js → p-CFpWrYAH.js} +2 -2
- package/dist/components/p-CICGtu7H.js +2 -0
- package/dist/components/{p-CtD24EyI.js.map → p-CICGtu7H.js.map} +1 -1
- package/dist/components/p-CLzlL3G4.js +2 -0
- package/dist/components/p-CLzlL3G4.js.map +1 -0
- package/dist/components/p-CXcjwduV.js +2 -0
- package/dist/components/{p-BhxwpOH8.js.map → p-CXcjwduV.js.map} +1 -1
- package/dist/components/p-Ca-I2UnB.js +2 -0
- package/dist/components/p-Ca-I2UnB.js.map +1 -0
- package/dist/components/p-CaRyxTMz.js +2 -0
- package/dist/components/p-CaRyxTMz.js.map +1 -0
- package/dist/components/{p-g40DTeV8.js → p-CvKKmZJj.js} +2 -2
- package/dist/components/p-D4o2D1hk.js +2 -0
- package/dist/components/p-D4o2D1hk.js.map +1 -0
- package/dist/components/{p-DXnFhmZF.js → p-D9iN80yX.js} +2 -2
- package/dist/components/p-DD1Lgs7O.js +2 -0
- package/dist/components/p-DD1Lgs7O.js.map +1 -0
- package/dist/components/{p-DjPZxzIG.js → p-DQDpDYyF.js} +2 -2
- package/dist/components/p-DTea1Du7.js +2 -0
- package/dist/components/p-DTea1Du7.js.map +1 -0
- package/dist/components/p-DWdRSOBV.js +2 -0
- package/dist/components/{p-BPS9VExm.js.map → p-DWdRSOBV.js.map} +1 -1
- package/dist/components/p-DcFfilOX.js +2 -0
- package/dist/components/p-DcFfilOX.js.map +1 -0
- package/dist/components/p-Dg3xLna0.js +2 -0
- package/dist/components/{p-C_0Q8Cnp.js.map → p-Dg3xLna0.js.map} +1 -1
- package/dist/components/p-DvVW0hxm.js +2 -0
- package/dist/components/p-DvVW0hxm.js.map +1 -0
- package/dist/components/p-YtgcuJYx.js +2 -0
- package/dist/components/{p-PZ6R_nGI.js.map → p-YtgcuJYx.js.map} +1 -1
- package/dist/components/p-loq_--ce.js +2 -0
- package/dist/components/{p-NUNsefU1.js.map → p-loq_--ce.js.map} +1 -1
- package/dist/docs/components.json +3586 -3064
- package/dist/lib/shell/index.d.ts +1 -1
- package/dist/lib/shell/index.js +2 -1
- package/dist/lib/shell/index.js.map +2 -2
- package/dist/lib/shell/shell-responsive.d.ts +3 -3
- package/dist/lib/utils/index.d.ts +1 -0
- package/dist/lib/utils/index.js +8 -0
- package/dist/lib/utils/index.js.map +3 -3
- package/dist/lib/utils/required-validity.d.ts +14 -0
- package/dist/mcp-data/registry/agent-activity.json +2 -2
- package/dist/mcp-data/registry/badge.json +2 -2
- package/dist/mcp-data/registry/bar-nav.json +2 -2
- package/dist/mcp-data/registry/bar-title.json +2 -2
- package/dist/mcp-data/registry/bar-workflow.json +25 -4
- package/dist/mcp-data/registry/breadcrumb.json +2 -2
- package/dist/mcp-data/registry/button-unfilled.json +3 -3
- package/dist/mcp-data/registry/chart-legend.json +1 -1
- 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/input.json +1 -1
- package/dist/mcp-data/registry/loader.json +2 -2
- package/dist/mcp-data/registry/mobile-bar-nav.json +333 -0
- package/dist/mcp-data/registry/mobile-header.json +351 -0
- package/dist/mcp-data/registry/mobile-section-switcher.json +210 -0
- package/dist/mcp-data/registry/mobile-sheet-nav.json +317 -0
- package/dist/mcp-data/registry/panel-nav.json +2 -2
- package/dist/mcp-data/registry/panel-tools.json +2 -2
- package/dist/mcp-data/registry/radio.json +1 -1
- package/dist/mcp-data/registry/registry.json +1544 -1429
- package/dist/mcp-data/registry/select-multi.json +1 -1
- package/dist/mcp-data/registry/select.json +2 -2
- package/dist/mcp-data/registry/shell-app.json +17 -17
- package/dist/mcp-data/registry/shell-page.json +26 -7
- package/dist/mcp-data/registry/shell-tools.json +10 -7
- package/dist/mcp-data/registry/switch.json +1 -1
- package/dist/mcp-data/registry/toast.json +2 -2
- package/dist/react/components.d.ts +4 -3
- package/dist/react/components.js +4 -3
- package/dist/react/ds-mobile-bar-nav.d.ts +13 -0
- package/dist/react/ds-mobile-bar-nav.js +15 -0
- package/dist/react/ds-mobile-header.d.ts +13 -0
- package/dist/react/ds-mobile-header.js +15 -0
- package/dist/react/ds-mobile-section-switcher.d.ts +12 -0
- package/dist/react/ds-mobile-section-switcher.js +12 -0
- package/dist/react/ds-mobile-sheet-nav.d.ts +14 -0
- package/dist/react/ds-mobile-sheet-nav.js +16 -0
- package/dist/types/components/BarWorkflow/BarWorkflow.d.ts +6 -0
- package/dist/types/components/ButtonUnfilled/ButtonUnfilled.d.ts +1 -1
- package/dist/types/components/MobileBarNav/MobileBarNav.d.ts +26 -0
- package/dist/types/components/MobileBarNav/index.d.ts +4 -0
- package/dist/types/components/MobileBarNav/mobile-bar-nav-types.d.ts +5 -0
- package/dist/types/components/MobileHeader/MobileHeader.d.ts +39 -0
- package/dist/types/components/MobileHeader/index.d.ts +2 -0
- package/dist/types/components/MobileHeader/mobile-header-types.d.ts +5 -0
- package/dist/types/components/MobileSectionSwitcher/MobileSectionSwitcher.d.ts +35 -0
- package/dist/types/components/MobileSectionSwitcher/index.d.ts +3 -0
- package/dist/types/components/MobileSectionSwitcher/mobile-section-switcher-types.d.ts +4 -0
- package/dist/types/components/MobileSectionSwitcher/mobile-section-switcher-utils.d.ts +10 -0
- package/dist/types/components/{ShellMobileNav/ShellMobileNav.d.ts → MobileSheetNav/MobileSheetNav.d.ts} +5 -7
- package/dist/types/components/MobileSheetNav/index.d.ts +1 -0
- package/dist/types/components/ShellApp/ShellApp.d.ts +4 -4
- package/dist/types/components/ShellPage/ShellPage.d.ts +4 -0
- package/dist/types/components.d.ts +530 -381
- package/dist/types/shell/index.d.ts +1 -1
- package/dist/types/shell/shell-responsive.d.ts +3 -3
- package/dist/types/utils/index.d.ts +1 -0
- package/dist/types/utils/required-validity.d.ts +15 -0
- package/package.json +1 -1
- package/dist/angular/ds-shell-mobile-bar.d.ts +0 -18
- package/dist/angular/ds-shell-mobile-nav.d.ts +0 -23
- package/dist/angular/ds-shell-mobile-section-nav.d.ts +0 -18
- package/dist/components/ds-shell-mobile-bar.js +0 -2
- package/dist/components/ds-shell-mobile-bar.js.map +0 -1
- package/dist/components/ds-shell-mobile-nav.js +0 -2
- package/dist/components/ds-shell-mobile-nav.js.map +0 -1
- package/dist/components/ds-shell-mobile-section-nav.d.ts +0 -11
- package/dist/components/ds-shell-mobile-section-nav.js +0 -2
- package/dist/components/ds-shell-mobile-section-nav.js.map +0 -1
- package/dist/components/p-B6Vuayt6.js +0 -2
- package/dist/components/p-B6Vuayt6.js.map +0 -1
- package/dist/components/p-BPS9VExm.js +0 -2
- package/dist/components/p-BVV_rlIP.js +0 -2
- package/dist/components/p-BVV_rlIP.js.map +0 -1
- package/dist/components/p-BhxwpOH8.js +0 -2
- package/dist/components/p-BtEjlcB9.js +0 -2
- package/dist/components/p-BtEjlcB9.js.map +0 -1
- package/dist/components/p-CH6cNXXF.js +0 -2
- package/dist/components/p-CH6cNXXF.js.map +0 -1
- package/dist/components/p-C_0Q8Cnp.js +0 -2
- package/dist/components/p-Ce52yVXF.js +0 -2
- package/dist/components/p-Ce52yVXF.js.map +0 -1
- package/dist/components/p-CgHTNfC1.js +0 -2
- package/dist/components/p-CgHTNfC1.js.map +0 -1
- package/dist/components/p-Co8hD3P-.js +0 -2
- package/dist/components/p-CoYFJD-w.js +0 -2
- package/dist/components/p-CoYFJD-w.js.map +0 -1
- package/dist/components/p-Cpr3K41-.js +0 -2
- package/dist/components/p-Cpr3K41-.js.map +0 -1
- package/dist/components/p-CtD24EyI.js +0 -2
- package/dist/components/p-DYqReipj.js +0 -2
- package/dist/components/p-DYqReipj.js.map +0 -1
- package/dist/components/p-NUNsefU1.js +0 -2
- package/dist/components/p-PZ6R_nGI.js +0 -2
- package/dist/components/p-jCWtxthA.js +0 -2
- package/dist/components/p-yhj1lIPx.js +0 -2
- package/dist/mcp-data/registry/shell-mobile-bar.json +0 -314
- package/dist/mcp-data/registry/shell-mobile-nav.json +0 -348
- package/dist/mcp-data/registry/shell-mobile-section-nav.json +0 -267
- package/dist/react/ds-shell-mobile-bar.d.ts +0 -13
- package/dist/react/ds-shell-mobile-bar.js +0 -15
- package/dist/react/ds-shell-mobile-nav.d.ts +0 -15
- package/dist/react/ds-shell-mobile-nav.js +0 -17
- package/dist/react/ds-shell-mobile-section-nav.d.ts +0 -12
- package/dist/react/ds-shell-mobile-section-nav.js +0 -12
- package/dist/types/components/ShellMobileBar/ShellMobileBar.d.ts +0 -25
- package/dist/types/components/ShellMobileBar/index.d.ts +0 -4
- package/dist/types/components/ShellMobileBar/shell-mobile-bar-types.d.ts +0 -5
- package/dist/types/components/ShellMobileNav/index.d.ts +0 -2
- package/dist/types/components/ShellMobileNav/shell-mobile-nav-types.d.ts +0 -6
- package/dist/types/components/ShellMobileSectionNav/ShellMobileSectionNav.d.ts +0 -30
- package/dist/types/components/ShellMobileSectionNav/index.d.ts +0 -2
- /package/dist/components/{p-9dQQSgwT.js.map → p-BHYrsGBw.js.map} +0 -0
- /package/dist/components/{p-jCWtxthA.js.map → p-BY0PzkUp.js.map} +0 -0
- /package/dist/components/{p-yhj1lIPx.js.map → p-C2ym_Ich.js.map} +0 -0
- /package/dist/components/{p-Biz6xo-z.js.map → p-CFpWrYAH.js.map} +0 -0
- /package/dist/components/{p-g40DTeV8.js.map → p-CvKKmZJj.js.map} +0 -0
- /package/dist/components/{p-DXnFhmZF.js.map → p-D9iN80yX.js.map} +0 -0
- /package/dist/components/{p-DjPZxzIG.js.map → p-DQDpDYyF.js.map} +0 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
3
|
+
"name": "mobile-header",
|
|
4
|
+
"title": "MobileHeader",
|
|
5
|
+
"description": "Consistent mobile top chrome with symmetric action lanes, a centered page identity or peer-section chooser, and an optional subordinate page-section row.",
|
|
6
|
+
"type": "registry:ui",
|
|
7
|
+
"meta": {
|
|
8
|
+
"library": "@ds-mo/ui",
|
|
9
|
+
"distribution": "npm",
|
|
10
|
+
"storybook": "https://zainadeel.github.io/compomo/?path=/story/mobile-header",
|
|
11
|
+
"source": "src/wc/components/MobileHeader/MobileHeader.tsx",
|
|
12
|
+
"intentStatus": "complete",
|
|
13
|
+
"intent": {
|
|
14
|
+
"audience": "specialized",
|
|
15
|
+
"status": "experimental",
|
|
16
|
+
"summary": "Consistent mobile top chrome with symmetric action lanes, a centered page identity or peer-section chooser, and an optional subordinate page-section row.",
|
|
17
|
+
"useWhen": [
|
|
18
|
+
"A routed page, persistent tool, account surface, or workflow needs the canonical mobile header presentation."
|
|
19
|
+
],
|
|
20
|
+
"avoidWhen": [
|
|
21
|
+
"Rendering desktop BarTitle, BarNav, or PanelToolHeader.",
|
|
22
|
+
"Rendering the Mobile Sheet Nav utility lane."
|
|
23
|
+
],
|
|
24
|
+
"commonlyComposedWith": [
|
|
25
|
+
"component:ds-mobile-section-switcher",
|
|
26
|
+
"component:ds-shell-page",
|
|
27
|
+
"component:ds-shell-tools"
|
|
28
|
+
],
|
|
29
|
+
"patterns": [
|
|
30
|
+
"pattern:application-shell"
|
|
31
|
+
],
|
|
32
|
+
"accessibility": [
|
|
33
|
+
"Static screens render a real h1 or h2 according to headingLevel.",
|
|
34
|
+
"Section-switching screens expose an equivalent semantic heading alongside the accessible popup trigger.",
|
|
35
|
+
"Subsections use a separately named navigation landmark and never replace the semantic page identity.",
|
|
36
|
+
"Leading and trailing slotted icon actions retain their own accessible names and tooltips."
|
|
37
|
+
],
|
|
38
|
+
"states": [
|
|
39
|
+
"Without multiple sections the center renders heading.",
|
|
40
|
+
"With multiple sections the center renders the controlled MobileSectionSwitcher.",
|
|
41
|
+
"Optional subsections render in a second row and emit dsSubsectionChange without changing the primary section.",
|
|
42
|
+
"Sections represent peer destinations at the current navigation level; subsections represent local views beneath the selected page or detail identity.",
|
|
43
|
+
"Brand tone changes surface and foreground without changing geometry or interaction ownership."
|
|
44
|
+
],
|
|
45
|
+
"responsiveBehavior": [
|
|
46
|
+
"The primary 48px lane is dedicated to the below-768px presentation; optional subsections add one subordinate 48px lane.",
|
|
47
|
+
"Equal flexible side lanes keep the center mathematically aligned when actions are asymmetric."
|
|
48
|
+
],
|
|
49
|
+
"references": [
|
|
50
|
+
{
|
|
51
|
+
"label": "Storybook",
|
|
52
|
+
"path": "src/wc/components/MobileHeader/MobileHeader.stories.ts"
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
},
|
|
56
|
+
"api": {
|
|
57
|
+
"props": {
|
|
58
|
+
"heading": {
|
|
59
|
+
"type": "string",
|
|
60
|
+
"resolvedType": "string",
|
|
61
|
+
"attribute": "heading",
|
|
62
|
+
"default": "''",
|
|
63
|
+
"required": false,
|
|
64
|
+
"mutable": false,
|
|
65
|
+
"description": "Static title used when no peer sections are supplied."
|
|
66
|
+
},
|
|
67
|
+
"headingLevel": {
|
|
68
|
+
"type": "MobileHeaderHeadingLevel",
|
|
69
|
+
"resolvedType": "\"h1\" | \"h2\"",
|
|
70
|
+
"attribute": "heading-level",
|
|
71
|
+
"default": "'h1'",
|
|
72
|
+
"required": false,
|
|
73
|
+
"mutable": false,
|
|
74
|
+
"description": "Semantic heading level for the active mobile screen."
|
|
75
|
+
},
|
|
76
|
+
"sections": {
|
|
77
|
+
"type": "TabItem[]",
|
|
78
|
+
"resolvedType": "TabItem[]",
|
|
79
|
+
"default": "[]",
|
|
80
|
+
"required": false,
|
|
81
|
+
"mutable": false,
|
|
82
|
+
"description": "Controlled peer sections. Their selected label replaces the static title."
|
|
83
|
+
},
|
|
84
|
+
"sectionsAriaLabel": {
|
|
85
|
+
"type": "string",
|
|
86
|
+
"resolvedType": "string",
|
|
87
|
+
"attribute": "sections-aria-label",
|
|
88
|
+
"default": "'Change page section'",
|
|
89
|
+
"required": false,
|
|
90
|
+
"mutable": false,
|
|
91
|
+
"description": "Accessible name for the section chooser."
|
|
92
|
+
},
|
|
93
|
+
"sectionsJson": {
|
|
94
|
+
"type": "string",
|
|
95
|
+
"resolvedType": "string",
|
|
96
|
+
"attribute": "sections-json",
|
|
97
|
+
"default": "''",
|
|
98
|
+
"required": false,
|
|
99
|
+
"mutable": false,
|
|
100
|
+
"description": "JSON fallback for `sections`."
|
|
101
|
+
},
|
|
102
|
+
"subsections": {
|
|
103
|
+
"type": "TabItem[]",
|
|
104
|
+
"resolvedType": "TabItem[]",
|
|
105
|
+
"default": "[]",
|
|
106
|
+
"required": false,
|
|
107
|
+
"mutable": false,
|
|
108
|
+
"description": "Controlled child sections within the selected page or detail screen."
|
|
109
|
+
},
|
|
110
|
+
"subsectionsAriaLabel": {
|
|
111
|
+
"type": "string",
|
|
112
|
+
"resolvedType": "string",
|
|
113
|
+
"attribute": "subsections-aria-label",
|
|
114
|
+
"default": "'Change page subsection'",
|
|
115
|
+
"required": false,
|
|
116
|
+
"mutable": false,
|
|
117
|
+
"description": "Accessible name for the child-section chooser."
|
|
118
|
+
},
|
|
119
|
+
"subsectionsJson": {
|
|
120
|
+
"type": "string",
|
|
121
|
+
"resolvedType": "string",
|
|
122
|
+
"attribute": "subsections-json",
|
|
123
|
+
"default": "''",
|
|
124
|
+
"required": false,
|
|
125
|
+
"mutable": false,
|
|
126
|
+
"description": "JSON fallback for `subsections`."
|
|
127
|
+
},
|
|
128
|
+
"subvalue": {
|
|
129
|
+
"type": "string",
|
|
130
|
+
"resolvedType": "string",
|
|
131
|
+
"attribute": "subvalue",
|
|
132
|
+
"default": "''",
|
|
133
|
+
"required": false,
|
|
134
|
+
"mutable": false,
|
|
135
|
+
"description": "Controlled selected child-section id."
|
|
136
|
+
},
|
|
137
|
+
"tone": {
|
|
138
|
+
"type": "MobileHeaderTone",
|
|
139
|
+
"resolvedType": "\"brand\" | \"default\"",
|
|
140
|
+
"attribute": "tone",
|
|
141
|
+
"default": "'default'",
|
|
142
|
+
"required": false,
|
|
143
|
+
"mutable": false,
|
|
144
|
+
"description": "Default page chrome or bold-brand workflow chrome."
|
|
145
|
+
},
|
|
146
|
+
"value": {
|
|
147
|
+
"type": "string",
|
|
148
|
+
"resolvedType": "string",
|
|
149
|
+
"attribute": "value",
|
|
150
|
+
"default": "''",
|
|
151
|
+
"required": false,
|
|
152
|
+
"mutable": false,
|
|
153
|
+
"description": "Controlled selected section id."
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
"events": [
|
|
157
|
+
{
|
|
158
|
+
"name": "dsSectionChange",
|
|
159
|
+
"detail": "string",
|
|
160
|
+
"bubbles": true,
|
|
161
|
+
"cancelable": true,
|
|
162
|
+
"composed": true,
|
|
163
|
+
"description": "Section selection intent."
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
"name": "dsSubsectionChange",
|
|
167
|
+
"detail": "string",
|
|
168
|
+
"bubbles": true,
|
|
169
|
+
"cancelable": true,
|
|
170
|
+
"composed": true,
|
|
171
|
+
"description": "Child-section selection intent."
|
|
172
|
+
}
|
|
173
|
+
],
|
|
174
|
+
"methods": [],
|
|
175
|
+
"slots": []
|
|
176
|
+
},
|
|
177
|
+
"props": {
|
|
178
|
+
"heading": {
|
|
179
|
+
"type": "string",
|
|
180
|
+
"resolvedType": "string",
|
|
181
|
+
"attribute": "heading",
|
|
182
|
+
"default": "''",
|
|
183
|
+
"required": false,
|
|
184
|
+
"mutable": false,
|
|
185
|
+
"description": "Static title used when no peer sections are supplied."
|
|
186
|
+
},
|
|
187
|
+
"headingLevel": {
|
|
188
|
+
"type": "MobileHeaderHeadingLevel",
|
|
189
|
+
"resolvedType": "\"h1\" | \"h2\"",
|
|
190
|
+
"attribute": "heading-level",
|
|
191
|
+
"default": "'h1'",
|
|
192
|
+
"required": false,
|
|
193
|
+
"mutable": false,
|
|
194
|
+
"description": "Semantic heading level for the active mobile screen."
|
|
195
|
+
},
|
|
196
|
+
"sections": {
|
|
197
|
+
"type": "TabItem[]",
|
|
198
|
+
"resolvedType": "TabItem[]",
|
|
199
|
+
"default": "[]",
|
|
200
|
+
"required": false,
|
|
201
|
+
"mutable": false,
|
|
202
|
+
"description": "Controlled peer sections. Their selected label replaces the static title."
|
|
203
|
+
},
|
|
204
|
+
"sectionsAriaLabel": {
|
|
205
|
+
"type": "string",
|
|
206
|
+
"resolvedType": "string",
|
|
207
|
+
"attribute": "sections-aria-label",
|
|
208
|
+
"default": "'Change page section'",
|
|
209
|
+
"required": false,
|
|
210
|
+
"mutable": false,
|
|
211
|
+
"description": "Accessible name for the section chooser."
|
|
212
|
+
},
|
|
213
|
+
"sectionsJson": {
|
|
214
|
+
"type": "string",
|
|
215
|
+
"resolvedType": "string",
|
|
216
|
+
"attribute": "sections-json",
|
|
217
|
+
"default": "''",
|
|
218
|
+
"required": false,
|
|
219
|
+
"mutable": false,
|
|
220
|
+
"description": "JSON fallback for `sections`."
|
|
221
|
+
},
|
|
222
|
+
"subsections": {
|
|
223
|
+
"type": "TabItem[]",
|
|
224
|
+
"resolvedType": "TabItem[]",
|
|
225
|
+
"default": "[]",
|
|
226
|
+
"required": false,
|
|
227
|
+
"mutable": false,
|
|
228
|
+
"description": "Controlled child sections within the selected page or detail screen."
|
|
229
|
+
},
|
|
230
|
+
"subsectionsAriaLabel": {
|
|
231
|
+
"type": "string",
|
|
232
|
+
"resolvedType": "string",
|
|
233
|
+
"attribute": "subsections-aria-label",
|
|
234
|
+
"default": "'Change page subsection'",
|
|
235
|
+
"required": false,
|
|
236
|
+
"mutable": false,
|
|
237
|
+
"description": "Accessible name for the child-section chooser."
|
|
238
|
+
},
|
|
239
|
+
"subsectionsJson": {
|
|
240
|
+
"type": "string",
|
|
241
|
+
"resolvedType": "string",
|
|
242
|
+
"attribute": "subsections-json",
|
|
243
|
+
"default": "''",
|
|
244
|
+
"required": false,
|
|
245
|
+
"mutable": false,
|
|
246
|
+
"description": "JSON fallback for `subsections`."
|
|
247
|
+
},
|
|
248
|
+
"subvalue": {
|
|
249
|
+
"type": "string",
|
|
250
|
+
"resolvedType": "string",
|
|
251
|
+
"attribute": "subvalue",
|
|
252
|
+
"default": "''",
|
|
253
|
+
"required": false,
|
|
254
|
+
"mutable": false,
|
|
255
|
+
"description": "Controlled selected child-section id."
|
|
256
|
+
},
|
|
257
|
+
"tone": {
|
|
258
|
+
"type": "MobileHeaderTone",
|
|
259
|
+
"resolvedType": "\"brand\" | \"default\"",
|
|
260
|
+
"attribute": "tone",
|
|
261
|
+
"default": "'default'",
|
|
262
|
+
"required": false,
|
|
263
|
+
"mutable": false,
|
|
264
|
+
"description": "Default page chrome or bold-brand workflow chrome."
|
|
265
|
+
},
|
|
266
|
+
"value": {
|
|
267
|
+
"type": "string",
|
|
268
|
+
"resolvedType": "string",
|
|
269
|
+
"attribute": "value",
|
|
270
|
+
"default": "''",
|
|
271
|
+
"required": false,
|
|
272
|
+
"mutable": false,
|
|
273
|
+
"description": "Controlled selected section id."
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
"events": [
|
|
277
|
+
{
|
|
278
|
+
"name": "dsSectionChange",
|
|
279
|
+
"detail": "string",
|
|
280
|
+
"bubbles": true,
|
|
281
|
+
"cancelable": true,
|
|
282
|
+
"composed": true,
|
|
283
|
+
"description": "Section selection intent."
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
"name": "dsSubsectionChange",
|
|
287
|
+
"detail": "string",
|
|
288
|
+
"bubbles": true,
|
|
289
|
+
"cancelable": true,
|
|
290
|
+
"composed": true,
|
|
291
|
+
"description": "Child-section selection intent."
|
|
292
|
+
}
|
|
293
|
+
],
|
|
294
|
+
"methods": [],
|
|
295
|
+
"slots": [],
|
|
296
|
+
"exports": {
|
|
297
|
+
"customElement": "ds-mobile-header",
|
|
298
|
+
"react": "DsMobileHeader",
|
|
299
|
+
"angular": "DsMobileHeader"
|
|
300
|
+
},
|
|
301
|
+
"consumption": {
|
|
302
|
+
"install": "npm install @ds-mo/ui @ds-mo/tokens @ds-mo/icons",
|
|
303
|
+
"cssSetup": "import '@ds-mo/tokens';\nimport '@ds-mo/tokens/reset';\nimport '@ds-mo/tokens/globals';",
|
|
304
|
+
"customElements": {
|
|
305
|
+
"import": "import '@ds-mo/ui/dist/components/ds-mobile-header.js';",
|
|
306
|
+
"example": "<ds-mobile-header></ds-mobile-header>"
|
|
307
|
+
},
|
|
308
|
+
"react": {
|
|
309
|
+
"import": "import { DsMobileHeader } from '@ds-mo/ui/react';",
|
|
310
|
+
"example": "<DsMobileHeader />"
|
|
311
|
+
},
|
|
312
|
+
"angular": {
|
|
313
|
+
"import": "import { DsMobileHeader } from '@ds-mo/ui/angular/ds-mobile-header';",
|
|
314
|
+
"example": "<ds-mobile-header></ds-mobile-header>"
|
|
315
|
+
},
|
|
316
|
+
"complexPropertyNote": "Assign these non-primitive values as JavaScript properties: sections, subsections.",
|
|
317
|
+
"peerDependencies": {
|
|
318
|
+
"required": [
|
|
319
|
+
"@ds-mo/tokens ^3.1.1",
|
|
320
|
+
"@ds-mo/icons ^6.4.0"
|
|
321
|
+
],
|
|
322
|
+
"frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
},
|
|
326
|
+
"dependencies": [
|
|
327
|
+
"@ds-mo/ui",
|
|
328
|
+
"@ds-mo/tokens"
|
|
329
|
+
],
|
|
330
|
+
"registryDependencies": [
|
|
331
|
+
"mobile-section-switcher",
|
|
332
|
+
"text"
|
|
333
|
+
],
|
|
334
|
+
"files": [
|
|
335
|
+
{
|
|
336
|
+
"path": "src/wc/components/MobileHeader/MobileHeader.css",
|
|
337
|
+
"content": ":host {\n display: block;\n min-width: 0;\n box-sizing: border-box;\n background: var(--color-background-primary);\n color: var(--color-foreground-primary);\n}\n\n:host([tone='brand']) {\n background: var(--color-background-bold-brand);\n color: var(--color-foreground-on-bold);\n}\n\n.mobile-header {\n position: relative;\n display: flex;\n flex-direction: column;\n width: 100%;\n min-width: 0;\n box-sizing: border-box;\n background: inherit;\n color: inherit;\n}\n\n.mobile-header__primary {\n display: grid;\n grid-template-columns: minmax(var(--dimension-size-400), 1fr) minmax(0, auto) minmax(var(--dimension-size-400), 1fr);\n align-items: center;\n gap: var(--dimension-space-050);\n width: 100%;\n height: var(--dimension-size-600);\n min-width: 0;\n padding: var(--dimension-space-100);\n box-sizing: border-box;\n background: inherit;\n color: inherit;\n}\n\n:host(:not([tone='brand'])) .mobile-header::after {\n content: '';\n position: absolute;\n inset-inline: 0;\n inset-block-end: 0;\n height: var(--dimension-stroke-width-012);\n background: var(--color-border-tertiary);\n pointer-events: none;\n}\n\n.mobile-header__subsections {\n display: flex;\n align-items: center;\n justify-content: center;\n min-width: 0;\n height: var(--dimension-size-600);\n padding: var(--dimension-space-100) var(--dimension-space-200);\n box-sizing: border-box;\n}\n\n.mobile-header__subsections ds-mobile-section-switcher {\n min-width: 0;\n max-width: 100%;\n}\n\n.mobile-header__lane {\n display: flex;\n align-items: center;\n gap: var(--dimension-space-050);\n min-width: 0;\n}\n\n.mobile-header__lane--leading {\n justify-content: flex-start;\n}\n\n.mobile-header__lane--trailing {\n justify-content: flex-end;\n}\n\n.mobile-header__center {\n position: relative;\n min-width: 0;\n max-width: 100%;\n justify-self: center;\n}\n\n.mobile-header__heading {\n display: block;\n min-width: 0;\n max-width: 100%;\n text-align: center;\n}\n\n.mobile-header__semantic-heading {\n position: absolute;\n width: var(--dimension-stroke-width-012);\n height: var(--dimension-stroke-width-012);\n padding: 0;\n margin: calc(var(--dimension-stroke-width-012) * -1);\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n}\n\n::slotted([slot='leading']),\n::slotted([slot='trailing']) {\n flex: 0 0 auto;\n}\n",
|
|
338
|
+
"type": "registry:ui"
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
"path": "src/wc/components/MobileHeader/MobileHeader.tsx",
|
|
342
|
+
"content": "import { Component, Event, EventEmitter, h, Host, Prop } from '@stencil/core';\nimport { getSelectableTabs, type TabItem } from '../TabGroup/tab-item-utils';\nimport type {\n MobileHeaderHeadingLevel,\n MobileHeaderTone,\n} from './mobile-header-types';\n\n@Component({\n tag: 'ds-mobile-header',\n styleUrl: 'MobileHeader.css',\n scoped: true,\n})\nexport class MobileHeader {\n /** Static title used when no peer sections are supplied. */\n @Prop() heading: string = '';\n /** Semantic heading level for the active mobile screen. */\n @Prop() headingLevel: MobileHeaderHeadingLevel = 'h1';\n /** Controlled peer sections. Their selected label replaces the static title. */\n @Prop() sections: TabItem[] = [];\n /** JSON fallback for `sections`. */\n @Prop({ attribute: 'sections-json' }) sectionsJson: string = '';\n /** Controlled selected section id. */\n @Prop() value: string = '';\n /** Accessible name for the section chooser. */\n @Prop() sectionsAriaLabel: string = 'Change page section';\n /** Controlled child sections within the selected page or detail screen. */\n @Prop() subsections: TabItem[] = [];\n /** JSON fallback for `subsections`. */\n @Prop({ attribute: 'subsections-json' }) subsectionsJson: string = '';\n /** Controlled selected child-section id. */\n @Prop() subvalue: string = '';\n /** Accessible name for the child-section chooser. */\n @Prop() subsectionsAriaLabel: string = 'Change page subsection';\n /** Default page chrome or bold-brand workflow chrome. */\n @Prop({ reflect: true }) tone: MobileHeaderTone = 'default';\n\n /** Section selection intent. */\n @Event() dsSectionChange!: EventEmitter<string>;\n /** Child-section selection intent. */\n @Event() dsSubsectionChange!: EventEmitter<string>;\n\n private parseSections(value: TabItem[], json: string): TabItem[] {\n if (!json.trim()) return value ?? [];\n try {\n const parsed = JSON.parse(json);\n return Array.isArray(parsed) ? (parsed as TabItem[]) : [];\n } catch {\n return [];\n }\n }\n\n private get resolvedSections(): TabItem[] {\n return this.parseSections(this.sections, this.sectionsJson);\n }\n\n private get resolvedSubsections(): TabItem[] {\n return this.parseSections(this.subsections, this.subsectionsJson);\n }\n\n private get selectedLabel(): string {\n const selectable = getSelectableTabs(this.resolvedSections);\n return selectable.find(section => section.id === this.value)?.label ??\n selectable[0]?.label ??\n this.heading;\n }\n\n private handleSectionChange = (event: CustomEvent<string>) => {\n event.stopPropagation();\n this.dsSectionChange.emit(event.detail);\n };\n\n private handleSubsectionChange = (event: CustomEvent<string>) => {\n event.stopPropagation();\n this.dsSubsectionChange.emit(event.detail);\n };\n\n render() {\n const Heading = this.headingLevel;\n const selectable = getSelectableTabs(this.resolvedSections);\n const hasSwitcher = selectable.length > 1;\n const hasSubsections = getSelectableTabs(this.resolvedSubsections).length > 1;\n const foreground = this.tone === 'brand' ? 'on-bold' : 'primary';\n\n return (\n <Host>\n <header class=\"mobile-header\">\n <div class=\"mobile-header__primary\">\n <div class=\"mobile-header__lane mobile-header__lane--leading\">\n <slot name=\"leading\" />\n </div>\n <div class=\"mobile-header__center\">\n {hasSwitcher ? (\n [\n <span\n class=\"mobile-header__semantic-heading\"\n role=\"heading\"\n aria-level={this.headingLevel === 'h1' ? '1' : '2'}\n >\n {this.selectedLabel}\n </span>,\n <ds-mobile-section-switcher\n sections={this.resolvedSections}\n value={this.value}\n navigationLabel={this.sectionsAriaLabel}\n onDsChange={this.handleSectionChange}\n />,\n ]\n ) : (\n <ds-text\n class=\"mobile-header__heading\"\n as={Heading}\n variant=\"text-body-medium\"\n emphasis\n color={foreground}\n lineTruncation={1}\n >\n {this.selectedLabel}\n </ds-text>\n )}\n </div>\n <div class=\"mobile-header__lane mobile-header__lane--trailing\">\n <slot name=\"trailing\" />\n </div>\n </div>\n {hasSubsections ? (\n <nav class=\"mobile-header__subsections\" aria-label={this.subsectionsAriaLabel}>\n <ds-mobile-section-switcher\n sections={this.resolvedSubsections}\n value={this.subvalue}\n navigationLabel={this.subsectionsAriaLabel}\n onDsChange={this.handleSubsectionChange}\n />\n </nav>\n ) : null}\n </header>\n </Host>\n );\n }\n}\n",
|
|
343
|
+
"type": "registry:ui"
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
"path": "src/wc/components/MobileHeader/mobile-header-types.ts",
|
|
347
|
+
"content": "import type { TabItem } from '../TabGroup/tab-item-utils';\n\nexport type MobileHeaderTone = 'default' | 'brand';\nexport type MobileHeaderHeadingLevel = 'h1' | 'h2';\nexport type MobileHeaderSectionItem = TabItem;\n\n",
|
|
348
|
+
"type": "registry:ui"
|
|
349
|
+
}
|
|
350
|
+
]
|
|
351
|
+
}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
3
|
+
"name": "mobile-section-switcher",
|
|
4
|
+
"title": "MobileSectionSwitcher",
|
|
5
|
+
"description": "Controlled mobile section chooser showing the current section, adjacent-position hints, and a complete tap menu.",
|
|
6
|
+
"type": "registry:ui",
|
|
7
|
+
"meta": {
|
|
8
|
+
"library": "@ds-mo/ui",
|
|
9
|
+
"distribution": "npm",
|
|
10
|
+
"storybook": "https://zainadeel.github.io/compomo/?path=/story/mobile-section-switcher",
|
|
11
|
+
"source": "src/wc/components/MobileSectionSwitcher/MobileSectionSwitcher.tsx",
|
|
12
|
+
"intentStatus": "complete",
|
|
13
|
+
"intent": {
|
|
14
|
+
"audience": "specialized",
|
|
15
|
+
"status": "experimental",
|
|
16
|
+
"summary": "Controlled mobile section chooser showing the current section, adjacent-position hints, and a complete tap menu.",
|
|
17
|
+
"useWhen": [
|
|
18
|
+
"A mobile page or tool header must combine current-page identity with ordered peer-section navigation."
|
|
19
|
+
],
|
|
20
|
+
"avoidWhen": [
|
|
21
|
+
"Rendering desktop BarNav.",
|
|
22
|
+
"The destination collection is primary application navigation."
|
|
23
|
+
],
|
|
24
|
+
"commonlyComposedWith": [
|
|
25
|
+
"component:ds-mobile-header"
|
|
26
|
+
],
|
|
27
|
+
"patterns": [
|
|
28
|
+
"pattern:application-shell"
|
|
29
|
+
],
|
|
30
|
+
"accessibility": [
|
|
31
|
+
"The trigger exposes the current section, popup relationship, and expanded state.",
|
|
32
|
+
"Decorative previous and next position hints are hidden from assistive technology.",
|
|
33
|
+
"The menu is always available so a future swipe gesture is never the only navigation mechanism."
|
|
34
|
+
],
|
|
35
|
+
"states": [
|
|
36
|
+
"Selection is controlled and dsChange reports intent without mutating value.",
|
|
37
|
+
"Dividers group menu items but never participate in previous or next resolution.",
|
|
38
|
+
"The first and last selectable sections expose only the available neighboring direction."
|
|
39
|
+
],
|
|
40
|
+
"responsiveBehavior": [
|
|
41
|
+
"Use only in the dedicated mobile header presentation."
|
|
42
|
+
],
|
|
43
|
+
"references": [
|
|
44
|
+
{
|
|
45
|
+
"label": "Storybook",
|
|
46
|
+
"path": "src/wc/components/MobileSectionSwitcher/MobileSectionSwitcher.stories.ts"
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
"api": {
|
|
51
|
+
"props": {
|
|
52
|
+
"navigationLabel": {
|
|
53
|
+
"type": "string",
|
|
54
|
+
"resolvedType": "string",
|
|
55
|
+
"attribute": "navigation-label",
|
|
56
|
+
"default": "'Change page section'",
|
|
57
|
+
"required": false,
|
|
58
|
+
"mutable": false,
|
|
59
|
+
"description": "Accessible name for the section chooser."
|
|
60
|
+
},
|
|
61
|
+
"sections": {
|
|
62
|
+
"type": "TabItem[]",
|
|
63
|
+
"resolvedType": "TabItem[]",
|
|
64
|
+
"default": "[]",
|
|
65
|
+
"required": false,
|
|
66
|
+
"mutable": false,
|
|
67
|
+
"description": "Ordered controlled sections. Divider entries group the popup menu."
|
|
68
|
+
},
|
|
69
|
+
"sectionsJson": {
|
|
70
|
+
"type": "string",
|
|
71
|
+
"resolvedType": "string",
|
|
72
|
+
"attribute": "sections-json",
|
|
73
|
+
"default": "''",
|
|
74
|
+
"required": false,
|
|
75
|
+
"mutable": false,
|
|
76
|
+
"description": "JSON fallback for `sections`."
|
|
77
|
+
},
|
|
78
|
+
"value": {
|
|
79
|
+
"type": "string",
|
|
80
|
+
"resolvedType": "string",
|
|
81
|
+
"attribute": "value",
|
|
82
|
+
"default": "''",
|
|
83
|
+
"required": false,
|
|
84
|
+
"mutable": false,
|
|
85
|
+
"description": "Controlled selected section id."
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
"events": [
|
|
89
|
+
{
|
|
90
|
+
"name": "dsChange",
|
|
91
|
+
"detail": "string",
|
|
92
|
+
"bubbles": true,
|
|
93
|
+
"cancelable": true,
|
|
94
|
+
"composed": true,
|
|
95
|
+
"description": "Selection intent. The route, tool, or workflow owner updates `value`."
|
|
96
|
+
}
|
|
97
|
+
],
|
|
98
|
+
"methods": [],
|
|
99
|
+
"slots": []
|
|
100
|
+
},
|
|
101
|
+
"props": {
|
|
102
|
+
"navigationLabel": {
|
|
103
|
+
"type": "string",
|
|
104
|
+
"resolvedType": "string",
|
|
105
|
+
"attribute": "navigation-label",
|
|
106
|
+
"default": "'Change page section'",
|
|
107
|
+
"required": false,
|
|
108
|
+
"mutable": false,
|
|
109
|
+
"description": "Accessible name for the section chooser."
|
|
110
|
+
},
|
|
111
|
+
"sections": {
|
|
112
|
+
"type": "TabItem[]",
|
|
113
|
+
"resolvedType": "TabItem[]",
|
|
114
|
+
"default": "[]",
|
|
115
|
+
"required": false,
|
|
116
|
+
"mutable": false,
|
|
117
|
+
"description": "Ordered controlled sections. Divider entries group the popup menu."
|
|
118
|
+
},
|
|
119
|
+
"sectionsJson": {
|
|
120
|
+
"type": "string",
|
|
121
|
+
"resolvedType": "string",
|
|
122
|
+
"attribute": "sections-json",
|
|
123
|
+
"default": "''",
|
|
124
|
+
"required": false,
|
|
125
|
+
"mutable": false,
|
|
126
|
+
"description": "JSON fallback for `sections`."
|
|
127
|
+
},
|
|
128
|
+
"value": {
|
|
129
|
+
"type": "string",
|
|
130
|
+
"resolvedType": "string",
|
|
131
|
+
"attribute": "value",
|
|
132
|
+
"default": "''",
|
|
133
|
+
"required": false,
|
|
134
|
+
"mutable": false,
|
|
135
|
+
"description": "Controlled selected section id."
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
"events": [
|
|
139
|
+
{
|
|
140
|
+
"name": "dsChange",
|
|
141
|
+
"detail": "string",
|
|
142
|
+
"bubbles": true,
|
|
143
|
+
"cancelable": true,
|
|
144
|
+
"composed": true,
|
|
145
|
+
"description": "Selection intent. The route, tool, or workflow owner updates `value`."
|
|
146
|
+
}
|
|
147
|
+
],
|
|
148
|
+
"methods": [],
|
|
149
|
+
"slots": [],
|
|
150
|
+
"exports": {
|
|
151
|
+
"customElement": "ds-mobile-section-switcher",
|
|
152
|
+
"react": "DsMobileSectionSwitcher",
|
|
153
|
+
"angular": "DsMobileSectionSwitcher"
|
|
154
|
+
},
|
|
155
|
+
"consumption": {
|
|
156
|
+
"install": "npm install @ds-mo/ui @ds-mo/tokens @ds-mo/icons",
|
|
157
|
+
"cssSetup": "import '@ds-mo/tokens';\nimport '@ds-mo/tokens/reset';\nimport '@ds-mo/tokens/globals';",
|
|
158
|
+
"customElements": {
|
|
159
|
+
"import": "import '@ds-mo/ui/dist/components/ds-mobile-section-switcher.js';",
|
|
160
|
+
"example": "<ds-mobile-section-switcher></ds-mobile-section-switcher>"
|
|
161
|
+
},
|
|
162
|
+
"react": {
|
|
163
|
+
"import": "import { DsMobileSectionSwitcher } from '@ds-mo/ui/react';",
|
|
164
|
+
"example": "<DsMobileSectionSwitcher />"
|
|
165
|
+
},
|
|
166
|
+
"angular": {
|
|
167
|
+
"import": "import { DsMobileSectionSwitcher } from '@ds-mo/ui/angular/ds-mobile-section-switcher';",
|
|
168
|
+
"example": "<ds-mobile-section-switcher></ds-mobile-section-switcher>"
|
|
169
|
+
},
|
|
170
|
+
"complexPropertyNote": "Assign these non-primitive values as JavaScript properties: sections.",
|
|
171
|
+
"peerDependencies": {
|
|
172
|
+
"required": [
|
|
173
|
+
"@ds-mo/tokens ^3.1.1",
|
|
174
|
+
"@ds-mo/icons ^6.4.0"
|
|
175
|
+
],
|
|
176
|
+
"frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
"dependencies": [
|
|
181
|
+
"@ds-mo/ui",
|
|
182
|
+
"@ds-mo/tokens"
|
|
183
|
+
],
|
|
184
|
+
"registryDependencies": [
|
|
185
|
+
"menu",
|
|
186
|
+
"text"
|
|
187
|
+
],
|
|
188
|
+
"files": [
|
|
189
|
+
{
|
|
190
|
+
"path": "src/wc/components/MobileSectionSwitcher/MobileSectionSwitcher.css",
|
|
191
|
+
"content": "@import '../../utils/focus-ring.css';\n@import '../../utils/interaction-fill.css';\n\n:host {\n display: block;\n min-width: 0;\n max-width: 100%;\n color: var(--color-foreground-primary);\n}\n\n.mobile-section-switcher {\n appearance: none;\n display: grid;\n grid-template-columns: var(--dimension-size-100) minmax(0, auto) var(--dimension-size-100);\n align-items: center;\n justify-content: center;\n gap: var(--dimension-space-050);\n max-width: 100%;\n min-height: var(--dimension-size-400);\n padding-inline: var(--dimension-space-100);\n border: 0;\n border-radius: var(--dimension-radius-100);\n background: var(--color-background-secondary);\n color: inherit;\n box-sizing: border-box;\n cursor: pointer;\n}\n\n.mobile-section-switcher--expanded {\n background: var(--color-background-tertiary);\n}\n\n.mobile-section-switcher__label {\n min-width: 0;\n max-width: 100%;\n text-align: center;\n}\n\n.mobile-section-switcher__position {\n width: var(--dimension-size-050);\n height: var(--dimension-size-050);\n border-radius: var(--dimension-radius-half);\n background: currentColor;\n opacity: 0;\n}\n\n.mobile-section-switcher__position--visible {\n opacity: 1;\n}\n",
|
|
192
|
+
"type": "registry:ui"
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
"path": "src/wc/components/MobileSectionSwitcher/MobileSectionSwitcher.tsx",
|
|
196
|
+
"content": "import {\n Component,\n Element,\n Event,\n EventEmitter,\n h,\n Host,\n Prop,\n State,\n Watch,\n} from '@stencil/core';\nimport type { MenuItemData, MenuSection } from '../Menu/menu-types';\nimport {\n getSelectableTabs,\n isTabDivider,\n type TabItem,\n type TabItemTab,\n} from '../TabGroup/tab-item-utils';\nimport { resolveMobileSectionPosition } from './mobile-section-switcher-utils';\n\nlet nextMobileSectionSwitcherId = 0;\n\n@Component({\n tag: 'ds-mobile-section-switcher',\n styleUrl: 'MobileSectionSwitcher.css',\n scoped: true,\n})\nexport class MobileSectionSwitcher {\n @Element() el!: HTMLElement;\n\n /** Ordered controlled sections. Divider entries group the popup menu. */\n @Prop() sections: TabItem[] = [];\n /** JSON fallback for `sections`. */\n @Prop({ attribute: 'sections-json' }) sectionsJson: string = '';\n /** Controlled selected section id. */\n @Prop() value: string = '';\n /** Accessible name for the section chooser. */\n @Prop() navigationLabel: string = 'Change page section';\n\n /** Selection intent. The route, tool, or workflow owner updates `value`. */\n @Event() dsChange!: EventEmitter<string>;\n\n @State() private menuOpen = false;\n @State() private initialFocusVisible = false;\n\n private readonly instanceId = nextMobileSectionSwitcherId++;\n private readonly triggerId = `ds-mobile-section-switcher-trigger-${this.instanceId}`;\n private readonly menuId = `ds-mobile-section-switcher-menu-${this.instanceId}`;\n private triggerEl: HTMLButtonElement | null = null;\n\n private get resolvedSections(): TabItem[] {\n if (!this.sectionsJson.trim()) return this.sections ?? [];\n try {\n const parsed = JSON.parse(this.sectionsJson);\n return Array.isArray(parsed) ? (parsed as TabItem[]) : [];\n } catch {\n return [];\n }\n }\n\n private get selectableSections(): TabItemTab[] {\n return getSelectableTabs(this.resolvedSections);\n }\n\n private get selectedIndex(): number {\n return resolveMobileSectionPosition(this.resolvedSections, this.value).selectedIndex;\n }\n\n private get selectedSection(): TabItemTab | undefined {\n return this.selectableSections[this.selectedIndex];\n }\n\n private get hasPrevious(): boolean {\n return resolveMobileSectionPosition(this.resolvedSections, this.value).hasPrevious;\n }\n\n private get hasNext(): boolean {\n return resolveMobileSectionPosition(this.resolvedSections, this.value).hasNext;\n }\n\n private get triggerAriaLabel(): string {\n return `${this.navigationLabel}. Current section: ${this.selectedSection?.label ?? ''}`;\n }\n\n private get menuSections(): MenuSection[] {\n const groups: MenuSection[] = [];\n let items: MenuItemData[] = [];\n const commit = () => {\n if (items.length) groups.push({ items });\n items = [];\n };\n\n for (const section of this.resolvedSections) {\n if (isTabDivider(section)) {\n commit();\n continue;\n }\n items.push({\n label: section.label,\n value: section.id,\n dot: section.dot,\n isSelected: section.id === this.selectedSection?.id,\n isInactive: section.isInactive,\n });\n }\n commit();\n return groups;\n }\n\n @Watch('sections')\n @Watch('sectionsJson')\n handleSectionsChange() {\n if (this.selectableSections.length <= 1) this.closeMenu();\n }\n\n private toggleMenu = (event: MouseEvent) => {\n if (this.selectableSections.length <= 1) return;\n this.initialFocusVisible = event.detail === 0;\n this.menuOpen = !this.menuOpen;\n };\n\n private closeMenu = () => {\n this.menuOpen = false;\n };\n\n private handleSelect = (event: CustomEvent<MenuItemData>) => {\n const id = String(event.detail.value ?? '');\n const section = this.selectableSections.find(candidate => candidate.id === id);\n if (!section || section.isInactive) return;\n this.closeMenu();\n if (id !== this.selectedSection?.id) this.dsChange.emit(id);\n requestAnimationFrame(() => this.triggerEl?.focus());\n };\n\n render() {\n const selected = this.selectedSection;\n if (!selected) return <Host />;\n\n return (\n <Host>\n <button\n ref={element => {\n this.triggerEl = element ?? null;\n }}\n id={this.triggerId}\n class={{\n 'mobile-section-switcher': true,\n 'mobile-section-switcher--expanded': this.menuOpen,\n 'ds-focus-ring-inset': true,\n 'ds-interaction-fill': true,\n }}\n type=\"button\"\n aria-haspopup=\"menu\"\n aria-controls={this.menuId}\n aria-expanded={String(this.menuOpen)}\n aria-label={this.triggerAriaLabel}\n onClick={this.toggleMenu}\n >\n <span\n class={{\n 'mobile-section-switcher__position': true,\n 'mobile-section-switcher__position--visible': this.hasPrevious,\n 'ds-interaction-fill__content': true,\n }}\n aria-hidden=\"true\"\n />\n <ds-text\n class=\"mobile-section-switcher__label ds-interaction-fill__content\"\n as=\"span\"\n variant=\"text-body-medium\"\n emphasis\n color=\"inherit\"\n lineTruncation={1}\n >\n {selected.label}\n </ds-text>\n <span\n class={{\n 'mobile-section-switcher__position': true,\n 'mobile-section-switcher__position--visible': this.hasNext,\n 'ds-interaction-fill__content': true,\n }}\n aria-hidden=\"true\"\n />\n </button>\n\n {this.selectableSections.length > 1 ? (\n <ds-menu\n id={this.menuId}\n anchorId={this.triggerId}\n align=\"center\"\n selectionMode=\"single\"\n menuLabel={this.navigationLabel}\n open={this.menuOpen}\n initialFocusVisible={this.initialFocusVisible}\n sections={this.menuSections}\n onDsClose={this.closeMenu}\n onDsSelect={this.handleSelect}\n />\n ) : null}\n </Host>\n );\n }\n}\n",
|
|
197
|
+
"type": "registry:ui"
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
"path": "src/wc/components/MobileSectionSwitcher/mobile-section-switcher-types.ts",
|
|
201
|
+
"content": "import type { TabItem } from '../TabGroup/tab-item-utils';\n\n/** Ordered mobile sections. Dividers group the tap menu but do not participate in selection. */\nexport type MobileSectionItem = TabItem;\n\n",
|
|
202
|
+
"type": "registry:ui"
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
"path": "src/wc/components/MobileSectionSwitcher/mobile-section-switcher-utils.ts",
|
|
206
|
+
"content": "import { getSelectableTabs, type TabItem, type TabItemTab } from '../TabGroup/tab-item-utils';\n\nexport interface MobileSectionPosition {\n selectedIndex: number;\n selected?: TabItemTab;\n hasPrevious: boolean;\n hasNext: boolean;\n}\n\n/** Resolve ordered selectable neighbors while ignoring visual divider entries. */\nexport function resolveMobileSectionPosition(\n sections: TabItem[],\n value: string\n): MobileSectionPosition {\n const selectable = getSelectableTabs(sections);\n const matchedIndex = selectable.findIndex(section => section.id === value);\n const selectedIndex = matchedIndex >= 0 ? matchedIndex : 0;\n return {\n selectedIndex,\n selected: selectable[selectedIndex],\n hasPrevious: selectedIndex > 0,\n hasNext: selectedIndex < selectable.length - 1,\n };\n}\n\n",
|
|
207
|
+
"type": "registry:ui"
|
|
208
|
+
}
|
|
209
|
+
]
|
|
210
|
+
}
|