@ds-mo/ui 11.0.0 → 12.0.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 +1 -1
- package/dist/.build-stamp +1 -1
- package/dist/agent-patterns.json +150 -9
- package/dist/agent.json +940 -220
- package/dist/angular/ds-bar-title.d.ts +28 -0
- package/dist/angular/ds-bar-title.js +48 -0
- package/dist/angular/ds-button-filled.d.ts +1 -1
- package/dist/angular/ds-button-filled.js +3 -3
- package/dist/angular/ds-chart-donut.d.ts +1 -1
- package/dist/angular/ds-chart-donut.js +3 -3
- package/dist/angular/ds-panel-nav.d.ts +1 -1
- package/dist/angular/{ds-app-shell.d.ts → ds-shell-app.d.ts} +5 -5
- package/dist/angular/{ds-app-shell.js → ds-shell-app.js} +10 -10
- package/dist/angular/ds-shell-page.d.ts +12 -0
- package/dist/angular/ds-shell-page.js +38 -0
- package/dist/angular/index.d.ts +1 -1
- package/dist/angular/index.js +3 -1
- package/dist/angular/proxies.d.ts +3 -1
- package/dist/angular/proxies.js +3 -1
- package/dist/components/ds-agent-activity.js +1 -1
- package/dist/components/ds-agent-response.js +1 -1
- package/dist/components/ds-agent-response.js.map +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-app-shell.d.ts → ds-bar-title.d.ts} +4 -4
- package/dist/components/ds-bar-title.js +2 -0
- package/dist/components/ds-bar-title.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-donut.js +1 -1
- package/dist/components/ds-card-data-viz-donut.js.map +1 -1
- 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.js +1 -1
- package/dist/components/ds-chart-donut.js +1 -1
- package/dist/components/ds-chart-donut.js.map +1 -1
- package/dist/components/ds-chart-legend.js +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-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.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-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-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-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-panel-tools.js.map +1 -1
- package/dist/components/ds-radio.js +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.d.ts +11 -0
- package/dist/components/ds-shell-app.js +2 -0
- package/dist/components/ds-shell-app.js.map +1 -0
- 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-page.d.ts +11 -0
- package/dist/components/ds-shell-page.js +2 -0
- package/dist/components/ds-shell-page.js.map +1 -0
- 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-tag.js +1 -1
- package/dist/components/ds-text.js +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-data-viz.js.map +1 -1
- package/dist/components/ds-tooltip.js +1 -1
- package/dist/components/ds-typing-indicator.js +1 -1
- package/dist/components/{p-DJ78wdNv.js → p-6vj4kh70.js} +2 -2
- package/dist/components/p-B3YvoGjS.js +2 -0
- package/dist/components/p-B3YvoGjS.js.map +1 -0
- package/dist/components/{p-BEWtqFX7.js → p-BH3es4p7.js} +2 -2
- package/dist/components/p-BUmDHPr3.js +2 -0
- package/dist/components/p-BUmDHPr3.js.map +1 -0
- package/dist/components/p-BYHKdFzV.js +2 -0
- package/dist/components/p-BYHKdFzV.js.map +1 -0
- package/dist/components/p-BZZwQfmN.js +2 -0
- package/dist/components/{p-CbckeueL.js.map → p-BZZwQfmN.js.map} +1 -1
- package/dist/components/{p-Dh4q5TSS.js → p-BhKhX1er.js} +2 -2
- package/dist/components/{p-CZZYGqKz.js → p-Bs6SS34m.js} +2 -2
- package/dist/components/p-CUik7PCi.js +2 -0
- package/dist/components/p-CUik7PCi.js.map +1 -0
- package/dist/components/{p-M5pt9I13.js → p-Cf-i-6aE.js} +2 -2
- package/dist/components/{p-C8e2A66f.js → p-Cf2J9MEo.js} +2 -2
- package/dist/components/{p-bDx_rlLm.js → p-CwTVEAl2.js} +2 -2
- package/dist/components/p-Cy04lXlc.js +2 -0
- package/dist/components/p-Cy04lXlc.js.map +1 -0
- package/dist/components/{p-BKhG2xrW.js → p-D2x17ei-.js} +1 -1
- package/dist/components/{p-BKhG2xrW.js.map → p-D2x17ei-.js.map} +1 -1
- package/dist/components/{p-CjP8sYlo.js → p-DABj3qTX.js} +2 -2
- package/dist/components/{p-DTqCBjUj.js → p-DUHcJWTQ.js} +2 -2
- package/dist/components/{p-CPPAndX2.js → p-DVk0wxxX.js} +2 -2
- package/dist/components/p-DfIch2Dk.js +2 -0
- package/dist/components/{p-BMwnjAIq.js.map → p-DfIch2Dk.js.map} +1 -1
- 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-DrDHC7V6.js → p-DxeHimqk.js} +2 -2
- package/dist/components/{p-DrDHC7V6.js.map → p-DxeHimqk.js.map} +1 -1
- package/dist/components/{p-CLn7QnE0.js → p-Dy_sZ-dI.js} +2 -2
- package/dist/components/{p-0kEg-Z4f.js → p-liMPkhUP.js} +2 -2
- package/dist/components/p-xFbUt9Tc.js +2 -0
- package/dist/components/p-xFbUt9Tc.js.map +1 -0
- package/dist/docs/components.json +1139 -255
- package/dist/lib/shell/chrome-transition.d.ts +1 -1
- package/dist/lib/shell/index.js +1 -1
- package/dist/lib/shell/index.js.map +1 -1
- package/dist/lib/shell/shell-gradient.d.ts +2 -2
- package/dist/mcp/cli.js +8 -12
- package/dist/mcp-data/registry/avatar.json +1 -1
- package/dist/mcp-data/registry/badge.json +4 -4
- package/dist/mcp-data/registry/bar-nav.json +8 -8
- package/dist/mcp-data/registry/bar-title.json +431 -0
- package/dist/mcp-data/registry/button-filled.json +38 -2
- package/dist/mcp-data/registry/card-data-viz-donut.json +73 -4
- package/dist/mcp-data/registry/chart-bar.json +67 -3
- package/dist/mcp-data/registry/chart-donut.json +94 -8
- package/dist/mcp-data/registry/chart-legend.json +73 -3
- package/dist/mcp-data/registry/chart-line.json +67 -3
- package/dist/mcp-data/registry/code-block.json +4 -3
- package/dist/mcp-data/registry/menu.json +1 -1
- package/dist/mcp-data/registry/message-composer.json +7 -5
- package/dist/mcp-data/registry/message-scroller.json +4 -3
- package/dist/mcp-data/registry/modal.json +5 -4
- package/dist/mcp-data/registry/panel-nav.json +8 -8
- package/dist/mcp-data/registry/panel-sub-nav.json +1 -1
- package/dist/mcp-data/registry/panel-tool-header.json +4 -3
- package/dist/mcp-data/registry/panel-tool-search.json +6 -5
- package/dist/mcp-data/registry/panel-tools.json +13 -13
- package/dist/mcp-data/registry/registry.json +921 -195
- package/dist/mcp-data/registry/select-multi.json +2 -1
- package/dist/mcp-data/registry/select.json +2 -1
- package/dist/mcp-data/registry/shell-app.json +213 -0
- package/dist/mcp-data/registry/shell-gradient-picker.json +8 -8
- package/dist/mcp-data/registry/shell-gradient-swatch.json +2 -2
- package/dist/mcp-data/registry/shell-page.json +199 -0
- package/dist/mcp-data/registry/swatch-picker.json +1 -1
- package/dist/mcp-data/registry/tooltip-data-viz.json +68 -4
- package/dist/react/components.d.ts +3 -1
- package/dist/react/components.js +3 -1
- package/dist/react/ds-bar-title.d.ts +14 -0
- package/dist/react/ds-bar-title.js +16 -0
- package/dist/react/{ds-app-shell.d.ts → ds-shell-app.d.ts} +3 -3
- package/dist/react/ds-shell-app.js +12 -0
- package/dist/react/ds-shell-page.d.ts +9 -0
- package/dist/react/ds-shell-page.js +12 -0
- package/dist/types/components/Badge/Badge.d.ts +1 -1
- package/dist/types/components/BarTitle/BarTitle.d.ts +71 -0
- package/dist/types/components/BarTitle/bar-title-types.d.ts +29 -0
- package/dist/types/components/BarTitle/index.d.ts +2 -0
- package/dist/types/components/ButtonFilled/ButtonFilled.d.ts +9 -0
- package/dist/types/components/ButtonFilled/index.d.ts +1 -1
- package/dist/types/components/CardDataVizDonut/CardDataVizDonut.d.ts +1 -0
- package/dist/types/components/ChartDonut/ChartDonut.d.ts +12 -2
- package/dist/types/components/Menu/Menu.d.ts +5 -0
- package/dist/types/components/PanelNav/PanelNav.d.ts +1 -1
- package/dist/types/components/{AppShell/AppShell.d.ts → ShellApp/ShellApp.d.ts} +3 -3
- package/dist/types/components/ShellPage/ShellPage.d.ts +37 -0
- package/dist/types/components/ShellPage/index.d.ts +3 -0
- package/dist/types/components/ShellPage/shell-page-responsive.d.ts +12 -0
- package/dist/types/components/ShellPage/shell-page-types.d.ts +5 -0
- package/dist/types/components/TooltipDataViz/TooltipDataViz.d.ts +3 -2
- package/dist/types/components.d.ts +314 -67
- package/dist/types/shell/chrome-transition.d.ts +1 -1
- package/dist/types/shell/shell-gradient.d.ts +2 -2
- package/dist/types/shell/shell-shortcuts.d.ts +1 -1
- package/package.json +1 -1
- package/dist/components/ds-app-shell.js +0 -2
- package/dist/components/ds-app-shell.js.map +0 -1
- package/dist/components/p-BHtg1fh3.js +0 -2
- package/dist/components/p-BHtg1fh3.js.map +0 -1
- package/dist/components/p-BMwnjAIq.js +0 -2
- package/dist/components/p-C3nDIMX5.js +0 -2
- package/dist/components/p-C3nDIMX5.js.map +0 -1
- package/dist/components/p-CKaJx0IX.js +0 -2
- package/dist/components/p-CKaJx0IX.js.map +0 -1
- package/dist/components/p-CTFBf97-.js +0 -2
- package/dist/components/p-CTFBf97-.js.map +0 -1
- package/dist/components/p-C_0Q8Cnp.js +0 -2
- package/dist/components/p-CbckeueL.js +0 -2
- package/dist/components/p-DirD-b2y.js +0 -2
- package/dist/components/p-DirD-b2y.js.map +0 -1
- package/dist/components/p-Hw-HMjCk.js +0 -2
- package/dist/components/p-Hw-HMjCk.js.map +0 -1
- package/dist/mcp-data/registry/app-shell.json +0 -210
- package/dist/react/ds-app-shell.js +0 -12
- /package/dist/components/{p-DJ78wdNv.js.map → p-6vj4kh70.js.map} +0 -0
- /package/dist/components/{p-BEWtqFX7.js.map → p-BH3es4p7.js.map} +0 -0
- /package/dist/components/{p-Dh4q5TSS.js.map → p-BhKhX1er.js.map} +0 -0
- /package/dist/components/{p-CZZYGqKz.js.map → p-Bs6SS34m.js.map} +0 -0
- /package/dist/components/{p-M5pt9I13.js.map → p-Cf-i-6aE.js.map} +0 -0
- /package/dist/components/{p-C8e2A66f.js.map → p-Cf2J9MEo.js.map} +0 -0
- /package/dist/components/{p-bDx_rlLm.js.map → p-CwTVEAl2.js.map} +0 -0
- /package/dist/components/{p-CjP8sYlo.js.map → p-DABj3qTX.js.map} +0 -0
- /package/dist/components/{p-DTqCBjUj.js.map → p-DUHcJWTQ.js.map} +0 -0
- /package/dist/components/{p-CPPAndX2.js.map → p-DVk0wxxX.js.map} +0 -0
- /package/dist/components/{p-CLn7QnE0.js.map → p-Dy_sZ-dI.js.map} +0 -0
- /package/dist/components/{p-0kEg-Z4f.js.map → p-liMPkhUP.js.map} +0 -0
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
3
|
+
"name": "bar-title",
|
|
4
|
+
"title": "BarTitle",
|
|
5
|
+
"description": "Page-level title chrome with optional Back navigation, supporting description, inline active-section menu, one primary action, grouped overflow actions, and explicit expanded, compact, or constrained variants.",
|
|
6
|
+
"type": "registry:ui",
|
|
7
|
+
"meta": {
|
|
8
|
+
"library": "@ds-mo/ui",
|
|
9
|
+
"distribution": "npm",
|
|
10
|
+
"storybook": "https://zainadeel.github.io/compomo/?path=/story/bar-title",
|
|
11
|
+
"source": "src/wc/components/BarTitle/BarTitle.tsx",
|
|
12
|
+
"intentStatus": "complete",
|
|
13
|
+
"intent": {
|
|
14
|
+
"audience": "general",
|
|
15
|
+
"status": "stable",
|
|
16
|
+
"summary": "Page-level title chrome with optional Back navigation, supporting description, inline active-section menu, one primary action, grouped overflow actions, and explicit expanded, compact, or constrained variants.",
|
|
17
|
+
"useWhen": [
|
|
18
|
+
"A top-level page needs one h1 above its content.",
|
|
19
|
+
"A list or detail page has multiple route-level sections that belong in the inline active-section menu.",
|
|
20
|
+
"A detail, create, or edit page needs a page-level Back action.",
|
|
21
|
+
"A page needs one primary action plus optional secondary or destructive overflow commands."
|
|
22
|
+
],
|
|
23
|
+
"avoidWhen": [
|
|
24
|
+
"The title belongs to a PanelTools drawer or fullscreen pane; use PanelToolHeader through PanelTools instead.",
|
|
25
|
+
"The choices are primary application destinations or BarNav destinations rather than sections within the current page.",
|
|
26
|
+
"The heading belongs to a card, modal, or other bounded region rather than the page.",
|
|
27
|
+
"Local panels inside page content should remain directly selectable; use TabGroup instead.",
|
|
28
|
+
"Automatic sticky or responsive page orchestration is required; compose BarTitle in ShellPage rather than implementing it in the header."
|
|
29
|
+
],
|
|
30
|
+
"alternatives": [
|
|
31
|
+
{
|
|
32
|
+
"when": "The header belongs to a PanelTools product view.",
|
|
33
|
+
"component": "component:ds-panel-tool-header",
|
|
34
|
+
"reason": "PanelToolHeader owns pane-level Back and actions without creating page chrome."
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"when": "A small set of inner-page panels should remain visible as tabs.",
|
|
38
|
+
"component": "component:ds-tab-group",
|
|
39
|
+
"reason": "TabGroup is the local content-view control rather than route-level page title chrome."
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
"commonlyComposedWith": [
|
|
43
|
+
"component:ds-shell-page",
|
|
44
|
+
"component:ds-button-filled",
|
|
45
|
+
"component:ds-button-unfilled",
|
|
46
|
+
"component:ds-menu",
|
|
47
|
+
"component:ds-text"
|
|
48
|
+
],
|
|
49
|
+
"patterns": [
|
|
50
|
+
"pattern:shell-page"
|
|
51
|
+
],
|
|
52
|
+
"accessibility": [
|
|
53
|
+
"Provide one concise heading; BarTitle renders exactly one h1 and changes only its visual recipe between variants.",
|
|
54
|
+
"Give Back a destination-specific accessible name such as Back to Drivers, provide the concise parent label such as Drivers for the expanded breadcrumb, and handle dsBack in the route owner.",
|
|
55
|
+
"Keep value synchronized with the current child route; dsSectionChange returns the selected section id.",
|
|
56
|
+
"Section and overflow triggers expose menu relationships and restore focus after selection or dismissal.",
|
|
57
|
+
"Use one filled primary action in the page decision area and mark destructive overflow actions explicitly."
|
|
58
|
+
],
|
|
59
|
+
"states": [
|
|
60
|
+
"Omitting Back, sections, primaryAction, and actions produces the top-level title-only header.",
|
|
61
|
+
"Two or more selectable sections add the inline section trigger; one section does not render a redundant menu.",
|
|
62
|
+
"Dividers in sections or actions create separate Menu groups without becoming selectable rows.",
|
|
63
|
+
"expanded renders the larger heading, optional description, inset divider, and an xs icon-label Back breadcrumb above a flush-left h1; compact renders 48px chrome with inline Back; constrained uses compact chrome and moves an auto-collapse primary action into overflow.",
|
|
64
|
+
"primaryAction collapse defaults to auto. Use never for Save-like actions whose hierarchy must remain visible in constrained layouts."
|
|
65
|
+
],
|
|
66
|
+
"responsiveBehavior": [
|
|
67
|
+
"BarTitle does not observe viewport, shell, scroll, or container state. Its owner selects an explicit variant.",
|
|
68
|
+
"ShellPage is the standard owner for automatic expanded, compact, and constrained selection.",
|
|
69
|
+
"Compact titles use the shared md control inset so top-level headings align with BarNav and inline Back geometry aligns with PanelToolHeader. Long headings and section labels truncate independently while Back and action controls retain complete hit targets and accessible names.",
|
|
70
|
+
"A never-collapse primary action remains visible in constrained mode; the title and section label yield space first."
|
|
71
|
+
],
|
|
72
|
+
"frameworkCaveats": {
|
|
73
|
+
"customElements": [
|
|
74
|
+
"Assign sections, primaryAction, and actions as JavaScript properties and replace array or object identities when controlled state changes.",
|
|
75
|
+
"Handle dsBack in the router owner, update value after dsSectionChange, and execute product commands from dsAction."
|
|
76
|
+
],
|
|
77
|
+
"react": [
|
|
78
|
+
"Pass arrays and objects directly to DsBarTitle and keep value controlled from route state.",
|
|
79
|
+
"Place DsBarTitle in DsShellPage with slot=header when automatic page behavior is required."
|
|
80
|
+
],
|
|
81
|
+
"angular": [
|
|
82
|
+
"Bind complex values on the standalone DsBarTitle adapter and handle the three intent events in the route shell.",
|
|
83
|
+
"Place ds-bar-title in ds-shell-page with slot=header; do not render router-outlet inside BarTitle."
|
|
84
|
+
]
|
|
85
|
+
},
|
|
86
|
+
"references": [
|
|
87
|
+
{
|
|
88
|
+
"label": "Explicit variant examples",
|
|
89
|
+
"path": "src/wc/components/BarTitle/BarTitle.stories.ts"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"label": "ShellPage composition and responsive examples",
|
|
93
|
+
"path": "src/wc/components/ShellPage/ShellPage.stories.ts"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"label": "Cross-browser shell-page and header coverage",
|
|
97
|
+
"path": "tests/e2e/bar-title.spec.ts"
|
|
98
|
+
}
|
|
99
|
+
]
|
|
100
|
+
},
|
|
101
|
+
"api": {
|
|
102
|
+
"props": {
|
|
103
|
+
"actions": {
|
|
104
|
+
"type": "BarTitleActionItem[]",
|
|
105
|
+
"resolvedType": "BarTitleActionItem[]",
|
|
106
|
+
"default": "[]",
|
|
107
|
+
"required": false,
|
|
108
|
+
"mutable": false,
|
|
109
|
+
"description": "Secondary page actions shown in the overflow menu. Dividers create groups."
|
|
110
|
+
},
|
|
111
|
+
"actionsAriaLabel": {
|
|
112
|
+
"type": "string",
|
|
113
|
+
"resolvedType": "string",
|
|
114
|
+
"attribute": "actions-aria-label",
|
|
115
|
+
"default": "'More page actions'",
|
|
116
|
+
"required": false,
|
|
117
|
+
"mutable": false,
|
|
118
|
+
"description": "Accessible name for the page-actions menu."
|
|
119
|
+
},
|
|
120
|
+
"backAriaLabel": {
|
|
121
|
+
"type": "string",
|
|
122
|
+
"resolvedType": "string",
|
|
123
|
+
"attribute": "back-aria-label",
|
|
124
|
+
"default": "'Back'",
|
|
125
|
+
"required": false,
|
|
126
|
+
"mutable": false,
|
|
127
|
+
"description": "Accessible name for the leading Back action."
|
|
128
|
+
},
|
|
129
|
+
"backLabel": {
|
|
130
|
+
"type": "string",
|
|
131
|
+
"resolvedType": "string",
|
|
132
|
+
"attribute": "back-label",
|
|
133
|
+
"default": "'Back'",
|
|
134
|
+
"required": false,
|
|
135
|
+
"mutable": false,
|
|
136
|
+
"description": "Visible parent-page label used by the expanded Back breadcrumb."
|
|
137
|
+
},
|
|
138
|
+
"description": {
|
|
139
|
+
"type": "string",
|
|
140
|
+
"resolvedType": "string",
|
|
141
|
+
"attribute": "description",
|
|
142
|
+
"default": "''",
|
|
143
|
+
"required": false,
|
|
144
|
+
"mutable": false,
|
|
145
|
+
"description": "Optional supporting copy shown in the expanded presentation."
|
|
146
|
+
},
|
|
147
|
+
"heading": {
|
|
148
|
+
"type": "string",
|
|
149
|
+
"resolvedType": "string",
|
|
150
|
+
"attribute": "heading",
|
|
151
|
+
"required": true,
|
|
152
|
+
"mutable": false,
|
|
153
|
+
"description": "The page's single visible h1."
|
|
154
|
+
},
|
|
155
|
+
"primaryAction": {
|
|
156
|
+
"type": "BarTitlePrimaryAction | null",
|
|
157
|
+
"resolvedType": "BarTitlePrimaryAction | null",
|
|
158
|
+
"default": "null",
|
|
159
|
+
"required": false,
|
|
160
|
+
"mutable": false,
|
|
161
|
+
"description": "The one highest-emphasis page action."
|
|
162
|
+
},
|
|
163
|
+
"sections": {
|
|
164
|
+
"type": "BarTitleSectionItem[]",
|
|
165
|
+
"resolvedType": "BarTitleSectionItem[]",
|
|
166
|
+
"default": "[]",
|
|
167
|
+
"required": false,
|
|
168
|
+
"mutable": false,
|
|
169
|
+
"description": "Optional page sections exposed through the active-section menu."
|
|
170
|
+
},
|
|
171
|
+
"sectionsAriaLabel": {
|
|
172
|
+
"type": "string",
|
|
173
|
+
"resolvedType": "string",
|
|
174
|
+
"attribute": "sections-aria-label",
|
|
175
|
+
"default": "'Change page section'",
|
|
176
|
+
"required": false,
|
|
177
|
+
"mutable": false,
|
|
178
|
+
"description": "Accessible name for the page-section menu."
|
|
179
|
+
},
|
|
180
|
+
"showBack": {
|
|
181
|
+
"type": "boolean",
|
|
182
|
+
"resolvedType": "boolean",
|
|
183
|
+
"attribute": "show-back",
|
|
184
|
+
"default": "false",
|
|
185
|
+
"required": false,
|
|
186
|
+
"mutable": false,
|
|
187
|
+
"description": "Show the leading page-level Back action."
|
|
188
|
+
},
|
|
189
|
+
"value": {
|
|
190
|
+
"type": "string",
|
|
191
|
+
"resolvedType": "string",
|
|
192
|
+
"attribute": "value",
|
|
193
|
+
"default": "''",
|
|
194
|
+
"required": false,
|
|
195
|
+
"mutable": false,
|
|
196
|
+
"description": "Id of the active page section."
|
|
197
|
+
},
|
|
198
|
+
"variant": {
|
|
199
|
+
"type": "BarTitleVariant",
|
|
200
|
+
"resolvedType": "\"compact\" | \"constrained\" | \"expanded\"",
|
|
201
|
+
"attribute": "variant",
|
|
202
|
+
"default": "'expanded'",
|
|
203
|
+
"required": false,
|
|
204
|
+
"mutable": false,
|
|
205
|
+
"description": "Explicit visual/capacity variant. ShellPage owns automatic selection."
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
"events": [
|
|
209
|
+
{
|
|
210
|
+
"name": "dsAction",
|
|
211
|
+
"detail": "string",
|
|
212
|
+
"bubbles": true,
|
|
213
|
+
"cancelable": true,
|
|
214
|
+
"composed": true,
|
|
215
|
+
"description": "Emitted with the activated primary or overflow action id."
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
"name": "dsBack",
|
|
219
|
+
"detail": "MouseEvent",
|
|
220
|
+
"bubbles": true,
|
|
221
|
+
"cancelable": true,
|
|
222
|
+
"composed": true,
|
|
223
|
+
"description": "Emitted when the leading Back action is activated."
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
"name": "dsSectionChange",
|
|
227
|
+
"detail": "string",
|
|
228
|
+
"bubbles": true,
|
|
229
|
+
"cancelable": true,
|
|
230
|
+
"composed": true,
|
|
231
|
+
"description": "Emitted with the newly selected page-section id."
|
|
232
|
+
}
|
|
233
|
+
],
|
|
234
|
+
"methods": [],
|
|
235
|
+
"slots": []
|
|
236
|
+
},
|
|
237
|
+
"props": {
|
|
238
|
+
"actions": {
|
|
239
|
+
"type": "BarTitleActionItem[]",
|
|
240
|
+
"resolvedType": "BarTitleActionItem[]",
|
|
241
|
+
"default": "[]",
|
|
242
|
+
"required": false,
|
|
243
|
+
"mutable": false,
|
|
244
|
+
"description": "Secondary page actions shown in the overflow menu. Dividers create groups."
|
|
245
|
+
},
|
|
246
|
+
"actionsAriaLabel": {
|
|
247
|
+
"type": "string",
|
|
248
|
+
"resolvedType": "string",
|
|
249
|
+
"attribute": "actions-aria-label",
|
|
250
|
+
"default": "'More page actions'",
|
|
251
|
+
"required": false,
|
|
252
|
+
"mutable": false,
|
|
253
|
+
"description": "Accessible name for the page-actions menu."
|
|
254
|
+
},
|
|
255
|
+
"backAriaLabel": {
|
|
256
|
+
"type": "string",
|
|
257
|
+
"resolvedType": "string",
|
|
258
|
+
"attribute": "back-aria-label",
|
|
259
|
+
"default": "'Back'",
|
|
260
|
+
"required": false,
|
|
261
|
+
"mutable": false,
|
|
262
|
+
"description": "Accessible name for the leading Back action."
|
|
263
|
+
},
|
|
264
|
+
"backLabel": {
|
|
265
|
+
"type": "string",
|
|
266
|
+
"resolvedType": "string",
|
|
267
|
+
"attribute": "back-label",
|
|
268
|
+
"default": "'Back'",
|
|
269
|
+
"required": false,
|
|
270
|
+
"mutable": false,
|
|
271
|
+
"description": "Visible parent-page label used by the expanded Back breadcrumb."
|
|
272
|
+
},
|
|
273
|
+
"description": {
|
|
274
|
+
"type": "string",
|
|
275
|
+
"resolvedType": "string",
|
|
276
|
+
"attribute": "description",
|
|
277
|
+
"default": "''",
|
|
278
|
+
"required": false,
|
|
279
|
+
"mutable": false,
|
|
280
|
+
"description": "Optional supporting copy shown in the expanded presentation."
|
|
281
|
+
},
|
|
282
|
+
"heading": {
|
|
283
|
+
"type": "string",
|
|
284
|
+
"resolvedType": "string",
|
|
285
|
+
"attribute": "heading",
|
|
286
|
+
"required": true,
|
|
287
|
+
"mutable": false,
|
|
288
|
+
"description": "The page's single visible h1."
|
|
289
|
+
},
|
|
290
|
+
"primaryAction": {
|
|
291
|
+
"type": "BarTitlePrimaryAction | null",
|
|
292
|
+
"resolvedType": "BarTitlePrimaryAction | null",
|
|
293
|
+
"default": "null",
|
|
294
|
+
"required": false,
|
|
295
|
+
"mutable": false,
|
|
296
|
+
"description": "The one highest-emphasis page action."
|
|
297
|
+
},
|
|
298
|
+
"sections": {
|
|
299
|
+
"type": "BarTitleSectionItem[]",
|
|
300
|
+
"resolvedType": "BarTitleSectionItem[]",
|
|
301
|
+
"default": "[]",
|
|
302
|
+
"required": false,
|
|
303
|
+
"mutable": false,
|
|
304
|
+
"description": "Optional page sections exposed through the active-section menu."
|
|
305
|
+
},
|
|
306
|
+
"sectionsAriaLabel": {
|
|
307
|
+
"type": "string",
|
|
308
|
+
"resolvedType": "string",
|
|
309
|
+
"attribute": "sections-aria-label",
|
|
310
|
+
"default": "'Change page section'",
|
|
311
|
+
"required": false,
|
|
312
|
+
"mutable": false,
|
|
313
|
+
"description": "Accessible name for the page-section menu."
|
|
314
|
+
},
|
|
315
|
+
"showBack": {
|
|
316
|
+
"type": "boolean",
|
|
317
|
+
"resolvedType": "boolean",
|
|
318
|
+
"attribute": "show-back",
|
|
319
|
+
"default": "false",
|
|
320
|
+
"required": false,
|
|
321
|
+
"mutable": false,
|
|
322
|
+
"description": "Show the leading page-level Back action."
|
|
323
|
+
},
|
|
324
|
+
"value": {
|
|
325
|
+
"type": "string",
|
|
326
|
+
"resolvedType": "string",
|
|
327
|
+
"attribute": "value",
|
|
328
|
+
"default": "''",
|
|
329
|
+
"required": false,
|
|
330
|
+
"mutable": false,
|
|
331
|
+
"description": "Id of the active page section."
|
|
332
|
+
},
|
|
333
|
+
"variant": {
|
|
334
|
+
"type": "BarTitleVariant",
|
|
335
|
+
"resolvedType": "\"compact\" | \"constrained\" | \"expanded\"",
|
|
336
|
+
"attribute": "variant",
|
|
337
|
+
"default": "'expanded'",
|
|
338
|
+
"required": false,
|
|
339
|
+
"mutable": false,
|
|
340
|
+
"description": "Explicit visual/capacity variant. ShellPage owns automatic selection."
|
|
341
|
+
}
|
|
342
|
+
},
|
|
343
|
+
"events": [
|
|
344
|
+
{
|
|
345
|
+
"name": "dsAction",
|
|
346
|
+
"detail": "string",
|
|
347
|
+
"bubbles": true,
|
|
348
|
+
"cancelable": true,
|
|
349
|
+
"composed": true,
|
|
350
|
+
"description": "Emitted with the activated primary or overflow action id."
|
|
351
|
+
},
|
|
352
|
+
{
|
|
353
|
+
"name": "dsBack",
|
|
354
|
+
"detail": "MouseEvent",
|
|
355
|
+
"bubbles": true,
|
|
356
|
+
"cancelable": true,
|
|
357
|
+
"composed": true,
|
|
358
|
+
"description": "Emitted when the leading Back action is activated."
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
"name": "dsSectionChange",
|
|
362
|
+
"detail": "string",
|
|
363
|
+
"bubbles": true,
|
|
364
|
+
"cancelable": true,
|
|
365
|
+
"composed": true,
|
|
366
|
+
"description": "Emitted with the newly selected page-section id."
|
|
367
|
+
}
|
|
368
|
+
],
|
|
369
|
+
"methods": [],
|
|
370
|
+
"slots": [],
|
|
371
|
+
"exports": {
|
|
372
|
+
"customElement": "ds-bar-title",
|
|
373
|
+
"react": "DsBarTitle",
|
|
374
|
+
"angular": "DsBarTitle"
|
|
375
|
+
},
|
|
376
|
+
"consumption": {
|
|
377
|
+
"install": "npm install @ds-mo/ui @ds-mo/tokens @ds-mo/icons",
|
|
378
|
+
"cssSetup": "import '@ds-mo/tokens';\nimport '@ds-mo/tokens/reset';\nimport '@ds-mo/tokens/globals';",
|
|
379
|
+
"customElements": {
|
|
380
|
+
"import": "import '@ds-mo/ui/dist/components/ds-bar-title.js';",
|
|
381
|
+
"example": "<ds-bar-title></ds-bar-title>"
|
|
382
|
+
},
|
|
383
|
+
"react": {
|
|
384
|
+
"import": "import { DsBarTitle } from '@ds-mo/ui/react';",
|
|
385
|
+
"example": "<DsBarTitle />"
|
|
386
|
+
},
|
|
387
|
+
"angular": {
|
|
388
|
+
"import": "import { DsBarTitle } from '@ds-mo/ui/angular/ds-bar-title';",
|
|
389
|
+
"example": "<ds-bar-title></ds-bar-title>"
|
|
390
|
+
},
|
|
391
|
+
"complexPropertyNote": "Assign these non-primitive values as JavaScript properties: actions, primaryAction, sections.",
|
|
392
|
+
"peerDependencies": {
|
|
393
|
+
"required": [
|
|
394
|
+
"@ds-mo/tokens ^3.1.1",
|
|
395
|
+
"@ds-mo/icons ^6.3.0"
|
|
396
|
+
],
|
|
397
|
+
"frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
},
|
|
401
|
+
"dependencies": [
|
|
402
|
+
"@ds-mo/ui",
|
|
403
|
+
"@ds-mo/tokens",
|
|
404
|
+
"@ds-mo/icons"
|
|
405
|
+
],
|
|
406
|
+
"registryDependencies": [
|
|
407
|
+
"button-filled",
|
|
408
|
+
"button-unfilled",
|
|
409
|
+
"icon",
|
|
410
|
+
"menu",
|
|
411
|
+
"text",
|
|
412
|
+
"tooltip"
|
|
413
|
+
],
|
|
414
|
+
"files": [
|
|
415
|
+
{
|
|
416
|
+
"path": "src/wc/components/BarTitle/BarTitle.css",
|
|
417
|
+
"content": "@import '../../utils/control-density.css';\n@import '../../utils/focus-ring.css';\n@import '../../utils/interaction-fill.css';\n\n:host {\n display: block;\n min-width: 0;\n box-sizing: border-box;\n background: var(--color-background-primary);\n}\n\n.bar-title {\n position: relative;\n min-width: 0;\n padding: 0;\n box-sizing: border-box;\n background: var(--color-background-primary);\n}\n\n.bar-title::after {\n content: '';\n position: absolute;\n inset: auto var(--dimension-space-400) 0;\n height: var(--dimension-stroke-width-012);\n background: var(--color-border-tertiary);\n pointer-events: none;\n}\n\n.bar-title__inner {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: var(--dimension-space-100);\n padding: var(--dimension-space-400);\n box-sizing: border-box;\n}\n\n.bar-title__row {\n display: flex;\n align-items: center;\n gap: var(--dimension-space-100);\n min-height: var(--dimension-size-400);\n min-width: 0;\n}\n\n.bar-title__identity {\n display: flex;\n flex: 1 1 auto;\n align-items: center;\n gap: var(--dimension-space-050);\n min-width: 0;\n}\n\n.bar-title__back,\n.bar-title__breadcrumb-back,\n.bar-title__section-chevron {\n flex: 0 0 auto;\n}\n\n.bar-title__breadcrumb {\n display: flex;\n align-items: center;\n min-width: 0;\n}\n\n.bar-title__heading {\n display: block;\n width: auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n user-select: none;\n}\n\n.bar-title__divider {\n width: var(--dimension-stroke-width-012);\n height: var(--dimension-size-250);\n flex: 0 0 var(--dimension-stroke-width-012);\n background: var(--color-border-tertiary);\n}\n\n.bar-title__section-selector {\n display: flex;\n flex: 0 1 auto;\n min-width: 0;\n max-width: var(--dimension-panel-width-sm);\n}\n\n.bar-title__section-trigger {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--ds-control-gap);\n height: var(--ds-control-height);\n min-width: 0;\n max-width: 100%;\n padding-inline: var(--ds-control-padding-inline);\n border: none;\n border-radius: var(--ds-control-radius);\n box-sizing: border-box;\n background: transparent;\n color: var(--color-foreground-secondary);\n cursor: pointer;\n font-family: inherit;\n user-select: none;\n transition: color var(--effect-motion-short-2);\n}\n\n.bar-title__section-trigger--expanded {\n color: var(--color-foreground-primary);\n}\n\n.bar-title__section-trigger--expanded::after,\n.bar-title__section-trigger--expanded:hover::after {\n background: var(--ds-interaction-pressed);\n}\n\n.bar-title__section-label {\n min-width: 0;\n padding-inline-start: var(--ds-control-label-inset);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.bar-title__section-chevron {\n margin-inline-end: var(--ds-control-label-inset);\n}\n\n.bar-title__actions {\n display: flex;\n align-items: center;\n gap: var(--dimension-space-100);\n margin-inline-start: auto;\n flex: 0 0 auto;\n}\n\n.bar-title__description {\n display: block;\n width: auto;\n min-width: 0;\n max-width: 100%;\n height: var(--dimension-size-400);\n margin-inline-start: 0;\n overflow: hidden;\n}\n\n:host(.bar-title-host--compact) .bar-title {\n height: var(--dimension-size-600);\n padding: var(--dimension-space-100);\n}\n\n:host(.bar-title-host--compact) .bar-title::after {\n inset-inline: 0;\n}\n\n:host(.bar-title-host--compact) .bar-title__inner {\n height: 100%;\n padding: 0;\n gap: 0;\n}\n\n:host(.bar-title-host--compact) .bar-title__row {\n height: 100%;\n}\n\n:host(.bar-title-host--compact) .bar-title__identity {\n height: var(--dimension-size-400);\n}\n\n:host(.bar-title-host--compact) .bar-title__heading {\n display: inline-flex;\n flex: 1 1 auto;\n align-items: center;\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}\n\n@media (prefers-reduced-motion: reduce) {\n .bar-title__section-trigger {\n transition: none;\n }\n}\n",
|
|
418
|
+
"type": "registry:ui"
|
|
419
|
+
},
|
|
420
|
+
{
|
|
421
|
+
"path": "src/wc/components/BarTitle/BarTitle.tsx",
|
|
422
|
+
"content": "import { Component, Event, EventEmitter, h, Host, Prop, State, Watch } from '@stencil/core';\nimport type { MenuItemData, MenuSection } from '../Menu/menu-types';\nimport {\n isBarTitleDivider,\n type BarTitleAction,\n type BarTitleActionItem,\n type BarTitlePrimaryAction,\n type BarTitleSection,\n type BarTitleSectionItem,\n type BarTitleVariant,\n} from './bar-title-types';\n\nlet nextBarTitleId = 0;\n\ntype FocusableButton = HTMLElement & { setFocus?: () => Promise<void> };\n\n@Component({\n tag: 'ds-bar-title',\n styleUrl: 'BarTitle.css',\n scoped: true,\n})\nexport class BarTitle {\n /** The page's single visible h1. */\n @Prop() heading!: string;\n\n /** Optional supporting copy shown in the expanded presentation. */\n @Prop() description: string = '';\n\n /** Show the leading page-level Back action. */\n @Prop({ attribute: 'show-back' }) showBack: boolean = false;\n\n /** Accessible name for the leading Back action. */\n @Prop() backAriaLabel: string = 'Back';\n\n /** Visible parent-page label used by the expanded Back breadcrumb. */\n @Prop() backLabel: string = 'Back';\n\n /** Optional page sections exposed through the active-section menu. */\n @Prop() sections: BarTitleSectionItem[] = [];\n\n /** Id of the active page section. */\n @Prop() value: string = '';\n\n /** Accessible name for the page-section menu. */\n @Prop() sectionsAriaLabel: string = 'Change page section';\n\n /** The one highest-emphasis page action. */\n @Prop() primaryAction: BarTitlePrimaryAction | null = null;\n\n /** Secondary page actions shown in the overflow menu. Dividers create groups. */\n @Prop() actions: BarTitleActionItem[] = [];\n\n /** Accessible name for the page-actions menu. */\n @Prop() actionsAriaLabel: string = 'More page actions';\n\n /** Explicit visual/capacity variant. ShellPage owns automatic selection. */\n @Prop() variant: BarTitleVariant = 'expanded';\n\n /** Emitted when the leading Back action is activated. */\n @Event() dsBack!: EventEmitter<MouseEvent>;\n\n /** Emitted with the newly selected page-section id. */\n @Event() dsSectionChange!: EventEmitter<string>;\n\n /** Emitted with the activated primary or overflow action id. */\n @Event() dsAction!: EventEmitter<string>;\n\n @State() private sectionMenuOpen = false;\n @State() private actionMenuOpen = false;\n @State() private sectionMenuInitialFocusVisible = false;\n @State() private actionMenuInitialFocusVisible = false;\n\n private readonly instanceId = nextBarTitleId++;\n private readonly sectionMenuTriggerId = `bar-title-section-trigger-${this.instanceId}`;\n private readonly sectionMenuId = `bar-title-section-menu-${this.instanceId}`;\n private readonly actionMenuTriggerId = `bar-title-action-trigger-${this.instanceId}`;\n private readonly actionMenuId = `bar-title-action-menu-${this.instanceId}`;\n private sectionTriggerEl: HTMLButtonElement | null = null;\n private actionTriggerEl: FocusableButton | null = null;\n\n @Watch('sections')\n handleSectionsChange() {\n if (!this.hasSectionSelector) this.closeSectionMenu();\n }\n\n @Watch('actions')\n @Watch('primaryAction')\n handleActionsChange() {\n if (!this.showActionMenuTrigger) this.closeActionMenu();\n }\n\n private get compact(): boolean {\n return this.variant !== 'expanded';\n }\n\n private get primaryCollapsed(): boolean {\n return (\n this.variant === 'constrained' &&\n this.primaryAction !== null &&\n (this.primaryAction.collapse ?? 'auto') === 'auto'\n );\n }\n\n private get selectableSections(): BarTitleSection[] {\n return this.sections.filter((item): item is BarTitleSection => !isBarTitleDivider(item));\n }\n\n private get hasSectionSelector(): boolean {\n return this.selectableSections.length > 1;\n }\n\n private get effectiveValue(): string {\n return this.selectableSections.some(section => section.id === this.value)\n ? this.value\n : (this.selectableSections[0]?.id ?? '');\n }\n\n private get selectedSectionLabel(): string {\n return this.selectableSections.find(section => section.id === this.effectiveValue)?.label ?? '';\n }\n\n private get sectionTriggerAriaLabel(): string {\n return `${this.sectionsAriaLabel}. Current section: ${this.selectedSectionLabel}`;\n }\n\n private groupsFromItems<T extends BarTitleSection | BarTitleAction>(\n source: Array<T | { type: 'divider' }>,\n map: (item: T) => MenuItemData\n ): MenuSection[] {\n const groups: MenuSection[] = [];\n let items: MenuItemData[] = [];\n const commit = () => {\n if (items.length > 0) groups.push({ items });\n items = [];\n };\n\n for (const item of source) {\n if (isBarTitleDivider(item)) {\n commit();\n } else {\n items.push(map(item));\n }\n }\n commit();\n return groups;\n }\n\n private get sectionMenuSections(): MenuSection[] {\n return this.groupsFromItems(this.sections, section => ({\n label: section.label,\n value: section.id,\n isSelected: section.id === this.effectiveValue,\n isInactive: section.isInactive,\n }));\n }\n\n private get selectableActions(): BarTitleAction[] {\n return this.actions.filter((item): item is BarTitleAction => !isBarTitleDivider(item));\n }\n\n private get showActionMenuTrigger(): boolean {\n return (\n this.selectableActions.length > 0 || (this.primaryCollapsed && this.primaryAction !== null)\n );\n }\n\n private actionMenuItem(action: BarTitleAction | BarTitlePrimaryAction): MenuItemData {\n const primary = action as BarTitlePrimaryAction;\n return {\n label: action.label,\n value: action.id,\n isInactive: action.isInactive || primary.isLoading,\n isDestructive: action.isDestructive || primary.intent === 'negative',\n };\n }\n\n private get actionMenuSections(): MenuSection[] {\n const groups = this.groupsFromItems(this.actions, action => this.actionMenuItem(action));\n if (!this.primaryCollapsed || !this.primaryAction) return groups;\n return [{ items: [this.actionMenuItem(this.primaryAction)] }, ...groups];\n }\n\n private toggleSectionMenu = (event: MouseEvent) => {\n this.sectionMenuInitialFocusVisible = event.detail === 0;\n this.actionMenuOpen = false;\n this.sectionMenuOpen = !this.sectionMenuOpen;\n };\n\n private closeSectionMenu = () => {\n this.sectionMenuOpen = false;\n };\n\n private handleSectionSelect = (event: CustomEvent<MenuItemData>) => {\n const id = String(event.detail?.value ?? '');\n const selected = this.selectableSections.find(section => section.id === id);\n if (!selected || selected.isInactive) return;\n this.closeSectionMenu();\n this.dsSectionChange.emit(id);\n requestAnimationFrame(() => this.sectionTriggerEl?.focus());\n };\n\n private toggleActionMenu = (event: MouseEvent) => {\n this.actionMenuInitialFocusVisible = event.detail === 0;\n this.sectionMenuOpen = false;\n this.actionMenuOpen = !this.actionMenuOpen;\n };\n\n private closeActionMenu = () => {\n this.actionMenuOpen = false;\n };\n\n private handleActionSelect = (event: CustomEvent<MenuItemData>) => {\n const id = String(event.detail?.value ?? '');\n const primaryMatches = this.primaryCollapsed && this.primaryAction?.id === id;\n const action = this.selectableActions.find(candidate => candidate.id === id);\n if (!primaryMatches && !action) return;\n if (\n (primaryMatches && (this.primaryAction?.isInactive || this.primaryAction?.isLoading)) ||\n action?.isInactive\n ) {\n return;\n }\n this.closeActionMenu();\n this.dsAction.emit(id);\n requestAnimationFrame(() => void this.actionTriggerEl?.setFocus?.());\n };\n\n private renderSectionSelector() {\n if (!this.hasSectionSelector) return null;\n return [\n <div class=\"bar-title__divider\" aria-hidden=\"true\" />,\n <div class=\"bar-title__section-selector\">\n <button\n ref={el => {\n this.sectionTriggerEl = el ?? null;\n }}\n id={this.sectionMenuTriggerId}\n class={{\n 'bar-title__section-trigger': true,\n 'bar-title__section-trigger--expanded': this.sectionMenuOpen,\n 'ds-control--md': true,\n 'ds-focus-ring-inset': true,\n 'ds-interaction-fill': true,\n }}\n type=\"button\"\n aria-haspopup=\"menu\"\n aria-controls={this.sectionMenuId}\n aria-expanded={String(this.sectionMenuOpen)}\n aria-label={this.sectionTriggerAriaLabel}\n onClick={this.toggleSectionMenu}\n >\n <ds-text\n class=\"bar-title__section-label ds-interaction-fill__content\"\n as=\"span\"\n variant=\"text-body-medium\"\n emphasis\n color=\"primary\"\n >\n {this.selectedSectionLabel}\n </ds-text>\n <ds-icon\n class=\"bar-title__section-chevron ds-interaction-fill__content\"\n name=\"ChevronUpDown\"\n size=\"sm\"\n color=\"inherit\"\n aria-hidden=\"true\"\n />\n </button>\n </div>,\n ];\n }\n\n private renderActions() {\n const primary = this.primaryAction;\n if (!primary && !this.showActionMenuTrigger) return null;\n\n return (\n <div class=\"bar-title__actions\">\n {primary && !this.primaryCollapsed ? (\n <ds-button-filled\n class=\"bar-title__primary-action\"\n variant={primary.icon ? 'icon-label' : 'label'}\n icon={primary.icon ?? ''}\n label={primary.label}\n intent={primary.intent ?? 'brand'}\n contrast={primary.contrast ?? 'bold'}\n size=\"md\"\n type={primary.type ?? 'button'}\n isInactive={primary.isInactive}\n isLoading={primary.isLoading}\n onDsClick={() => this.dsAction.emit(primary.id)}\n />\n ) : null}\n {this.showActionMenuTrigger ? (\n <ds-button-unfilled\n ref={el => {\n this.actionTriggerEl = el ?? null;\n }}\n id={this.actionMenuTriggerId}\n class=\"bar-title__more-actions\"\n variant=\"icon\"\n icon=\"Ellipses\"\n aria-label={this.actionsAriaLabel}\n size=\"md\"\n activeFill={!this.compact}\n hasBorder={!this.compact && !this.primaryCollapsed}\n haspopup=\"menu\"\n controls={this.actionMenuId}\n expanded={this.actionMenuOpen}\n onDsClick={(event: CustomEvent<MouseEvent>) => this.toggleActionMenu(event.detail)}\n />\n ) : null}\n </div>\n );\n }\n\n private renderBack(compact: boolean) {\n if (!this.showBack) return null;\n\n if (!compact) {\n return (\n <div class=\"bar-title__breadcrumb\">\n <ds-button-unfilled\n class=\"bar-title__breadcrumb-back\"\n variant=\"icon-label\"\n icon=\"ChevronLeft\"\n label={this.backLabel}\n aria-label={this.backAriaLabel}\n size=\"xs\"\n hasBorder={false}\n onDsClick={(event: CustomEvent<MouseEvent>) => this.dsBack.emit(event.detail)}\n />\n </div>\n );\n }\n\n return (\n <ds-tooltip label={this.backAriaLabel} side=\"bottom\" size=\"sm\">\n <ds-button-unfilled\n class=\"bar-title__back\"\n variant=\"icon\"\n icon=\"ChevronLeft\"\n aria-label={this.backAriaLabel}\n size=\"md\"\n activeFill={false}\n hasBorder={false}\n onDsClick={(event: CustomEvent<MouseEvent>) => this.dsBack.emit(event.detail)}\n />\n </ds-tooltip>\n );\n }\n\n render() {\n const compact = this.compact;\n return (\n <Host\n class={{\n 'bar-title-host--compact': compact,\n 'bar-title-host--expanded': this.variant === 'expanded',\n 'bar-title-host--constrained': this.variant === 'constrained',\n 'bar-title-host--has-description': !!this.description,\n 'bar-title-host--has-back': this.showBack,\n }}\n >\n <div class=\"bar-title\">\n <div class=\"bar-title__inner\">\n {!compact ? this.renderBack(false) : null}\n <div class=\"bar-title__row\">\n <div class=\"bar-title__identity\">\n {compact ? this.renderBack(true) : null}\n <ds-text\n class=\"bar-title__heading ds-control--md\"\n variant={compact ? 'text-title-small' : 'text-title-medium'}\n emphasis\n color=\"primary\"\n as=\"h1\"\n lineTruncation={1}\n >\n {this.heading}\n </ds-text>\n </div>\n {this.renderSectionSelector()}\n {this.renderActions()}\n </div>\n {this.description && !compact ? (\n <ds-text\n class=\"bar-title__description\"\n variant=\"text-body-small\"\n color=\"secondary\"\n lineTruncation={2}\n wrap=\"wrap\"\n as=\"p\"\n >\n {this.description}\n </ds-text>\n ) : null}\n </div>\n </div>\n\n {this.hasSectionSelector ? (\n <ds-menu\n id={this.sectionMenuId}\n class=\"bar-title__section-menu\"\n anchorId={this.sectionMenuTriggerId}\n menuLabel={this.sectionsAriaLabel}\n open={this.sectionMenuOpen}\n initialFocusVisible={this.sectionMenuInitialFocusVisible}\n sections={this.sectionMenuSections}\n onDsClose={this.closeSectionMenu}\n onDsSelect={this.handleSectionSelect}\n />\n ) : null}\n\n {this.showActionMenuTrigger ? (\n <ds-menu\n id={this.actionMenuId}\n class=\"bar-title__action-menu\"\n anchorId={this.actionMenuTriggerId}\n align=\"end\"\n menuLabel={this.actionsAriaLabel}\n open={this.actionMenuOpen}\n initialFocusVisible={this.actionMenuInitialFocusVisible}\n sections={this.actionMenuSections}\n onDsClose={this.closeActionMenu}\n onDsSelect={this.handleActionSelect}\n />\n ) : null}\n </Host>\n );\n }\n}\n",
|
|
423
|
+
"type": "registry:ui"
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
"path": "src/wc/components/BarTitle/bar-title-types.ts",
|
|
427
|
+
"content": "import type { ButtonFilledContrast, ButtonFilledIntent } from '../ButtonFilled/ButtonFilled';\n\nexport interface BarTitleSection {\n id: string;\n label: string;\n isInactive?: boolean;\n}\n\nexport interface BarTitleDivider {\n type: 'divider';\n}\n\nexport type BarTitleSectionItem = BarTitleSection | BarTitleDivider;\n\nexport interface BarTitleAction {\n id: string;\n label: string;\n isInactive?: boolean;\n isDestructive?: boolean;\n}\n\nexport interface BarTitlePrimaryAction extends BarTitleAction {\n icon?: string;\n intent?: ButtonFilledIntent;\n contrast?: ButtonFilledContrast;\n isLoading?: boolean;\n type?: 'button' | 'submit' | 'reset';\n collapse?: BarTitlePrimaryActionCollapse;\n}\n\nexport type BarTitleActionItem = BarTitleAction | BarTitleDivider;\n\nexport type BarTitleVariant = 'expanded' | 'compact' | 'constrained';\n\nexport type BarTitlePrimaryActionCollapse = 'auto' | 'never';\n\nexport function isBarTitleDivider(\n item: BarTitleSectionItem | BarTitleActionItem\n): item is BarTitleDivider {\n return 'type' in item && item.type === 'divider';\n}\n",
|
|
428
|
+
"type": "registry:ui"
|
|
429
|
+
}
|
|
430
|
+
]
|
|
431
|
+
}
|
|
@@ -53,6 +53,8 @@
|
|
|
53
53
|
"Use only one filled action per local decision area; render all secondary actions with ButtonUnfilled.",
|
|
54
54
|
"Choose brand or neutral for general commands. Reserve positive, negative, warning, and caution for matching action consequences, and AI, guide, or walkthrough for actions that enter those feature experiences.",
|
|
55
55
|
"Contrast serves both surface adaptation and hierarchy, but never permits a second filled action in the same decision area.",
|
|
56
|
+
"The optional inset border is off by default. Enable it only when the filled action needs an explicit edge against its parent surface.",
|
|
57
|
+
"Parent surface context changes only the optional inset border color. Contrast continues to own the button fill, foreground, hover, pressed, and focus treatments; never use surface context to change action hierarchy.",
|
|
56
58
|
"Rounded changes only the control radius to the half-radius treatment; it does not change hierarchy, size, variant, intent, or interaction semantics.",
|
|
57
59
|
"Loading prevents duplicate activation without applying inactive opacity or removing the current keyboard focus.",
|
|
58
60
|
"Icon and icon-label loading replace the icon in place. Label-only loading centers the loader while preserving the button's measured width."
|
|
@@ -89,6 +91,14 @@
|
|
|
89
91
|
"mutable": false,
|
|
90
92
|
"description": "Accessible name override. Required for icon-only buttons."
|
|
91
93
|
},
|
|
94
|
+
"background": {
|
|
95
|
+
"type": "ButtonFilledBackground | undefined",
|
|
96
|
+
"resolvedType": "\"always-dark\" | \"bold\" | \"faint\" | \"inverted\" | \"media\" | \"medium\" | \"strong\" | \"translucent\" | undefined",
|
|
97
|
+
"attribute": "background",
|
|
98
|
+
"required": false,
|
|
99
|
+
"mutable": false,
|
|
100
|
+
"description": "Actual parent surface context for the optional inset border color only.\nOmit on primary and secondary surfaces."
|
|
101
|
+
},
|
|
92
102
|
"contrast": {
|
|
93
103
|
"type": "ButtonFilledContrast",
|
|
94
104
|
"resolvedType": "\"bold\" | \"faint\" | \"medium\" | \"strong\"",
|
|
@@ -98,6 +108,15 @@
|
|
|
98
108
|
"mutable": false,
|
|
99
109
|
"description": "Background fill weight. Foreground uses the paired contrast token:\nbold → faint, strong → medium, medium → strong, faint → bold."
|
|
100
110
|
},
|
|
111
|
+
"hasBorder": {
|
|
112
|
+
"type": "boolean",
|
|
113
|
+
"resolvedType": "boolean",
|
|
114
|
+
"attribute": "has-border",
|
|
115
|
+
"default": "false",
|
|
116
|
+
"required": false,
|
|
117
|
+
"mutable": false,
|
|
118
|
+
"description": "Show a 1px secondary inset border."
|
|
119
|
+
},
|
|
101
120
|
"icon": {
|
|
102
121
|
"type": "string",
|
|
103
122
|
"resolvedType": "string",
|
|
@@ -216,6 +235,14 @@
|
|
|
216
235
|
"mutable": false,
|
|
217
236
|
"description": "Accessible name override. Required for icon-only buttons."
|
|
218
237
|
},
|
|
238
|
+
"background": {
|
|
239
|
+
"type": "ButtonFilledBackground | undefined",
|
|
240
|
+
"resolvedType": "\"always-dark\" | \"bold\" | \"faint\" | \"inverted\" | \"media\" | \"medium\" | \"strong\" | \"translucent\" | undefined",
|
|
241
|
+
"attribute": "background",
|
|
242
|
+
"required": false,
|
|
243
|
+
"mutable": false,
|
|
244
|
+
"description": "Actual parent surface context for the optional inset border color only.\nOmit on primary and secondary surfaces."
|
|
245
|
+
},
|
|
219
246
|
"contrast": {
|
|
220
247
|
"type": "ButtonFilledContrast",
|
|
221
248
|
"resolvedType": "\"bold\" | \"faint\" | \"medium\" | \"strong\"",
|
|
@@ -225,6 +252,15 @@
|
|
|
225
252
|
"mutable": false,
|
|
226
253
|
"description": "Background fill weight. Foreground uses the paired contrast token:\nbold → faint, strong → medium, medium → strong, faint → bold."
|
|
227
254
|
},
|
|
255
|
+
"hasBorder": {
|
|
256
|
+
"type": "boolean",
|
|
257
|
+
"resolvedType": "boolean",
|
|
258
|
+
"attribute": "has-border",
|
|
259
|
+
"default": "false",
|
|
260
|
+
"required": false,
|
|
261
|
+
"mutable": false,
|
|
262
|
+
"description": "Show a 1px secondary inset border."
|
|
263
|
+
},
|
|
228
264
|
"icon": {
|
|
229
265
|
"type": "string",
|
|
230
266
|
"resolvedType": "string",
|
|
@@ -374,12 +410,12 @@
|
|
|
374
410
|
"files": [
|
|
375
411
|
{
|
|
376
412
|
"path": "src/wc/components/ButtonFilled/ButtonFilled.css",
|
|
377
|
-
"content": "@import '../../utils/focus-ring.css';\n@import '../../utils/interaction-fill.css';\n@import '../../utils/control-inactive.css';\n@import '../../utils/control-density.css';\n@import '../../utils/control-width.css';\n\n:host {\n display: inline-flex;\n outline: none;\n --ds-button-filled-bg: var(--color-background-bold-brand);\n --ds-button-filled-fg: var(--color-foreground-faint-brand);\n}\n\n/* Icon-only: fixed square from density height (hug). Fill stretches the hit target. */\n:host(.button-filled-host--icon.ds-control-width--hug) {\n width: var(--ds-control-height, var(--dimension-size-400));\n height: var(--ds-control-height, var(--dimension-size-400));\n min-width: var(--ds-control-height, var(--dimension-size-400));\n min-height: var(--ds-control-height, var(--dimension-size-400));\n}\n\n:host(.button-filled-host--icon.ds-control-width--fill) {\n height: var(--ds-control-height, var(--dimension-size-400));\n min-height: var(--ds-control-height, var(--dimension-size-400));\n}\n\n:host(.ds-control-width--fill) .button-filled {\n width: 100%;\n}\n\n.button-filled {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n height: var(--ds-control-height, var(--dimension-size-400));\n padding: 0 var(--ds-control-padding-inline, var(--dimension-space-075));\n gap: var(--ds-control-gap, var(--dimension-space-050));\n border: none;\n border-radius: var(--ds-control-radius, var(--dimension-radius-025));\n background-color: var(--ds-button-filled-bg);\n color: var(--ds-button-filled-fg);\n cursor: pointer;\n -webkit-user-select: none;\n user-select: none;\n overflow: hidden;\n transition:\n background-color var(--effect-motion-short-2),\n color var(--effect-motion-short-2),\n transform var(--effect-motion-short-2);\n /* Hover/press: `.ds-interaction-fill` + contrast → `--on-*` (token overlay, not color-mix). */\n}\n\n.button-filled--icon {\n width: 100%;\n height: 100%;\n padding: 0;\n}\n\n.button-filled--rounded {\n --ds-control-radius: var(--dimension-radius-half);\n}\n\n.button-filled:active:not(:disabled):not(.ds-control-inactive) {\n transform: scale(var(--dimension-scale-subtle));\n}\n\n@media (prefers-reduced-motion: reduce) {\n .button-filled {\n transition:\n background-color var(--effect-motion-short-2),\n color var(--effect-motion-short-2);\n }\n\n .button-filled:active:not(:disabled):not(.ds-control-inactive) {\n transform: none;\n }\n}\n\n/* Inactive: `.ds-control-inactive` (25% opacity). */\n\n.button-filled__icon-wrap {\n position: relative;\n width: var(--ds-control-icon, var(--dimension-iconography-md));\n height: var(--ds-control-icon, var(--dimension-iconography-md));\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n z-index: 2;\n}\n\n.button-filled__label {\n position: relative;\n z-index: 2;\n padding: 0 var(--ds-control-label-inset, var(--dimension-space-025));\n white-space: nowrap;\n flex-shrink: 0;\n min-width: 0;\n}\n\n.button-filled__label--loading {\n visibility: hidden;\n}\n\n.button-filled > .button-filled__loader-overlay {\n position: absolute;\n inset: 0;\n z-index: 2;\n display: flex;\n align-items: center;\n justify-content: center;\n pointer-events: none;\n}\n\n/* ── Intent + contrast (bold default) ─────────────────────────────────────── */\n\n.button-filled--intent-neutral {\n --ds-button-filled-bg: var(--color-background-bold-neutral);\n --ds-button-filled-fg: var(--color-foreground-faint-neutral);\n}\n\n.button-filled--intent-brand {\n --ds-button-filled-bg: var(--color-background-bold-brand);\n --ds-button-filled-fg: var(--color-foreground-faint-brand);\n}\n\n.button-filled--intent-ai {\n --ds-button-filled-bg: var(--color-background-bold-ai);\n --ds-button-filled-fg: var(--color-foreground-faint-ai);\n}\n\n.button-filled--intent-negative {\n --ds-button-filled-bg: var(--color-background-bold-negative);\n --ds-button-filled-fg: var(--color-foreground-faint-negative);\n}\n\n.button-filled--intent-warning {\n --ds-button-filled-bg: var(--color-background-bold-warning);\n --ds-button-filled-fg: var(--color-foreground-faint-warning);\n}\n\n.button-filled--intent-caution {\n --ds-button-filled-bg: var(--color-background-bold-caution);\n --ds-button-filled-fg: var(--color-foreground-faint-caution);\n}\n\n.button-filled--intent-positive {\n --ds-button-filled-bg: var(--color-background-bold-positive);\n --ds-button-filled-fg: var(--color-foreground-faint-positive);\n}\n\n.button-filled--intent-guide {\n --ds-button-filled-bg: var(--color-background-bold-guide);\n --ds-button-filled-fg: var(--color-foreground-faint-guide);\n}\n\n.button-filled--intent-walkthrough {\n --ds-button-filled-bg: var(--color-background-bold-walkthrough);\n --ds-button-filled-fg: var(--color-foreground-faint-walkthrough);\n}\n\n/* strong → medium fg */\n.button-filled--contrast-strong.button-filled--intent-neutral {\n --ds-button-filled-bg: var(--color-background-strong-neutral);\n --ds-button-filled-fg: var(--color-foreground-medium-neutral);\n}\n\n.button-filled--contrast-strong.button-filled--intent-brand {\n --ds-button-filled-bg: var(--color-background-strong-brand);\n --ds-button-filled-fg: var(--color-foreground-medium-brand);\n}\n\n.button-filled--contrast-strong.button-filled--intent-ai {\n --ds-button-filled-bg: var(--color-background-strong-ai);\n --ds-button-filled-fg: var(--color-foreground-medium-ai);\n}\n\n.button-filled--contrast-strong.button-filled--intent-negative {\n --ds-button-filled-bg: var(--color-background-strong-negative);\n --ds-button-filled-fg: var(--color-foreground-medium-negative);\n}\n\n.button-filled--contrast-strong.button-filled--intent-warning {\n --ds-button-filled-bg: var(--color-background-strong-warning);\n --ds-button-filled-fg: var(--color-foreground-medium-warning);\n}\n\n.button-filled--contrast-strong.button-filled--intent-caution {\n --ds-button-filled-bg: var(--color-background-strong-caution);\n --ds-button-filled-fg: var(--color-foreground-medium-caution);\n}\n\n.button-filled--contrast-strong.button-filled--intent-positive {\n --ds-button-filled-bg: var(--color-background-strong-positive);\n --ds-button-filled-fg: var(--color-foreground-medium-positive);\n}\n\n.button-filled--contrast-strong.button-filled--intent-guide {\n --ds-button-filled-bg: var(--color-background-strong-guide);\n --ds-button-filled-fg: var(--color-foreground-medium-guide);\n}\n\n.button-filled--contrast-strong.button-filled--intent-walkthrough {\n --ds-button-filled-bg: var(--color-background-strong-walkthrough);\n --ds-button-filled-fg: var(--color-foreground-medium-walkthrough);\n}\n\n/* medium → strong fg */\n.button-filled--contrast-medium.button-filled--intent-neutral {\n --ds-button-filled-bg: var(--color-background-medium-neutral);\n --ds-button-filled-fg: var(--color-foreground-strong-neutral);\n}\n\n.button-filled--contrast-medium.button-filled--intent-brand {\n --ds-button-filled-bg: var(--color-background-medium-brand);\n --ds-button-filled-fg: var(--color-foreground-strong-brand);\n}\n\n.button-filled--contrast-medium.button-filled--intent-ai {\n --ds-button-filled-bg: var(--color-background-medium-ai);\n --ds-button-filled-fg: var(--color-foreground-strong-ai);\n}\n\n.button-filled--contrast-medium.button-filled--intent-negative {\n --ds-button-filled-bg: var(--color-background-medium-negative);\n --ds-button-filled-fg: var(--color-foreground-strong-negative);\n}\n\n.button-filled--contrast-medium.button-filled--intent-warning {\n --ds-button-filled-bg: var(--color-background-medium-warning);\n --ds-button-filled-fg: var(--color-foreground-strong-warning);\n}\n\n.button-filled--contrast-medium.button-filled--intent-caution {\n --ds-button-filled-bg: var(--color-background-medium-caution);\n --ds-button-filled-fg: var(--color-foreground-strong-caution);\n}\n\n.button-filled--contrast-medium.button-filled--intent-positive {\n --ds-button-filled-bg: var(--color-background-medium-positive);\n --ds-button-filled-fg: var(--color-foreground-strong-positive);\n}\n\n.button-filled--contrast-medium.button-filled--intent-guide {\n --ds-button-filled-bg: var(--color-background-medium-guide);\n --ds-button-filled-fg: var(--color-foreground-strong-guide);\n}\n\n.button-filled--contrast-medium.button-filled--intent-walkthrough {\n --ds-button-filled-bg: var(--color-background-medium-walkthrough);\n --ds-button-filled-fg: var(--color-foreground-strong-walkthrough);\n}\n\n/* faint → bold fg */\n.button-filled--contrast-faint.button-filled--intent-neutral {\n --ds-button-filled-bg: var(--color-background-faint-neutral);\n --ds-button-filled-fg: var(--color-foreground-bold-neutral);\n}\n\n.button-filled--contrast-faint.button-filled--intent-brand {\n --ds-button-filled-bg: var(--color-background-faint-brand);\n --ds-button-filled-fg: var(--color-foreground-bold-brand);\n}\n\n.button-filled--contrast-faint.button-filled--intent-ai {\n --ds-button-filled-bg: var(--color-background-faint-ai);\n --ds-button-filled-fg: var(--color-foreground-bold-ai);\n}\n\n.button-filled--contrast-faint.button-filled--intent-negative {\n --ds-button-filled-bg: var(--color-background-faint-negative);\n --ds-button-filled-fg: var(--color-foreground-bold-negative);\n}\n\n.button-filled--contrast-faint.button-filled--intent-warning {\n --ds-button-filled-bg: var(--color-background-faint-warning);\n --ds-button-filled-fg: var(--color-foreground-bold-warning);\n}\n\n.button-filled--contrast-faint.button-filled--intent-caution {\n --ds-button-filled-bg: var(--color-background-faint-caution);\n --ds-button-filled-fg: var(--color-foreground-bold-caution);\n}\n\n.button-filled--contrast-faint.button-filled--intent-positive {\n --ds-button-filled-bg: var(--color-background-faint-positive);\n --ds-button-filled-fg: var(--color-foreground-bold-positive);\n}\n\n.button-filled--contrast-faint.button-filled--intent-guide {\n --ds-button-filled-bg: var(--color-background-faint-guide);\n --ds-button-filled-fg: var(--color-foreground-bold-guide);\n}\n\n.button-filled--contrast-faint.button-filled--intent-walkthrough {\n --ds-button-filled-bg: var(--color-background-faint-walkthrough);\n --ds-button-filled-fg: var(--color-foreground-bold-walkthrough);\n}\n",
|
|
413
|
+
"content": "@import '../../utils/focus-ring.css';\n@import '../../utils/interaction-fill.css';\n@import '../../utils/control-inactive.css';\n@import '../../utils/control-density.css';\n@import '../../utils/control-width.css';\n\n:host {\n display: inline-flex;\n outline: none;\n --ds-button-filled-bg: var(--color-background-bold-brand);\n --ds-button-filled-fg: var(--color-foreground-faint-brand);\n --ds-button-filled-border: var(--color-border-secondary);\n}\n\n/* Icon-only: fixed square from density height (hug). Fill stretches the hit target. */\n:host(.button-filled-host--icon.ds-control-width--hug) {\n width: var(--ds-control-height, var(--dimension-size-400));\n height: var(--ds-control-height, var(--dimension-size-400));\n min-width: var(--ds-control-height, var(--dimension-size-400));\n min-height: var(--ds-control-height, var(--dimension-size-400));\n}\n\n:host(.button-filled-host--icon.ds-control-width--fill) {\n height: var(--ds-control-height, var(--dimension-size-400));\n min-height: var(--ds-control-height, var(--dimension-size-400));\n}\n\n:host(.ds-control-width--fill) .button-filled {\n width: 100%;\n}\n\n.button-filled {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n height: var(--ds-control-height, var(--dimension-size-400));\n padding: 0 var(--ds-control-padding-inline, var(--dimension-space-075));\n gap: var(--ds-control-gap, var(--dimension-space-050));\n border: none;\n border-radius: var(--ds-control-radius, var(--dimension-radius-025));\n background-color: var(--ds-button-filled-bg);\n color: var(--ds-button-filled-fg);\n cursor: pointer;\n -webkit-user-select: none;\n user-select: none;\n overflow: hidden;\n transition:\n background-color var(--effect-motion-short-2),\n color var(--effect-motion-short-2),\n transform var(--effect-motion-short-2);\n /* Hover/press: `.ds-interaction-fill` + contrast → `--on-*` (token overlay, not color-mix). */\n}\n\n.button-filled--icon {\n width: 100%;\n height: 100%;\n padding: 0;\n}\n\n.button-filled--rounded {\n --ds-control-radius: var(--dimension-radius-half);\n}\n\n/* Inset stroke via interaction-fill ::after (above hover and pressed washes). */\n.button-filled--bordered {\n --ds-interaction-border-width: var(--dimension-stroke-width-012);\n --ds-interaction-border-color: var(--ds-button-filled-border);\n}\n\n/* Preserve the border while inactive, when interaction-fill is intentionally omitted. */\n.button-filled--bordered:not(.ds-interaction-fill) {\n box-shadow: inset 0 0 0 var(--ds-interaction-border-width) var(--ds-interaction-border-color);\n}\n\n/*\n * Parent-surface context affects only the optional inset border.\n * Intent + contrast continue to own fill, foreground, and interaction overlays.\n */\n.button-filled--background-medium {\n --ds-button-filled-border: var(--color-border-on-medium-background-secondary);\n}\n\n.button-filled--background-bold {\n --ds-button-filled-border: var(--color-border-on-bold-background-secondary);\n}\n\n.button-filled--background-strong {\n --ds-button-filled-border: var(--color-border-on-strong-background-secondary);\n}\n\n.button-filled--background-translucent {\n --ds-button-filled-border: var(--color-translucent-border-secondary);\n}\n\n.button-filled--background-inverted {\n --ds-button-filled-border: var(--color-inverted-border-secondary);\n}\n\n.button-filled--background-media {\n --ds-button-filled-border: var(--color-media-border-secondary);\n}\n\n.button-filled--background-always-dark {\n --ds-button-filled-border: var(--color-always-dark-border-secondary);\n}\n\n.button-filled:active:not(:disabled):not(.ds-control-inactive) {\n transform: scale(var(--dimension-scale-subtle));\n}\n\n@media (prefers-reduced-motion: reduce) {\n .button-filled {\n transition:\n background-color var(--effect-motion-short-2),\n color var(--effect-motion-short-2);\n }\n\n .button-filled:active:not(:disabled):not(.ds-control-inactive) {\n transform: none;\n }\n}\n\n/* Inactive: `.ds-control-inactive` (25% opacity). */\n\n.button-filled__icon-wrap {\n position: relative;\n width: var(--ds-control-icon, var(--dimension-iconography-md));\n height: var(--ds-control-icon, var(--dimension-iconography-md));\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n z-index: 2;\n}\n\n.button-filled__label {\n position: relative;\n z-index: 2;\n padding: 0 var(--ds-control-label-inset, var(--dimension-space-025));\n white-space: nowrap;\n flex-shrink: 0;\n min-width: 0;\n}\n\n.button-filled__label--loading {\n visibility: hidden;\n}\n\n.button-filled > .button-filled__loader-overlay {\n position: absolute;\n inset: 0;\n z-index: 2;\n display: flex;\n align-items: center;\n justify-content: center;\n pointer-events: none;\n}\n\n/* ── Intent + contrast (bold default) ─────────────────────────────────────── */\n\n.button-filled--intent-neutral {\n --ds-button-filled-bg: var(--color-background-bold-neutral);\n --ds-button-filled-fg: var(--color-foreground-faint-neutral);\n}\n\n.button-filled--intent-brand {\n --ds-button-filled-bg: var(--color-background-bold-brand);\n --ds-button-filled-fg: var(--color-foreground-faint-brand);\n}\n\n.button-filled--intent-ai {\n --ds-button-filled-bg: var(--color-background-bold-ai);\n --ds-button-filled-fg: var(--color-foreground-faint-ai);\n}\n\n.button-filled--intent-negative {\n --ds-button-filled-bg: var(--color-background-bold-negative);\n --ds-button-filled-fg: var(--color-foreground-faint-negative);\n}\n\n.button-filled--intent-warning {\n --ds-button-filled-bg: var(--color-background-bold-warning);\n --ds-button-filled-fg: var(--color-foreground-faint-warning);\n}\n\n.button-filled--intent-caution {\n --ds-button-filled-bg: var(--color-background-bold-caution);\n --ds-button-filled-fg: var(--color-foreground-faint-caution);\n}\n\n.button-filled--intent-positive {\n --ds-button-filled-bg: var(--color-background-bold-positive);\n --ds-button-filled-fg: var(--color-foreground-faint-positive);\n}\n\n.button-filled--intent-guide {\n --ds-button-filled-bg: var(--color-background-bold-guide);\n --ds-button-filled-fg: var(--color-foreground-faint-guide);\n}\n\n.button-filled--intent-walkthrough {\n --ds-button-filled-bg: var(--color-background-bold-walkthrough);\n --ds-button-filled-fg: var(--color-foreground-faint-walkthrough);\n}\n\n/* strong → medium fg */\n.button-filled--contrast-strong.button-filled--intent-neutral {\n --ds-button-filled-bg: var(--color-background-strong-neutral);\n --ds-button-filled-fg: var(--color-foreground-medium-neutral);\n}\n\n.button-filled--contrast-strong.button-filled--intent-brand {\n --ds-button-filled-bg: var(--color-background-strong-brand);\n --ds-button-filled-fg: var(--color-foreground-medium-brand);\n}\n\n.button-filled--contrast-strong.button-filled--intent-ai {\n --ds-button-filled-bg: var(--color-background-strong-ai);\n --ds-button-filled-fg: var(--color-foreground-medium-ai);\n}\n\n.button-filled--contrast-strong.button-filled--intent-negative {\n --ds-button-filled-bg: var(--color-background-strong-negative);\n --ds-button-filled-fg: var(--color-foreground-medium-negative);\n}\n\n.button-filled--contrast-strong.button-filled--intent-warning {\n --ds-button-filled-bg: var(--color-background-strong-warning);\n --ds-button-filled-fg: var(--color-foreground-medium-warning);\n}\n\n.button-filled--contrast-strong.button-filled--intent-caution {\n --ds-button-filled-bg: var(--color-background-strong-caution);\n --ds-button-filled-fg: var(--color-foreground-medium-caution);\n}\n\n.button-filled--contrast-strong.button-filled--intent-positive {\n --ds-button-filled-bg: var(--color-background-strong-positive);\n --ds-button-filled-fg: var(--color-foreground-medium-positive);\n}\n\n.button-filled--contrast-strong.button-filled--intent-guide {\n --ds-button-filled-bg: var(--color-background-strong-guide);\n --ds-button-filled-fg: var(--color-foreground-medium-guide);\n}\n\n.button-filled--contrast-strong.button-filled--intent-walkthrough {\n --ds-button-filled-bg: var(--color-background-strong-walkthrough);\n --ds-button-filled-fg: var(--color-foreground-medium-walkthrough);\n}\n\n/* medium → strong fg */\n.button-filled--contrast-medium.button-filled--intent-neutral {\n --ds-button-filled-bg: var(--color-background-medium-neutral);\n --ds-button-filled-fg: var(--color-foreground-strong-neutral);\n}\n\n.button-filled--contrast-medium.button-filled--intent-brand {\n --ds-button-filled-bg: var(--color-background-medium-brand);\n --ds-button-filled-fg: var(--color-foreground-strong-brand);\n}\n\n.button-filled--contrast-medium.button-filled--intent-ai {\n --ds-button-filled-bg: var(--color-background-medium-ai);\n --ds-button-filled-fg: var(--color-foreground-strong-ai);\n}\n\n.button-filled--contrast-medium.button-filled--intent-negative {\n --ds-button-filled-bg: var(--color-background-medium-negative);\n --ds-button-filled-fg: var(--color-foreground-strong-negative);\n}\n\n.button-filled--contrast-medium.button-filled--intent-warning {\n --ds-button-filled-bg: var(--color-background-medium-warning);\n --ds-button-filled-fg: var(--color-foreground-strong-warning);\n}\n\n.button-filled--contrast-medium.button-filled--intent-caution {\n --ds-button-filled-bg: var(--color-background-medium-caution);\n --ds-button-filled-fg: var(--color-foreground-strong-caution);\n}\n\n.button-filled--contrast-medium.button-filled--intent-positive {\n --ds-button-filled-bg: var(--color-background-medium-positive);\n --ds-button-filled-fg: var(--color-foreground-strong-positive);\n}\n\n.button-filled--contrast-medium.button-filled--intent-guide {\n --ds-button-filled-bg: var(--color-background-medium-guide);\n --ds-button-filled-fg: var(--color-foreground-strong-guide);\n}\n\n.button-filled--contrast-medium.button-filled--intent-walkthrough {\n --ds-button-filled-bg: var(--color-background-medium-walkthrough);\n --ds-button-filled-fg: var(--color-foreground-strong-walkthrough);\n}\n\n/* faint → bold fg */\n.button-filled--contrast-faint.button-filled--intent-neutral {\n --ds-button-filled-bg: var(--color-background-faint-neutral);\n --ds-button-filled-fg: var(--color-foreground-bold-neutral);\n}\n\n.button-filled--contrast-faint.button-filled--intent-brand {\n --ds-button-filled-bg: var(--color-background-faint-brand);\n --ds-button-filled-fg: var(--color-foreground-bold-brand);\n}\n\n.button-filled--contrast-faint.button-filled--intent-ai {\n --ds-button-filled-bg: var(--color-background-faint-ai);\n --ds-button-filled-fg: var(--color-foreground-bold-ai);\n}\n\n.button-filled--contrast-faint.button-filled--intent-negative {\n --ds-button-filled-bg: var(--color-background-faint-negative);\n --ds-button-filled-fg: var(--color-foreground-bold-negative);\n}\n\n.button-filled--contrast-faint.button-filled--intent-warning {\n --ds-button-filled-bg: var(--color-background-faint-warning);\n --ds-button-filled-fg: var(--color-foreground-bold-warning);\n}\n\n.button-filled--contrast-faint.button-filled--intent-caution {\n --ds-button-filled-bg: var(--color-background-faint-caution);\n --ds-button-filled-fg: var(--color-foreground-bold-caution);\n}\n\n.button-filled--contrast-faint.button-filled--intent-positive {\n --ds-button-filled-bg: var(--color-background-faint-positive);\n --ds-button-filled-fg: var(--color-foreground-bold-positive);\n}\n\n.button-filled--contrast-faint.button-filled--intent-guide {\n --ds-button-filled-bg: var(--color-background-faint-guide);\n --ds-button-filled-fg: var(--color-foreground-bold-guide);\n}\n\n.button-filled--contrast-faint.button-filled--intent-walkthrough {\n --ds-button-filled-bg: var(--color-background-faint-walkthrough);\n --ds-button-filled-fg: var(--color-foreground-bold-walkthrough);\n}\n",
|
|
378
414
|
"type": "registry:ui"
|
|
379
415
|
},
|
|
380
416
|
{
|
|
381
417
|
"path": "src/wc/components/ButtonFilled/ButtonFilled.tsx",
|
|
382
|
-
"content": "import { Component, Element, Event, EventEmitter, h, Host, Method, Prop } from '@stencil/core';\nimport { controlWidthClass, CONTROL_TEXT_VARIANT, type ControlWidth } from '../../utils';\n\nexport type ButtonFilledIntent =\n | 'neutral'\n | 'brand'\n | 'ai'\n | 'negative'\n | 'warning'\n | 'caution'\n | 'positive'\n | 'guide'\n | 'walkthrough';\n\nexport type ButtonFilledContrast = 'bold' | 'strong' | 'medium' | 'faint';\n\nexport type ButtonFilledVariant = 'icon' | 'label' | 'icon-label';\n\nexport type ButtonFilledSize = 'md' | 'sm' | 'xs';\n\nexport type ButtonFilledWidth = ControlWidth;\n\n/**\n * `ds-icon` size prop matching control-density icon metrics\n * (md→20 / sm→16 / xs→12 via `--dimension-iconography-*`).\n */\nconst ICON_SIZE: Record<ButtonFilledSize, 'md' | 'sm' | 'xs'> = {\n md: 'md',\n sm: 'sm',\n xs: 'xs',\n};\n\n@Component({\n tag: 'ds-button-filled',\n styleUrl: 'ButtonFilled.css',\n scoped: true,\n})\nexport class ButtonFilled {\n @Element() el!: HTMLElement;\n\n /**\n * Content layout. Default is label-only; pass `icon` for icon-only chrome\n * (nav / tool rails) or `icon-label` for leading icon + text.\n */\n @Prop() variant: ButtonFilledVariant = 'label';\n\n /** Control density (height, padding, icon, type). */\n @Prop() size: ButtonFilledSize = 'md';\n\n /** Width fit — hug content (default) or fill the parent. */\n @Prop() width: ButtonFilledWidth = 'hug';\n\n /** Visible text for `label` / `icon-label` variants. */\n @Prop() label: string = '';\n\n /** Icon name passed to <ds-icon> for `icon` / `icon-label` variants. */\n @Prop() icon: string = '';\n\n /** Semantic colour intent. */\n @Prop() intent: ButtonFilledIntent = 'brand';\n\n /**\n * Background fill weight. Foreground uses the paired contrast token:\n * bold → faint, strong → medium, medium → strong, faint → bold.\n */\n @Prop() contrast: ButtonFilledContrast = 'bold';\n\n /** Use the half-radius treatment instead of the default control radius. */\n @Prop() rounded: boolean = false;\n\n /** Disables interaction. */\n @Prop() isInactive: boolean = false;\n\n /** Shows an inline loader and prevents interaction without applying inactive opacity. */\n @Prop() isLoading: boolean = false;\n\n /** Native button type. */\n @Prop() type: 'button' | 'submit' | 'reset' = 'button';\n\n /** Accessible name override. Required for icon-only buttons. */\n @Prop({ attribute: 'aria-label' }) ariaLabel: string | null = null;\n\n @Event() dsClick!: EventEmitter<MouseEvent>;\n\n private buttonEl: HTMLButtonElement | null = null;\n\n @Method()\n async setFocus() {\n this.buttonEl?.focus();\n }\n\n private handleClick = (event: MouseEvent) => {\n if (this.isInactive || this.isLoading) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n this.dsClick.emit(event);\n };\n\n private get showIcon(): boolean {\n return this.variant === 'icon' || this.variant === 'icon-label';\n }\n\n private get showLabel(): boolean {\n return this.variant === 'label' || this.variant === 'icon-label';\n }\n\n private get accessibleName(): string | undefined {\n if (this.ariaLabel) return this.ariaLabel;\n if (this.isLoading && this.variant === 'label' && this.label) return this.label;\n return undefined;\n }\n\n render() {\n const textVariant = CONTROL_TEXT_VARIANT[this.size];\n const iconSize = ICON_SIZE[this.size];\n\n const cls: Record<string, boolean> = {\n 'button-filled': true,\n 'ds-focus-ring-inset': true,\n 'ds-interaction-fill': !this.isInactive,\n /* Bold is the default filled contrast — on-bold interaction tokens. */\n 'ds-interaction-fill--on-bold': this.contrast === 'bold',\n 'ds-interaction-fill--on-strong': this.contrast === 'strong',\n 'ds-interaction-fill--on-medium': this.contrast === 'medium',\n /* faint → default app interaction tokens (no --on-*). */\n 'ds-control-inactive': this.isInactive,\n 'ds-control--md': this.size === 'md',\n 'ds-control--sm': this.size === 'sm',\n 'ds-control--xs': this.size === 'xs',\n 'button-filled--icon': this.variant === 'icon',\n 'button-filled--label': this.variant === 'label',\n 'button-filled--icon-label': this.variant === 'icon-label',\n 'button-filled--rounded': this.rounded,\n [`button-filled--intent-${this.intent}`]: true,\n [`button-filled--contrast-${this.contrast}`]: this.contrast !== 'bold',\n };\n\n return (\n <Host\n class={{\n 'button-filled-host': true,\n 'button-filled-host--icon': this.variant === 'icon',\n 'ds-control--md': this.size === 'md',\n 'ds-control--sm': this.size === 'sm',\n 'ds-control--xs': this.size === 'xs',\n ...controlWidthClass(this.width),\n }}\n tabIndex={-1}\n >\n <button\n ref={el => {\n this.buttonEl = el ?? null;\n }}\n type={this.type}\n class={cls}\n disabled={this.isInactive}\n aria-label={this.accessibleName}\n aria-busy={this.isLoading ? 'true' : undefined}\n aria-disabled={this.isLoading ? 'true' : undefined}\n onClick={this.handleClick}\n >\n {this.showIcon && (\n <span class=\"button-filled__icon-wrap ds-interaction-fill__content\">\n {this.isLoading\n ? <ds-loader size={iconSize} color=\"inherit\" />\n : <ds-icon name={this.icon} size={iconSize} color=\"inherit\" />\n }\n </span>\n )}\n {this.showLabel && (\n <ds-text\n class={{\n 'button-filled__label': true,\n 'button-filled__label--loading': this.isLoading && this.variant === 'label',\n 'ds-interaction-fill__content': true,\n }}\n as=\"span\"\n variant={textVariant}\n emphasis\n color=\"inherit\"\n >\n {this.label}\n </ds-text>\n )}\n {this.isLoading && this.variant === 'label' && (\n <span class=\"button-filled__loader-overlay ds-interaction-fill__content\">\n <ds-loader size={iconSize} color=\"inherit\" />\n </span>\n )}\n </button>\n </Host>\n );\n }\n}\n",
|
|
418
|
+
"content": "import { Component, Element, Event, EventEmitter, h, Host, Method, Prop } from '@stencil/core';\nimport { controlWidthClass, CONTROL_TEXT_VARIANT, type ControlWidth } from '../../utils';\nimport type { ChoiceBackground } from '../../utils/choice-list';\n\nexport type ButtonFilledIntent =\n | 'neutral'\n | 'brand'\n | 'ai'\n | 'negative'\n | 'warning'\n | 'caution'\n | 'positive'\n | 'guide'\n | 'walkthrough';\n\nexport type ButtonFilledContrast = 'bold' | 'strong' | 'medium' | 'faint';\n\nexport type ButtonFilledBackground = ChoiceBackground;\n\nexport type ButtonFilledVariant = 'icon' | 'label' | 'icon-label';\n\nexport type ButtonFilledSize = 'md' | 'sm' | 'xs';\n\nexport type ButtonFilledWidth = ControlWidth;\n\n/**\n * `ds-icon` size prop matching control-density icon metrics\n * (md→20 / sm→16 / xs→12 via `--dimension-iconography-*`).\n */\nconst ICON_SIZE: Record<ButtonFilledSize, 'md' | 'sm' | 'xs'> = {\n md: 'md',\n sm: 'sm',\n xs: 'xs',\n};\n\n@Component({\n tag: 'ds-button-filled',\n styleUrl: 'ButtonFilled.css',\n scoped: true,\n})\nexport class ButtonFilled {\n @Element() el!: HTMLElement;\n\n /**\n * Content layout. Default is label-only; pass `icon` for icon-only chrome\n * (nav / tool rails) or `icon-label` for leading icon + text.\n */\n @Prop() variant: ButtonFilledVariant = 'label';\n\n /** Control density (height, padding, icon, type). */\n @Prop() size: ButtonFilledSize = 'md';\n\n /** Width fit — hug content (default) or fill the parent. */\n @Prop() width: ButtonFilledWidth = 'hug';\n\n /** Visible text for `label` / `icon-label` variants. */\n @Prop() label: string = '';\n\n /** Icon name passed to <ds-icon> for `icon` / `icon-label` variants. */\n @Prop() icon: string = '';\n\n /** Semantic colour intent. */\n @Prop() intent: ButtonFilledIntent = 'brand';\n\n /**\n * Background fill weight. Foreground uses the paired contrast token:\n * bold → faint, strong → medium, medium → strong, faint → bold.\n */\n @Prop() contrast: ButtonFilledContrast = 'bold';\n\n /** Show a 1px secondary inset border. */\n @Prop() hasBorder: boolean = false;\n\n /**\n * Actual parent surface context for the optional inset border color only.\n * Omit on primary and secondary surfaces.\n */\n @Prop() background: ButtonFilledBackground | undefined;\n\n /** Use the half-radius treatment instead of the default control radius. */\n @Prop() rounded: boolean = false;\n\n /** Disables interaction. */\n @Prop() isInactive: boolean = false;\n\n /** Shows an inline loader and prevents interaction without applying inactive opacity. */\n @Prop() isLoading: boolean = false;\n\n /** Native button type. */\n @Prop() type: 'button' | 'submit' | 'reset' = 'button';\n\n /** Accessible name override. Required for icon-only buttons. */\n @Prop({ attribute: 'aria-label' }) ariaLabel: string | null = null;\n\n @Event() dsClick!: EventEmitter<MouseEvent>;\n\n private buttonEl: HTMLButtonElement | null = null;\n\n @Method()\n async setFocus() {\n this.buttonEl?.focus();\n }\n\n private handleClick = (event: MouseEvent) => {\n if (this.isInactive || this.isLoading) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n this.dsClick.emit(event);\n };\n\n private get showIcon(): boolean {\n return this.variant === 'icon' || this.variant === 'icon-label';\n }\n\n private get showLabel(): boolean {\n return this.variant === 'label' || this.variant === 'icon-label';\n }\n\n private get accessibleName(): string | undefined {\n if (this.ariaLabel) return this.ariaLabel;\n if (this.isLoading && this.variant === 'label' && this.label) return this.label;\n return undefined;\n }\n\n render() {\n const textVariant = CONTROL_TEXT_VARIANT[this.size];\n const iconSize = ICON_SIZE[this.size];\n\n const cls: Record<string, boolean> = {\n 'button-filled': true,\n 'ds-focus-ring-inset': true,\n 'ds-interaction-fill': !this.isInactive,\n /* Bold is the default filled contrast — on-bold interaction tokens. */\n 'ds-interaction-fill--on-bold': this.contrast === 'bold',\n 'ds-interaction-fill--on-strong': this.contrast === 'strong',\n 'ds-interaction-fill--on-medium': this.contrast === 'medium',\n /* faint → default app interaction tokens (no --on-*). */\n 'button-filled--bordered': this.hasBorder,\n 'ds-control-inactive': this.isInactive,\n 'ds-control--md': this.size === 'md',\n 'ds-control--sm': this.size === 'sm',\n 'ds-control--xs': this.size === 'xs',\n 'button-filled--icon': this.variant === 'icon',\n 'button-filled--label': this.variant === 'label',\n 'button-filled--icon-label': this.variant === 'icon-label',\n 'button-filled--rounded': this.rounded,\n [`button-filled--background-${this.background}`]: this.background !== undefined,\n [`button-filled--intent-${this.intent}`]: true,\n [`button-filled--contrast-${this.contrast}`]: this.contrast !== 'bold',\n };\n\n return (\n <Host\n class={{\n 'button-filled-host': true,\n 'button-filled-host--icon': this.variant === 'icon',\n 'ds-control--md': this.size === 'md',\n 'ds-control--sm': this.size === 'sm',\n 'ds-control--xs': this.size === 'xs',\n ...controlWidthClass(this.width),\n }}\n tabIndex={-1}\n >\n <button\n ref={el => {\n this.buttonEl = el ?? null;\n }}\n type={this.type}\n class={cls}\n disabled={this.isInactive}\n aria-label={this.accessibleName}\n aria-busy={this.isLoading ? 'true' : undefined}\n aria-disabled={this.isLoading ? 'true' : undefined}\n onClick={this.handleClick}\n >\n {this.showIcon && (\n <span class=\"button-filled__icon-wrap ds-interaction-fill__content\">\n {this.isLoading\n ? <ds-loader size={iconSize} color=\"inherit\" />\n : <ds-icon name={this.icon} size={iconSize} color=\"inherit\" />\n }\n </span>\n )}\n {this.showLabel && (\n <ds-text\n class={{\n 'button-filled__label': true,\n 'button-filled__label--loading': this.isLoading && this.variant === 'label',\n 'ds-interaction-fill__content': true,\n }}\n as=\"span\"\n variant={textVariant}\n emphasis\n color=\"inherit\"\n >\n {this.label}\n </ds-text>\n )}\n {this.isLoading && this.variant === 'label' && (\n <span class=\"button-filled__loader-overlay ds-interaction-fill__content\">\n <ds-loader size={iconSize} color=\"inherit\" />\n </span>\n )}\n </button>\n </Host>\n );\n }\n}\n",
|
|
383
419
|
"type": "registry:ui"
|
|
384
420
|
}
|
|
385
421
|
]
|