@ds-mo/ui 14.22.2 → 14.24.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/.package-ready.json +1 -1
- package/dist/agent-patterns.json +14 -7
- package/dist/agent.json +112 -26
- package/dist/angular/ds-bar-title.d.ts +1 -1
- package/dist/angular/ds-bar-title.js +3 -3
- package/dist/angular/ds-button-filled.d.ts +3 -1
- package/dist/angular/ds-button-filled.js +7 -4
- package/dist/angular/ds-button-unfilled.d.ts +3 -1
- package/dist/angular/ds-button-unfilled.js +7 -4
- package/dist/angular/ds-panel-tools.d.ts +7 -1
- package/dist/angular/ds-panel-tools.js +7 -4
- package/dist/angular/ds-shell-app.d.ts +7 -1
- package/dist/angular/ds-shell-app.js +5 -2
- package/dist/angular/ds-shell-tools.d.ts +4 -1
- package/dist/angular/ds-shell-tools.js +7 -4
- package/dist/components/ds-agent-questionnaire.js +1 -1
- package/dist/components/ds-agent-response.js +1 -1
- package/dist/components/ds-banner.js +1 -1
- package/dist/components/ds-bar-nav.js +1 -1
- package/dist/components/ds-bar-title.js +1 -1
- package/dist/components/ds-bar-workflow.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-chart.js +1 -1
- package/dist/components/ds-card-setting.js +1 -1
- package/dist/components/ds-code-block.js +1 -1
- package/dist/components/ds-filter-menu.js +1 -1
- package/dist/components/ds-input.js +1 -1
- package/dist/components/ds-markdown.js +1 -1
- package/dist/components/ds-message-actions.js +1 -1
- package/dist/components/ds-message-composer.js +1 -1
- package/dist/components/ds-message-scroller.js +1 -1
- package/dist/components/ds-message-scroller.js.map +1 -1
- package/dist/components/ds-mobile-sheet-nav.js +1 -1
- package/dist/components/ds-modal.js +1 -1
- package/dist/components/ds-pagination.js +1 -1
- package/dist/components/ds-panel-nav.js +1 -1
- package/dist/components/ds-panel-tool-header.js +1 -1
- package/dist/components/ds-panel-tool-search.js +1 -1
- package/dist/components/ds-panel-tools.js +1 -1
- package/dist/components/ds-select.js +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-tools.js +1 -1
- package/dist/components/ds-table-filter.js +1 -1
- package/dist/components/ds-table-group.js +1 -1
- package/dist/components/ds-table-saved-views.js +1 -1
- package/dist/components/ds-table-search.js +1 -1
- package/dist/components/ds-table-sort.js +1 -1
- package/dist/components/ds-table.js +1 -1
- package/dist/components/ds-toast.js +1 -1
- package/dist/components/p-BR1ayqMU.js +2 -0
- package/dist/components/p-BR1ayqMU.js.map +1 -0
- package/dist/components/{p-DzVYGJJv.js → p-BSRIF4m8.js} +2 -2
- package/dist/components/{p-FitB53eM.js → p-BZlhBJZL.js} +2 -2
- package/dist/components/{p-BmqnrfTf.js → p-Bo6uW_8T.js} +2 -2
- package/dist/components/{p-BIaHDBfP.js → p-Bq8svcPs.js} +2 -2
- package/dist/components/{p-DAFR4U9P.js → p-BqbdABo3.js} +2 -2
- package/dist/components/{p-nVv71P3f.js → p-CEXchU5N.js} +2 -2
- package/dist/components/p-CEfxLsbX.js +2 -0
- package/dist/components/p-CEfxLsbX.js.map +1 -0
- package/dist/components/{p-DXbryJHz.js → p-CYMKmJ2s.js} +2 -2
- package/dist/components/p-CZHIkVgj.js +2 -0
- package/dist/components/p-CZHIkVgj.js.map +1 -0
- package/dist/components/{p-CL0tECXf.js → p-CZjjDhUl.js} +2 -2
- package/dist/components/p-C_FFU6W3.js +2 -0
- package/dist/components/p-C_FFU6W3.js.map +1 -0
- package/dist/components/{p-CilwchJH.js → p-CglHiyY2.js} +2 -2
- package/dist/components/{p-9M0ak2q_.js → p-DLaN9BPq.js} +2 -2
- package/dist/components/{p-CrYJnDev.js → p-DiS5BgLA.js} +2 -2
- package/dist/components/{p-DiyO47xX.js → p-PXdvBMXB.js} +2 -2
- package/dist/components/{p-7MWaWl8w.js → p-kslioYhf.js} +2 -2
- package/dist/components/p-kslioYhf.js.map +1 -0
- package/dist/docs/components.json +434 -32
- package/dist/lib/components/BarTitle/bar-title-types.d.ts +54 -1
- package/dist/lib/components/ButtonFilled/ButtonFilled.d.ts +12 -1
- package/dist/lib/components/PanelTools/panel-tools-types.d.ts +76 -1
- package/dist/lib/components/ShellApp/shell-app-types.d.ts +6 -2
- package/dist/lib/shell/index.d.ts +2 -1
- package/dist/lib/shell/index.js.map +2 -2
- package/dist/mcp-data/registry/agent-activity.json +1 -1
- package/dist/mcp-data/registry/agent-questionnaire.json +1 -1
- package/dist/mcp-data/registry/agent-response.json +1 -1
- package/dist/mcp-data/registry/agent-source-list.json +1 -1
- package/dist/mcp-data/registry/agent-tool-call.json +1 -1
- package/dist/mcp-data/registry/attachment-list.json +1 -1
- package/dist/mcp-data/registry/avatar.json +1 -1
- package/dist/mcp-data/registry/badge.json +1 -1
- package/dist/mcp-data/registry/banner.json +1 -1
- package/dist/mcp-data/registry/bar-action.json +1 -1
- package/dist/mcp-data/registry/bar-nav.json +1 -1
- package/dist/mcp-data/registry/bar-title.json +35 -13
- package/dist/mcp-data/registry/bar-workflow.json +1 -1
- package/dist/mcp-data/registry/breadcrumb.json +1 -1
- package/dist/mcp-data/registry/button-filled.json +61 -7
- package/dist/mcp-data/registry/button-unfilled.json +61 -7
- package/dist/mcp-data/registry/card-chart.json +1 -1
- package/dist/mcp-data/registry/card-overview.json +1 -1
- package/dist/mcp-data/registry/card-setting.json +1 -1
- package/dist/mcp-data/registry/chart-legend.json +1 -1
- package/dist/mcp-data/registry/chart.json +1 -1
- package/dist/mcp-data/registry/checkbox.json +1 -1
- package/dist/mcp-data/registry/chip.json +1 -1
- package/dist/mcp-data/registry/code-block.json +1 -1
- package/dist/mcp-data/registry/conversation-list-item.json +1 -1
- package/dist/mcp-data/registry/conversation-list-section.json +1 -1
- package/dist/mcp-data/registry/conversation-list.json +1 -1
- package/dist/mcp-data/registry/divider.json +1 -1
- package/dist/mcp-data/registry/empty-state.json +1 -1
- package/dist/mcp-data/registry/field.json +1 -1
- package/dist/mcp-data/registry/filter-menu.json +1 -1
- package/dist/mcp-data/registry/icon.json +1 -1
- package/dist/mcp-data/registry/input.json +1 -1
- package/dist/mcp-data/registry/loader.json +1 -1
- package/dist/mcp-data/registry/markdown.json +1 -1
- package/dist/mcp-data/registry/menu.json +1 -1
- package/dist/mcp-data/registry/message-actions.json +1 -1
- package/dist/mcp-data/registry/message-bubble.json +1 -1
- package/dist/mcp-data/registry/message-composer.json +1 -1
- package/dist/mcp-data/registry/message-scroller.json +9 -2
- package/dist/mcp-data/registry/message.json +1 -1
- package/dist/mcp-data/registry/mobile-bar-nav.json +1 -1
- package/dist/mcp-data/registry/mobile-header.json +1 -1
- package/dist/mcp-data/registry/mobile-section-switcher.json +1 -1
- package/dist/mcp-data/registry/mobile-sheet-nav.json +1 -1
- package/dist/mcp-data/registry/modal.json +1 -1
- package/dist/mcp-data/registry/pagination.json +1 -1
- package/dist/mcp-data/registry/panel-nav.json +1 -1
- package/dist/mcp-data/registry/panel-sub-nav.json +1 -1
- package/dist/mcp-data/registry/panel-tool-header.json +1 -1
- package/dist/mcp-data/registry/panel-tool-search.json +1 -1
- package/dist/mcp-data/registry/panel-tools.json +62 -15
- package/dist/mcp-data/registry/paper-texture.json +1 -1
- package/dist/mcp-data/registry/radio.json +1 -1
- package/dist/mcp-data/registry/registry.json +112 -26
- package/dist/mcp-data/registry/scroll-overlay.json +1 -1
- package/dist/mcp-data/registry/select.json +1 -1
- package/dist/mcp-data/registry/shell-app.json +26 -3
- package/dist/mcp-data/registry/shell-page.json +1 -1
- package/dist/mcp-data/registry/shell-tools.json +39 -6
- package/dist/mcp-data/registry/skeleton.json +1 -1
- package/dist/mcp-data/registry/slider.json +1 -1
- package/dist/mcp-data/registry/swatch-picker.json +1 -1
- package/dist/mcp-data/registry/switch.json +1 -1
- package/dist/mcp-data/registry/tab-group.json +1 -1
- package/dist/mcp-data/registry/table-filter.json +1 -1
- package/dist/mcp-data/registry/table-group.json +1 -1
- package/dist/mcp-data/registry/table-saved-views.json +1 -1
- package/dist/mcp-data/registry/table-search.json +1 -1
- package/dist/mcp-data/registry/table-sort.json +1 -1
- package/dist/mcp-data/registry/table-toolbar.json +1 -1
- package/dist/mcp-data/registry/table.json +1 -1
- package/dist/mcp-data/registry/tag.json +1 -1
- package/dist/mcp-data/registry/text.json +1 -1
- package/dist/mcp-data/registry/toast.json +1 -1
- package/dist/mcp-data/registry/tooltip-chart.json +1 -1
- package/dist/mcp-data/registry/tooltip.json +1 -1
- package/dist/mcp-data/registry/typing-indicator.json +1 -1
- package/dist/react/ds-button-filled.d.ts +1 -0
- package/dist/react/ds-button-filled.js +4 -1
- package/dist/react/ds-button-unfilled.d.ts +1 -0
- package/dist/react/ds-button-unfilled.js +1 -0
- package/dist/react/ds-panel-tools.d.ts +2 -1
- package/dist/react/ds-panel-tools.js +1 -0
- package/dist/react/ds-shell-app.d.ts +2 -1
- package/dist/react/ds-shell-app.js +1 -0
- package/dist/react/ds-shell-tools.d.ts +2 -1
- package/dist/react/ds-shell-tools.js +2 -1
- package/dist/types/components/BarTitle/BarTitle.d.ts +19 -6
- package/dist/types/components/BarTitle/bar-title-actions.d.ts +11 -0
- package/dist/types/components/BarTitle/bar-title-types.d.ts +54 -1
- package/dist/types/components/BarTitle/index.d.ts +1 -1
- package/dist/types/components/ButtonFilled/ButtonFilled.d.ts +12 -1
- package/dist/types/components/ButtonUnfilled/ButtonUnfilled.d.ts +12 -1
- package/dist/types/components/MessageScroller/MessageScroller.d.ts +14 -0
- package/dist/types/components/MessageScroller/message-scroller-transcript.d.ts +9 -0
- package/dist/types/components/PanelTools/PanelTools.d.ts +17 -1
- package/dist/types/components/PanelTools/index.d.ts +1 -1
- package/dist/types/components/PanelTools/panel-tools-types.d.ts +76 -1
- package/dist/types/components/PanelTools/panel-tools-utils.d.ts +17 -1
- package/dist/types/components/ShellApp/ShellApp.d.ts +16 -1
- package/dist/types/components/ShellApp/shell-app-types.d.ts +6 -2
- package/dist/types/components/ShellTools/ShellTools.d.ts +5 -1
- package/dist/types/components/ShellTools/index.d.ts +1 -1
- package/dist/types/components.d.ts +94 -6
- package/dist/types/shell/index.d.ts +2 -1
- package/dist/types/utils/button-story-foundation.d.ts +2 -0
- package/dist/vue/ds-bar-title.js +1 -0
- package/dist/vue/ds-button-filled.js +6 -2
- package/dist/vue/ds-button-unfilled.js +4 -0
- package/dist/vue/ds-panel-tools.js +3 -0
- package/dist/vue/ds-shell-app.js +2 -0
- package/dist/vue/ds-shell-tools.js +5 -2
- package/package.json +3 -3
- package/dist/components/p--68f7nIx.js +0 -2
- package/dist/components/p--68f7nIx.js.map +0 -1
- package/dist/components/p-7MWaWl8w.js.map +0 -1
- package/dist/components/p-BnTPuV3x.js +0 -2
- package/dist/components/p-BnTPuV3x.js.map +0 -1
- package/dist/components/p-COFw_fcj.js +0 -2
- package/dist/components/p-COFw_fcj.js.map +0 -1
- package/dist/components/p-CvHrCyuz.js +0 -2
- package/dist/components/p-CvHrCyuz.js.map +0 -1
- /package/dist/components/{p-DzVYGJJv.js.map → p-BSRIF4m8.js.map} +0 -0
- /package/dist/components/{p-FitB53eM.js.map → p-BZlhBJZL.js.map} +0 -0
- /package/dist/components/{p-BmqnrfTf.js.map → p-Bo6uW_8T.js.map} +0 -0
- /package/dist/components/{p-BIaHDBfP.js.map → p-Bq8svcPs.js.map} +0 -0
- /package/dist/components/{p-DAFR4U9P.js.map → p-BqbdABo3.js.map} +0 -0
- /package/dist/components/{p-nVv71P3f.js.map → p-CEXchU5N.js.map} +0 -0
- /package/dist/components/{p-DXbryJHz.js.map → p-CYMKmJ2s.js.map} +0 -0
- /package/dist/components/{p-CL0tECXf.js.map → p-CZjjDhUl.js.map} +0 -0
- /package/dist/components/{p-CilwchJH.js.map → p-CglHiyY2.js.map} +0 -0
- /package/dist/components/{p-9M0ak2q_.js.map → p-DLaN9BPq.js.map} +0 -0
- /package/dist/components/{p-CrYJnDev.js.map → p-DiS5BgLA.js.map} +0 -0
- /package/dist/components/{p-DiyO47xX.js.map → p-PXdvBMXB.js.map} +0 -0
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
"A secondary command accompanies the single filled primary action in a local decision area.",
|
|
19
19
|
"A toolbar, tool rail, overflow area, or shell region needs a compact icon action.",
|
|
20
20
|
"A command represents a persistent toggle or mode whose active state remains meaningful after activation.",
|
|
21
|
-
"A row, card, or toolbar needs an overflow or more-options menu; this is the only component that carries that role."
|
|
21
|
+
"A row, card, or toolbar needs an overflow or more-options menu; this is the only component that carries that role.",
|
|
22
|
+
"A secondary command has closely related alternatives and needs split mode without losing its border, surface, active, variant, or loading treatment."
|
|
22
23
|
],
|
|
23
24
|
"avoidWhen": [
|
|
24
25
|
"The command is the single primary action in a local decision area; use ButtonFilled instead.",
|
|
@@ -53,6 +54,7 @@
|
|
|
53
54
|
],
|
|
54
55
|
"accessibility": [
|
|
55
56
|
"Provide an explicit accessible name for every icon-only action.",
|
|
57
|
+
"In split mode, provide menuAriaLabel for the appended ChevronDown segment, pass controls with the Menu id, and synchronize expanded with the Menu open state.",
|
|
56
58
|
"Set hasMenu when the button triggers a Menu; it implies aria-haspopup of menu. Pass controls with the Menu id and expanded from the same open state given to Menu. Expanded popup triggers hold only the pressed wash while open, without changing their resting foreground; expanded disclosure controls without popup semantics retain the normal resting appearance.",
|
|
57
59
|
"Give an icon-only menu button an accessible name that states the role, such as More options or Customize table, because no visible label or chevron carries it.",
|
|
58
60
|
"Use haspopup directly for a non-menu popup such as a listbox or dialog; those cases get no chevron.",
|
|
@@ -78,7 +80,9 @@
|
|
|
78
80
|
"Icon and icon-label loading replace the icon in place. Label-only loading centers the loader while preserving the button's measured width.",
|
|
79
81
|
"hasMenu covers two distinct menu-button shapes and the variant selects between them. With label or icon-label the action has a menu, and a trailing chevron carries the affordance. With icon the button is a menu and no chevron is added.",
|
|
80
82
|
"Because the icon-only shape has no chevron, its glyph must convey the menu on its own. Use Ellipses for a generic more-options or overflow control. Use a specific icon when the menu has a named purpose, such as Table for Customize table.",
|
|
81
|
-
"An open popup is a transient pressed state rather than a selected one. While expanded is true and haspopup or hasMenu identifies a popup, the pressed wash is held for the popup's complete rendered lifecycle and survives hover without promoting foreground or selected fill, including when chrome opts out of selected fills with activeFill set to false. Expanded disclosure buttons without popup semantics remain visually neutral."
|
|
83
|
+
"An open popup is a transient pressed state rather than a selected one. While expanded is true and haspopup or hasMenu identifies a popup, the pressed wash is held for the popup's complete rendered lifecycle and survives hover without promoting foreground or selected fill, including when chrome opts out of selected fills with activeFill set to false. Expanded disclosure buttons without popup semantics remain visually neutral.",
|
|
84
|
+
"Split mode supports label, icon, and icon-label primary segments. The primary segment emits dsClick and the appended menu segment emits dsMenuClick.",
|
|
85
|
+
"Split mode keeps both segments flush and uses a tertiary surface-aware separator. Bordered mode also preserves the shared outer border; borderless mode limits the separator to the content line height."
|
|
82
86
|
],
|
|
83
87
|
"responsiveBehavior": [
|
|
84
88
|
"The consuming layout decides when an icon-label action becomes icon-only and must provide an explicit accessible name after changing variants. Table caption Customize is one such layout: below 900px it uses the icon shape while keeping the same neutral resting foreground regardless of the controlled column configuration.",
|
|
@@ -270,6 +274,15 @@
|
|
|
270
274
|
"mutable": false,
|
|
271
275
|
"description": "Whether the visible label uses the emphasized weight."
|
|
272
276
|
},
|
|
277
|
+
"menuAriaLabel": {
|
|
278
|
+
"type": "string",
|
|
279
|
+
"resolvedType": "string",
|
|
280
|
+
"attribute": "menu-aria-label",
|
|
281
|
+
"default": "'More options'",
|
|
282
|
+
"required": false,
|
|
283
|
+
"mutable": false,
|
|
284
|
+
"description": "Accessible name for the appended menu segment in split mode."
|
|
285
|
+
},
|
|
273
286
|
"pressScale": {
|
|
274
287
|
"type": "boolean",
|
|
275
288
|
"resolvedType": "boolean",
|
|
@@ -305,6 +318,15 @@
|
|
|
305
318
|
"mutable": false,
|
|
306
319
|
"description": "Control density (height, padding, icon, type)."
|
|
307
320
|
},
|
|
321
|
+
"split": {
|
|
322
|
+
"type": "boolean",
|
|
323
|
+
"resolvedType": "boolean",
|
|
324
|
+
"attribute": "split",
|
|
325
|
+
"default": "false",
|
|
326
|
+
"required": false,
|
|
327
|
+
"mutable": false,
|
|
328
|
+
"description": "Append a separate ChevronDown menu segment while preserving this button's\nvariant, size, surface, active, loading, border, and width treatment."
|
|
329
|
+
},
|
|
308
330
|
"type": {
|
|
309
331
|
"type": "'button' | 'submit' | 'reset'",
|
|
310
332
|
"resolvedType": "\"button\" | \"reset\" | \"submit\"",
|
|
@@ -347,12 +369,19 @@
|
|
|
347
369
|
"bubbles": true,
|
|
348
370
|
"cancelable": true,
|
|
349
371
|
"composed": true
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
"name": "dsMenuClick",
|
|
375
|
+
"detail": "MouseEvent",
|
|
376
|
+
"bubbles": true,
|
|
377
|
+
"cancelable": true,
|
|
378
|
+
"composed": true
|
|
350
379
|
}
|
|
351
380
|
],
|
|
352
381
|
"methods": [
|
|
353
382
|
{
|
|
354
383
|
"name": "setFocus",
|
|
355
|
-
"signature": "setFocus() => Promise<void>"
|
|
384
|
+
"signature": "setFocus(segment?: \"primary\" | \"menu\") => Promise<void>"
|
|
356
385
|
}
|
|
357
386
|
],
|
|
358
387
|
"slots": []
|
|
@@ -522,6 +551,15 @@
|
|
|
522
551
|
"mutable": false,
|
|
523
552
|
"description": "Whether the visible label uses the emphasized weight."
|
|
524
553
|
},
|
|
554
|
+
"menuAriaLabel": {
|
|
555
|
+
"type": "string",
|
|
556
|
+
"resolvedType": "string",
|
|
557
|
+
"attribute": "menu-aria-label",
|
|
558
|
+
"default": "'More options'",
|
|
559
|
+
"required": false,
|
|
560
|
+
"mutable": false,
|
|
561
|
+
"description": "Accessible name for the appended menu segment in split mode."
|
|
562
|
+
},
|
|
525
563
|
"pressScale": {
|
|
526
564
|
"type": "boolean",
|
|
527
565
|
"resolvedType": "boolean",
|
|
@@ -557,6 +595,15 @@
|
|
|
557
595
|
"mutable": false,
|
|
558
596
|
"description": "Control density (height, padding, icon, type)."
|
|
559
597
|
},
|
|
598
|
+
"split": {
|
|
599
|
+
"type": "boolean",
|
|
600
|
+
"resolvedType": "boolean",
|
|
601
|
+
"attribute": "split",
|
|
602
|
+
"default": "false",
|
|
603
|
+
"required": false,
|
|
604
|
+
"mutable": false,
|
|
605
|
+
"description": "Append a separate ChevronDown menu segment while preserving this button's\nvariant, size, surface, active, loading, border, and width treatment."
|
|
606
|
+
},
|
|
560
607
|
"type": {
|
|
561
608
|
"type": "'button' | 'submit' | 'reset'",
|
|
562
609
|
"resolvedType": "\"button\" | \"reset\" | \"submit\"",
|
|
@@ -599,12 +646,19 @@
|
|
|
599
646
|
"bubbles": true,
|
|
600
647
|
"cancelable": true,
|
|
601
648
|
"composed": true
|
|
649
|
+
},
|
|
650
|
+
{
|
|
651
|
+
"name": "dsMenuClick",
|
|
652
|
+
"detail": "MouseEvent",
|
|
653
|
+
"bubbles": true,
|
|
654
|
+
"cancelable": true,
|
|
655
|
+
"composed": true
|
|
602
656
|
}
|
|
603
657
|
],
|
|
604
658
|
"methods": [
|
|
605
659
|
{
|
|
606
660
|
"name": "setFocus",
|
|
607
|
-
"signature": "setFocus() => Promise<void>"
|
|
661
|
+
"signature": "setFocus(segment?: \"primary\" | \"menu\") => Promise<void>"
|
|
608
662
|
}
|
|
609
663
|
],
|
|
610
664
|
"slots": [],
|
|
@@ -635,7 +689,7 @@
|
|
|
635
689
|
},
|
|
636
690
|
"peerDependencies": {
|
|
637
691
|
"required": [
|
|
638
|
-
"@ds-mo/tokens ^6.5.
|
|
692
|
+
"@ds-mo/tokens ^6.5.1",
|
|
639
693
|
"@ds-mo/icons ^7.0.0"
|
|
640
694
|
],
|
|
641
695
|
"frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
|
|
@@ -657,12 +711,12 @@
|
|
|
657
711
|
"files": [
|
|
658
712
|
{
|
|
659
713
|
"path": "src/wc/components/ButtonUnfilled/ButtonUnfilled.css",
|
|
660
|
-
"content": "@import '../../utils/button-base.css';\n@import '../../utils/table-caption-control.css';\n\n:host {\n --ds-button-unfilled-fg: var(--color-foreground-secondary);\n --ds-button-unfilled-fg-active: var(--color-foreground-primary);\n --ds-button-unfilled-dot-ring: var(--color-background-secondary);\n --ds-button-unfilled-border: var(--color-border-secondary);\n}\n\n.button-unfilled {\n background: transparent;\n color: var(--ds-button-unfilled-fg);\n /* Hover/press/selected fill: `.ds-interaction-fill` (+ `--selected` / `--on-*`).\n Active foreground changes remain independent from popup-open pressed paint. */\n}\n\n.button-unfilled--active {\n color: var(--ds-button-unfilled-fg-active);\n}\n\n/*\n * An open popup is a transient pressed state, not a selected state. Keep the\n * pressed wash visible for the popup's complete rendered lifecycle without\n * promoting the resting foreground or selected fill.\n */\n/* Inset stroke via interaction-fill ::after (above selected / hover washes). */\n.button-unfilled--bordered {\n --ds-interaction-border-color: var(--ds-button-unfilled-border);\n}\n\n/* Inactive: `.ds-control-inactive` (50% opacity). */\n\n/* Foreground / chrome tokens per surface — interaction tokens come from util `--on-*`. */\n.button-unfilled--background-medium {\n --ds-button-unfilled-fg: var(--color-foreground-on-medium-background-secondary);\n --ds-button-unfilled-fg-active: var(--color-foreground-on-medium-background-primary);\n --ds-button-unfilled-dot-ring: var(--color-background-medium-neutral);\n --ds-button-unfilled-border: var(--color-border-on-medium-background-secondary);\n}\n\n.button-unfilled--background-bold {\n --ds-button-unfilled-fg: var(--color-foreground-on-bold-background-secondary);\n --ds-button-unfilled-fg-active: var(--color-foreground-on-bold-background-primary);\n --ds-button-unfilled-dot-ring: var(--color-background-bold-neutral);\n --ds-button-unfilled-border: var(--color-border-on-bold-background-secondary);\n}\n\n.button-unfilled--background-strong {\n --ds-button-unfilled-fg: var(--color-foreground-on-strong-background-secondary);\n --ds-button-unfilled-fg-active: var(--color-foreground-on-strong-background-primary);\n --ds-button-unfilled-dot-ring: var(--color-background-strong-neutral);\n --ds-button-unfilled-border: var(--color-border-on-strong-background-secondary);\n}\n\n.button-unfilled--background-translucent {\n --ds-button-unfilled-fg: var(--color-translucent-foreground-secondary);\n --ds-button-unfilled-fg-active: var(--color-translucent-foreground-primary);\n --ds-button-unfilled-dot-ring: var(--color-translucent-translucent);\n --ds-button-unfilled-border: var(--color-translucent-border-secondary);\n}\n\n.button-unfilled--background-inverted {\n --ds-button-unfilled-fg: var(--color-inverted-foreground-secondary);\n --ds-button-unfilled-fg-active: var(--color-inverted-foreground-primary);\n --ds-button-unfilled-dot-ring: var(--color-inverted-background);\n --ds-button-unfilled-border: var(--color-inverted-border-secondary);\n}\n\n.button-unfilled--background-media {\n --ds-button-unfilled-fg: var(--color-media-foreground-secondary);\n --ds-button-unfilled-fg-active: var(--color-media-foreground-primary);\n --ds-button-unfilled-dot-ring: var(--color-media-background);\n --ds-button-unfilled-border: var(--color-media-border-secondary);\n}\n\n.button-unfilled--on-always-dark {\n --ds-button-unfilled-fg: var(--color-always-dark-foreground-secondary);\n --ds-button-unfilled-fg-active: var(--color-always-dark-foreground-primary);\n --ds-button-unfilled-dot-ring: var(--color-always-dark-background);\n --ds-button-unfilled-border: var(--color-always-dark-border-secondary);\n}\n\n/*\n * After surface ring defaults: selected fill remaps the knock-out to the active\n * wash so the badge halo matches the selected background.\n */\n.button-unfilled.ds-interaction-fill--selected {\n --ds-button-unfilled-dot-ring: var(--ds-interaction-active);\n}\n",
|
|
714
|
+
"content": "@import '../../utils/button-base.css';\n@import '../../utils/button-split.css';\n@import '../../utils/table-caption-control.css';\n\n:host {\n --ds-button-unfilled-fg: var(--color-foreground-secondary);\n --ds-button-unfilled-fg-active: var(--color-foreground-primary);\n --ds-button-unfilled-dot-ring: var(--color-background-secondary);\n --ds-button-unfilled-border: var(--color-border-secondary);\n --ds-button-split-border: var(--color-border-secondary);\n --ds-button-split-divider: var(--color-border-tertiary);\n}\n\n:host(.button-unfilled-host--background-medium) {\n --ds-button-split-border: var(--color-border-on-medium-background-secondary);\n --ds-button-split-divider: var(--color-border-on-medium-background-tertiary);\n}\n\n:host(.button-unfilled-host--background-bold) {\n --ds-button-split-border: var(--color-border-on-bold-background-secondary);\n --ds-button-split-divider: var(--color-border-on-bold-background-tertiary);\n}\n\n:host(.button-unfilled-host--background-strong) {\n --ds-button-split-border: var(--color-border-on-strong-background-secondary);\n --ds-button-split-divider: var(--color-border-on-strong-background-tertiary);\n}\n\n:host(.button-unfilled-host--background-translucent) {\n --ds-button-split-border: var(--color-translucent-border-secondary);\n --ds-button-split-divider: var(--color-translucent-border-tertiary);\n}\n\n:host(.button-unfilled-host--background-inverted) {\n --ds-button-split-border: var(--color-inverted-border-secondary);\n --ds-button-split-divider: var(--color-inverted-border-tertiary);\n}\n\n:host(.button-unfilled-host--background-media) {\n --ds-button-split-border: var(--color-media-border-secondary);\n --ds-button-split-divider: var(--color-media-border-tertiary);\n}\n\n:host(.button-unfilled-host--background-always-dark) {\n --ds-button-split-border: var(--color-always-dark-border-secondary);\n --ds-button-split-divider: var(--color-always-dark-border-tertiary);\n}\n\n.button-unfilled {\n background: transparent;\n color: var(--ds-button-unfilled-fg);\n /* Hover/press/selected fill: `.ds-interaction-fill` (+ `--selected` / `--on-*`).\n Active foreground changes remain independent from popup-open pressed paint. */\n}\n\n.button-unfilled--active {\n color: var(--ds-button-unfilled-fg-active);\n}\n\n/*\n * An open popup is a transient pressed state, not a selected state. Keep the\n * pressed wash visible for the popup's complete rendered lifecycle without\n * promoting the resting foreground or selected fill.\n */\n/* Inset stroke via interaction-fill ::after (above selected / hover washes). */\n.button-unfilled--bordered {\n --ds-interaction-border-color: var(--ds-button-unfilled-border);\n}\n\n/* Inactive: `.ds-control-inactive` (50% opacity). */\n\n/* Foreground / chrome tokens per surface — interaction tokens come from util `--on-*`. */\n.button-unfilled--background-medium {\n --ds-button-unfilled-fg: var(--color-foreground-on-medium-background-secondary);\n --ds-button-unfilled-fg-active: var(--color-foreground-on-medium-background-primary);\n --ds-button-unfilled-dot-ring: var(--color-background-medium-neutral);\n --ds-button-unfilled-border: var(--color-border-on-medium-background-secondary);\n}\n\n.button-unfilled--background-bold {\n --ds-button-unfilled-fg: var(--color-foreground-on-bold-background-secondary);\n --ds-button-unfilled-fg-active: var(--color-foreground-on-bold-background-primary);\n --ds-button-unfilled-dot-ring: var(--color-background-bold-neutral);\n --ds-button-unfilled-border: var(--color-border-on-bold-background-secondary);\n}\n\n.button-unfilled--background-strong {\n --ds-button-unfilled-fg: var(--color-foreground-on-strong-background-secondary);\n --ds-button-unfilled-fg-active: var(--color-foreground-on-strong-background-primary);\n --ds-button-unfilled-dot-ring: var(--color-background-strong-neutral);\n --ds-button-unfilled-border: var(--color-border-on-strong-background-secondary);\n}\n\n.button-unfilled--background-translucent {\n --ds-button-unfilled-fg: var(--color-translucent-foreground-secondary);\n --ds-button-unfilled-fg-active: var(--color-translucent-foreground-primary);\n --ds-button-unfilled-dot-ring: var(--color-translucent-translucent);\n --ds-button-unfilled-border: var(--color-translucent-border-secondary);\n}\n\n.button-unfilled--background-inverted {\n --ds-button-unfilled-fg: var(--color-inverted-foreground-secondary);\n --ds-button-unfilled-fg-active: var(--color-inverted-foreground-primary);\n --ds-button-unfilled-dot-ring: var(--color-inverted-background);\n --ds-button-unfilled-border: var(--color-inverted-border-secondary);\n}\n\n.button-unfilled--background-media {\n --ds-button-unfilled-fg: var(--color-media-foreground-secondary);\n --ds-button-unfilled-fg-active: var(--color-media-foreground-primary);\n --ds-button-unfilled-dot-ring: var(--color-media-background);\n --ds-button-unfilled-border: var(--color-media-border-secondary);\n}\n\n.button-unfilled--on-always-dark {\n --ds-button-unfilled-fg: var(--color-always-dark-foreground-secondary);\n --ds-button-unfilled-fg-active: var(--color-always-dark-foreground-primary);\n --ds-button-unfilled-dot-ring: var(--color-always-dark-background);\n --ds-button-unfilled-border: var(--color-always-dark-border-secondary);\n}\n\n/*\n * After surface ring defaults: selected fill remaps the knock-out to the active\n * wash so the badge halo matches the selected background.\n */\n.button-unfilled.ds-interaction-fill--selected {\n --ds-button-unfilled-dot-ring: var(--ds-interaction-active);\n}\n",
|
|
661
715
|
"type": "registry:ui"
|
|
662
716
|
},
|
|
663
717
|
{
|
|
664
718
|
"path": "src/wc/components/ButtonUnfilled/ButtonUnfilled.tsx",
|
|
665
|
-
"content": "import {\n Component,\n Element,\n Event,\n EventEmitter,\n h,\n Host,\n Method,\n Prop,\n State,\n Watch,\n} from '@stencil/core';\nimport { controlWidthClass } from '../../utils';\nimport { beginElevatedControlPress } from '../../utils/control-press';\nimport { renderButtonContent } from '../../utils/button-render';\nimport type { ControlInsetDepth } from '../../utils/control-text';\nimport { observeTableCaptionCompact } from '../../utils/table-caption-compact';\nimport type { ButtonPopup, ButtonSize, ButtonVariant, ButtonWidth } from '../../utils/button-types';\n\nexport type ButtonUnfilledBackground =\n | 'faint'\n | 'medium'\n | 'bold'\n | 'strong'\n | 'translucent'\n | 'inverted'\n | 'media'\n | 'always-dark';\n\nexport type ButtonUnfilledVariant = ButtonVariant;\nexport type ButtonUnfilledSize = ButtonSize;\nexport type ButtonUnfilledWidth = ButtonWidth;\nexport type ButtonUnfilledPopup = ButtonPopup;\n\n@Component({\n tag: 'ds-button-unfilled',\n styleUrl: 'ButtonUnfilled.css',\n scoped: true,\n})\nexport class ButtonUnfilled {\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: ButtonUnfilledVariant = 'label';\n\n /** Control density (height, padding, icon, type). */\n @Prop() size: ButtonUnfilledSize = 'md';\n\n /** Use reduced outer geometry when nested inside a control of the same size. */\n @Prop() isInset: boolean = false;\n\n /** Single removes 4px overall; double removes 8px overall (xs stays single). */\n @Prop() insetDepth: ControlInsetDepth = 'single';\n\n /** Width fit — hug content (default) or fill the parent. */\n @Prop() width: ButtonUnfilledWidth = 'hug';\n\n /** Visible text for `label` / `icon-label` variants. */\n @Prop() label: string = '';\n\n /** Whether the visible label uses the emphasized weight. */\n @Prop() labelEmphasis: boolean = true;\n\n /** Icon name passed to <ds-icon> for `icon` / `icon-label` variants. */\n @Prop() icon: string = '';\n\n /**\n * Owner-controlled visual emphasis inside a composite. This does not add\n * toggle semantics and does not emit dsChange.\n */\n @Prop() isActive: boolean = false;\n\n /**\n * When active, render the selected interaction fill.\n * Default `true` for general UI. Shell chrome (nav / tool rails) should pass\n * `false` so selection is foreground-only (primary color, no fill).\n */\n @Prop() activeFill: boolean = true;\n\n /** Show a 1px secondary inset border. Default on; shell chrome can pass `false`. */\n @Prop() hasBorder: boolean = true;\n\n /** Use the half-radius treatment instead of the default control radius. */\n @Prop() rounded: boolean = false;\n\n /**\n * Scale down during a physical pointer press.\n * Disable when an owning composite requires fixed child or background geometry.\n */\n @Prop() pressScale: boolean = true;\n\n /** Show a notification dot at the top-right of the icon zone (icon variant only). */\n @Prop() dot: 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 /** Actual parent surface context. Omit on primary and secondary surfaces. */\n @Prop() background: ButtonUnfilledBackground | undefined;\n\n /** Accessible name override. Required for icon-only buttons. */\n @Prop({ attribute: 'aria-label' }) ariaLabel: string | null = null;\n @Prop() controls: string | undefined;\n /**\n * Controlled disclosure or popup state forwarded to `aria-expanded`.\n * Popup triggers hold only the pressed wash while open; their resting\n * foreground is unchanged. Ordinary disclosures remain visually neutral.\n */\n @Prop() expanded: boolean | undefined;\n @Prop() haspopup: ButtonUnfilledPopup | undefined;\n /**\n * Controlled state for a genuine toggle button. Adds aria-pressed, promotes\n * active styling, and makes activation emit dsChange with the requested state.\n */\n @Prop() pressed: boolean | undefined;\n\n /**\n * Collapse the visible label and chevron to an icon-only control when the\n * owning `ds-table` caption is narrower than 900px. The trigger omits those\n * parts rather than clipping them.\n */\n @Prop({ reflect: true }) collapseLabel: boolean = false;\n\n /**\n * Mark the button as a Menu trigger. Implies `aria-haspopup=\"menu\"` and covers\n * both menu-button shapes:\n *\n * - `label` / `icon-label` — the action *has* a menu; a trailing chevron carries\n * the affordance.\n * - `icon` — the button *is* a menu. No chevron is added, so the glyph must\n * convey the menu on its own. Use `Ellipses` for generic more-options;\n * use a specific icon when the menu has a named purpose, such as\n * `Table` for Customize table.\n *\n * Use `haspopup` directly for non-menu popups.\n */\n @Prop() hasMenu: boolean = false;\n\n /**\n * Native `tabindex` for roving keyboard groups in shell chrome.\n * Omit for the default button tab stop (`0`).\n */\n @Prop({ attribute: 'tab-index' }) focusTabIndex?: number;\n\n @Event() dsClick!: EventEmitter<MouseEvent>;\n @Event() dsChange!: EventEmitter<boolean>;\n\n @State() private captionCompact = false;\n\n private buttonEl: HTMLButtonElement | null = null;\n private captionCompactDisconnect: (() => void) | undefined;\n private hasLoaded = false;\n\n componentDidLoad(): void {\n this.hasLoaded = true;\n this.syncCaptionCompactObserver();\n }\n\n connectedCallback(): void {\n if (this.hasLoaded) this.syncCaptionCompactObserver();\n }\n\n disconnectedCallback(): void {\n this.disconnectCaptionCompactObserver();\n }\n\n @Watch('collapseLabel')\n onCollapseLabelChange() {\n this.syncCaptionCompactObserver();\n }\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 if (this.pressed !== undefined) this.dsChange.emit(!this.pressed);\n };\n\n private get captionIconOnly(): boolean {\n return (\n this.collapseLabel &&\n this.captionCompact &&\n this.variant === 'icon-label' &&\n Boolean(this.icon)\n );\n }\n\n private get visualVariant(): ButtonUnfilledVariant {\n return this.captionIconOnly ? 'icon' : this.variant;\n }\n\n private get showDot(): boolean {\n return this.variant === 'icon' && this.dot && !this.isLoading;\n }\n\n private syncCaptionCompactObserver(): void {\n this.disconnectCaptionCompactObserver();\n if (!this.collapseLabel) {\n if (this.captionCompact) this.captionCompact = false;\n return;\n }\n this.captionCompactDisconnect = observeTableCaptionCompact(this.el, compact => {\n if (this.captionCompact !== compact) this.captionCompact = compact;\n });\n }\n\n private disconnectCaptionCompactObserver(): void {\n this.captionCompactDisconnect?.();\n this.captionCompactDisconnect = undefined;\n }\n\n private get resolvedHaspopup(): ButtonUnfilledPopup | undefined {\n return this.haspopup ?? (this.hasMenu ? 'menu' : undefined);\n }\n\n private get doubleInset(): boolean {\n return this.isInset && this.insetDepth === 'double' && this.size !== 'xs';\n }\n\n /** Only popup triggers hold a pressed visual while expanded. */\n private get expandedPopup(): boolean {\n return this.expanded === true && this.resolvedHaspopup !== undefined && !this.isInactive;\n }\n\n private get visuallyActive(): boolean {\n return this.isActive || this.pressed === true;\n }\n\n /** Knock-out ring: selected fill → active wash; otherwise surface token. */\n private get dotRing(): string {\n if ((this.isActive || this.pressed === true) && this.activeFill) {\n return 'var(--ds-interaction-active)';\n }\n return 'var(--ds-button-unfilled-dot-ring)';\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 bg = this.background;\n const cls: Record<string, boolean> = {\n 'button-unfilled': true,\n 'ds-button': true,\n 'ds-focus-ring-inset': true,\n 'ds-control-press-scale': this.pressScale,\n 'ds-interaction-fill': true,\n 'ds-interaction-fill--selected':\n (this.isActive || this.pressed === true) && this.activeFill && !this.isInactive,\n 'ds-interaction-fill--on-faint': bg === 'faint',\n 'ds-interaction-fill--on-medium': bg === 'medium',\n 'ds-interaction-fill--on-bold': bg === 'bold',\n 'ds-interaction-fill--on-strong': bg === 'strong',\n 'ds-interaction-fill--on-translucent': bg === 'translucent',\n 'ds-interaction-fill--on-inverted': bg === 'inverted',\n 'ds-interaction-fill--on-media': bg === 'media',\n 'ds-interaction-fill--on-always-dark': bg === 'always-dark',\n 'button-unfilled--active': this.visuallyActive,\n 'button-unfilled--expanded': this.expandedPopup,\n 'ds-button--expanded': this.expandedPopup,\n 'button-unfilled--bordered': this.hasBorder,\n 'ds-button--bordered': this.hasBorder,\n 'button-unfilled--rounded': this.rounded,\n 'ds-button--rounded': this.rounded,\n 'ds-control-inactive': this.isInactive,\n 'ds-control--lg': this.size === 'lg',\n 'ds-control--md': this.size === 'md',\n 'ds-control--sm': this.size === 'sm',\n 'ds-control--xs': this.size === 'xs',\n 'ds-control--inset': this.isInset && !this.doubleInset,\n 'ds-control--inset-double': this.doubleInset,\n 'ds-control-frame': true,\n 'button-unfilled--icon': this.visualVariant === 'icon',\n 'ds-button--icon': this.visualVariant === 'icon',\n 'button-unfilled--label': this.visualVariant === 'label',\n 'button-unfilled--icon-label': this.visualVariant === 'icon-label',\n 'button-unfilled--background-faint': bg === 'faint',\n 'button-unfilled--background-medium': bg === 'medium',\n 'button-unfilled--background-bold': bg === 'bold',\n 'button-unfilled--background-strong': bg === 'strong',\n 'button-unfilled--background-translucent': bg === 'translucent',\n 'button-unfilled--background-inverted': bg === 'inverted',\n 'button-unfilled--background-media': bg === 'media',\n 'button-unfilled--on-always-dark': bg === 'always-dark',\n };\n\n const button = (\n <button\n ref={el => {\n this.buttonEl = el ?? null;\n }}\n type={this.type}\n class={cls}\n disabled={this.isInactive}\n tabIndex={this.focusTabIndex ?? 0}\n aria-label={this.accessibleName}\n aria-busy={this.isLoading ? 'true' : undefined}\n aria-disabled={this.isLoading ? 'true' : undefined}\n aria-controls={this.controls}\n aria-expanded={this.expanded === undefined ? undefined : String(this.expanded)}\n aria-haspopup={this.resolvedHaspopup}\n aria-pressed={this.pressed === undefined ? undefined : String(this.pressed)}\n onPointerDown={event =>\n beginElevatedControlPress(event, this.pressScale && !this.isInactive && !this.isLoading)\n }\n onClick={this.handleClick}\n >\n {renderButtonContent({\n namespace: 'button-unfilled',\n variant: this.visualVariant,\n size: this.size,\n label: this.label,\n labelEmphasis: this.labelEmphasis,\n icon: this.icon,\n hasMenu: this.hasMenu,\n isLoading: this.isLoading,\n dot: {\n visible: this.showDot,\n background: this.dotRing,\n },\n })}\n </button>\n );\n\n return (\n <Host\n class={{\n 'button-unfilled-host': true,\n 'button-unfilled-host--icon': this.visualVariant === 'icon',\n 'ds-button-host--icon': this.visualVariant === 'icon',\n 'ds-control--lg': this.size === 'lg',\n 'ds-control--md': this.size === 'md',\n 'ds-control--sm': this.size === 'sm',\n 'ds-control--xs': this.size === 'xs',\n 'ds-control--inset': this.isInset && !this.doubleInset,\n 'ds-control--inset-double': this.doubleInset,\n 'ds-table-caption-control': this.collapseLabel,\n 'ds-table-caption-control--compact': this.captionIconOnly,\n ...controlWidthClass(this.width),\n }}\n tabIndex={-1}\n >\n {this.collapseLabel ? (\n <ds-tooltip\n label={this.captionIconOnly ? this.label || this.accessibleName || '' : ''}\n side=\"top\"\n size=\"sm\"\n >\n {button}\n </ds-tooltip>\n ) : (\n button\n )}\n </Host>\n );\n }\n}\n",
|
|
719
|
+
"content": "import {\n Component,\n Element,\n Event,\n EventEmitter,\n h,\n Host,\n Method,\n Prop,\n State,\n Watch,\n} from '@stencil/core';\nimport { controlWidthClass } from '../../utils';\nimport { beginElevatedControlPress } from '../../utils/control-press';\nimport { renderButtonContent } from '../../utils/button-render';\nimport type { ControlInsetDepth } from '../../utils/control-text';\nimport { observeTableCaptionCompact } from '../../utils/table-caption-compact';\nimport type { ButtonPopup, ButtonSize, ButtonVariant, ButtonWidth } from '../../utils/button-types';\n\nexport type ButtonUnfilledBackground =\n | 'faint'\n | 'medium'\n | 'bold'\n | 'strong'\n | 'translucent'\n | 'inverted'\n | 'media'\n | 'always-dark';\n\nexport type ButtonUnfilledVariant = ButtonVariant;\nexport type ButtonUnfilledSize = ButtonSize;\nexport type ButtonUnfilledWidth = ButtonWidth;\nexport type ButtonUnfilledPopup = ButtonPopup;\n\n@Component({\n tag: 'ds-button-unfilled',\n styleUrl: 'ButtonUnfilled.css',\n scoped: true,\n})\nexport class ButtonUnfilled {\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: ButtonUnfilledVariant = 'label';\n\n /** Control density (height, padding, icon, type). */\n @Prop() size: ButtonUnfilledSize = 'md';\n\n /** Use reduced outer geometry when nested inside a control of the same size. */\n @Prop() isInset: boolean = false;\n\n /** Single removes 4px overall; double removes 8px overall (xs stays single). */\n @Prop() insetDepth: ControlInsetDepth = 'single';\n\n /** Width fit — hug content (default) or fill the parent. */\n @Prop() width: ButtonUnfilledWidth = 'hug';\n\n /** Visible text for `label` / `icon-label` variants. */\n @Prop() label: string = '';\n\n /** Whether the visible label uses the emphasized weight. */\n @Prop() labelEmphasis: boolean = true;\n\n /** Icon name passed to <ds-icon> for `icon` / `icon-label` variants. */\n @Prop() icon: string = '';\n\n /**\n * Owner-controlled visual emphasis inside a composite. This does not add\n * toggle semantics and does not emit dsChange.\n */\n @Prop() isActive: boolean = false;\n\n /**\n * When active, render the selected interaction fill.\n * Default `true` for general UI. Shell chrome (nav / tool rails) should pass\n * `false` so selection is foreground-only (primary color, no fill).\n */\n @Prop() activeFill: boolean = true;\n\n /** Show a 1px secondary inset border. Default on; shell chrome can pass `false`. */\n @Prop() hasBorder: boolean = true;\n\n /** Use the half-radius treatment instead of the default control radius. */\n @Prop() rounded: boolean = false;\n\n /**\n * Scale down during a physical pointer press.\n * Disable when an owning composite requires fixed child or background geometry.\n */\n @Prop() pressScale: boolean = true;\n\n /** Show a notification dot at the top-right of the icon zone (icon variant only). */\n @Prop() dot: 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 /** Actual parent surface context. Omit on primary and secondary surfaces. */\n @Prop() background: ButtonUnfilledBackground | undefined;\n\n /** Accessible name override. Required for icon-only buttons. */\n @Prop({ attribute: 'aria-label' }) ariaLabel: string | null = null;\n @Prop() controls: string | undefined;\n /**\n * Controlled disclosure or popup state forwarded to `aria-expanded`.\n * Popup triggers hold only the pressed wash while open; their resting\n * foreground is unchanged. Ordinary disclosures remain visually neutral.\n */\n @Prop() expanded: boolean | undefined;\n @Prop() haspopup: ButtonUnfilledPopup | undefined;\n\n /**\n * Append a separate ChevronDown menu segment while preserving this button's\n * variant, size, surface, active, loading, border, and width treatment.\n */\n @Prop() split: boolean = false;\n\n /** Accessible name for the appended menu segment in split mode. */\n @Prop() menuAriaLabel: string = 'More options';\n\n /**\n * Controlled state for a genuine toggle button. Adds aria-pressed, promotes\n * active styling, and makes activation emit dsChange with the requested state.\n */\n @Prop() pressed: boolean | undefined;\n\n /**\n * Collapse the visible label and chevron to an icon-only control when the\n * owning `ds-table` caption is narrower than 900px. The trigger omits those\n * parts rather than clipping them.\n */\n @Prop({ reflect: true }) collapseLabel: boolean = false;\n\n /**\n * Mark the button as a Menu trigger. Implies `aria-haspopup=\"menu\"` and covers\n * both menu-button shapes:\n *\n * - `label` / `icon-label` — the action *has* a menu; a trailing chevron carries\n * the affordance.\n * - `icon` — the button *is* a menu. No chevron is added, so the glyph must\n * convey the menu on its own. Use `Ellipses` for generic more-options;\n * use a specific icon when the menu has a named purpose, such as\n * `Table` for Customize table.\n *\n * Use `haspopup` directly for non-menu popups.\n */\n @Prop() hasMenu: boolean = false;\n\n /**\n * Native `tabindex` for roving keyboard groups in shell chrome.\n * Omit for the default button tab stop (`0`).\n */\n @Prop({ attribute: 'tab-index' }) focusTabIndex?: number;\n\n @Event() dsClick!: EventEmitter<MouseEvent>;\n @Event() dsMenuClick!: EventEmitter<MouseEvent>;\n @Event() dsChange!: EventEmitter<boolean>;\n\n @State() private captionCompact = false;\n\n private buttonEl: HTMLButtonElement | null = null;\n private menuButtonEl: HTMLButtonElement | null = null;\n private captionCompactDisconnect: (() => void) | undefined;\n private hasLoaded = false;\n\n componentDidLoad(): void {\n this.hasLoaded = true;\n this.syncCaptionCompactObserver();\n }\n\n connectedCallback(): void {\n if (this.hasLoaded) this.syncCaptionCompactObserver();\n }\n\n disconnectedCallback(): void {\n this.disconnectCaptionCompactObserver();\n }\n\n @Watch('collapseLabel')\n onCollapseLabelChange() {\n this.syncCaptionCompactObserver();\n }\n\n @Method()\n async setFocus(segment: 'primary' | 'menu' = 'primary') {\n (segment === 'menu' ? this.menuButtonEl : 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 if (this.pressed !== undefined) this.dsChange.emit(!this.pressed);\n };\n\n private handleMenuClick = (event: MouseEvent) => {\n if (this.isInactive || this.isLoading) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n this.dsMenuClick.emit(event);\n };\n\n private get captionIconOnly(): boolean {\n return (\n this.collapseLabel &&\n this.captionCompact &&\n this.variant === 'icon-label' &&\n Boolean(this.icon)\n );\n }\n\n private get visualVariant(): ButtonUnfilledVariant {\n return this.captionIconOnly ? 'icon' : this.variant;\n }\n\n private get showDot(): boolean {\n return this.variant === 'icon' && this.dot && !this.isLoading;\n }\n\n private syncCaptionCompactObserver(): void {\n this.disconnectCaptionCompactObserver();\n if (!this.collapseLabel) {\n if (this.captionCompact) this.captionCompact = false;\n return;\n }\n this.captionCompactDisconnect = observeTableCaptionCompact(this.el, compact => {\n if (this.captionCompact !== compact) this.captionCompact = compact;\n });\n }\n\n private disconnectCaptionCompactObserver(): void {\n this.captionCompactDisconnect?.();\n this.captionCompactDisconnect = undefined;\n }\n\n private get resolvedHaspopup(): ButtonUnfilledPopup | undefined {\n return this.haspopup ?? (this.hasMenu ? 'menu' : undefined);\n }\n\n private get doubleInset(): boolean {\n return this.isInset && this.insetDepth === 'double' && this.size !== 'xs';\n }\n\n /** Only popup triggers hold a pressed visual while expanded. */\n private get expandedPopup(): boolean {\n return this.expanded === true && this.resolvedHaspopup !== undefined && !this.isInactive;\n }\n\n private get visuallyActive(): boolean {\n return this.isActive || this.pressed === true;\n }\n\n /** Knock-out ring: selected fill → active wash; otherwise surface token. */\n private get dotRing(): string {\n if ((this.isActive || this.pressed === true) && this.activeFill) {\n return 'var(--ds-interaction-active)';\n }\n return 'var(--ds-button-unfilled-dot-ring)';\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 private buttonClass(\n variant: ButtonUnfilledVariant,\n expanded: boolean,\n bordered: boolean\n ): Record<string, boolean> {\n const bg = this.background;\n const cls: Record<string, boolean> = {\n 'button-unfilled': true,\n 'ds-button': true,\n 'ds-focus-ring-inset': true,\n 'ds-control-press-scale': this.pressScale && !this.split,\n 'ds-interaction-fill': true,\n 'ds-interaction-fill--selected':\n (this.isActive || this.pressed === true) && this.activeFill && !this.isInactive,\n 'ds-interaction-fill--on-faint': bg === 'faint',\n 'ds-interaction-fill--on-medium': bg === 'medium',\n 'ds-interaction-fill--on-bold': bg === 'bold',\n 'ds-interaction-fill--on-strong': bg === 'strong',\n 'ds-interaction-fill--on-translucent': bg === 'translucent',\n 'ds-interaction-fill--on-inverted': bg === 'inverted',\n 'ds-interaction-fill--on-media': bg === 'media',\n 'ds-interaction-fill--on-always-dark': bg === 'always-dark',\n 'button-unfilled--active': this.visuallyActive,\n 'button-unfilled--expanded': expanded,\n 'ds-button--expanded': expanded,\n 'button-unfilled--bordered': bordered,\n 'ds-button--bordered': bordered,\n 'button-unfilled--rounded': this.rounded,\n 'ds-button--rounded': this.rounded,\n 'ds-control-inactive': this.isInactive,\n 'ds-control--lg': this.size === 'lg',\n 'ds-control--md': this.size === 'md',\n 'ds-control--sm': this.size === 'sm',\n 'ds-control--xs': this.size === 'xs',\n 'ds-control--inset': this.isInset && !this.doubleInset,\n 'ds-control--inset-double': this.doubleInset,\n 'ds-control-frame': true,\n 'button-unfilled--icon': variant === 'icon',\n 'ds-button--icon': variant === 'icon',\n 'button-unfilled--label': variant === 'label',\n 'button-unfilled--icon-label': variant === 'icon-label',\n 'button-unfilled--background-faint': bg === 'faint',\n 'button-unfilled--background-medium': bg === 'medium',\n 'button-unfilled--background-bold': bg === 'bold',\n 'button-unfilled--background-strong': bg === 'strong',\n 'button-unfilled--background-translucent': bg === 'translucent',\n 'button-unfilled--background-inverted': bg === 'inverted',\n 'button-unfilled--background-media': bg === 'media',\n 'button-unfilled--on-always-dark': bg === 'always-dark',\n };\n return cls;\n }\n\n render() {\n const primaryButton = (\n <button\n ref={el => {\n this.buttonEl = el ?? null;\n }}\n type={this.type}\n class={{\n ...this.buttonClass(\n this.visualVariant,\n !this.split && this.expandedPopup,\n this.hasBorder && !this.split\n ),\n 'ds-button-split__primary': this.split,\n }}\n disabled={this.isInactive}\n tabIndex={this.focusTabIndex ?? 0}\n aria-label={this.accessibleName}\n aria-busy={this.isLoading ? 'true' : undefined}\n aria-disabled={this.isLoading ? 'true' : undefined}\n aria-controls={this.split ? undefined : this.controls}\n aria-expanded={\n this.split || this.expanded === undefined ? undefined : String(this.expanded)\n }\n aria-haspopup={this.split ? undefined : this.resolvedHaspopup}\n aria-pressed={this.pressed === undefined ? undefined : String(this.pressed)}\n onPointerDown={event =>\n beginElevatedControlPress(\n event,\n this.pressScale && !this.split && !this.isInactive && !this.isLoading\n )\n }\n onClick={this.handleClick}\n >\n {renderButtonContent({\n namespace: 'button-unfilled',\n variant: this.visualVariant,\n size: this.size,\n label: this.label,\n labelEmphasis: this.labelEmphasis,\n icon: this.icon,\n hasMenu: !this.split && this.hasMenu,\n isLoading: this.isLoading,\n dot: {\n visible: this.showDot,\n background: this.dotRing,\n },\n })}\n </button>\n );\n\n const control = this.split ? (\n <div\n class={{\n 'ds-button-split': true,\n 'ds-button-split--rounded': this.rounded,\n }}\n >\n {primaryButton}\n <span\n class={{\n 'ds-button-split__divider': true,\n 'ds-button-split__divider--content-height': !this.hasBorder,\n }}\n aria-hidden=\"true\"\n />\n <button\n ref={el => {\n this.menuButtonEl = el ?? null;\n }}\n class={{\n ...this.buttonClass('icon', this.expanded === true && !this.isInactive, false),\n 'ds-button-split__menu': true,\n }}\n type=\"button\"\n disabled={this.isInactive || this.isLoading}\n tabIndex={this.focusTabIndex ?? 0}\n aria-label={this.menuAriaLabel}\n aria-controls={this.controls}\n aria-expanded={String(this.expanded === true)}\n aria-haspopup=\"menu\"\n onClick={this.handleMenuClick}\n >\n {renderButtonContent({\n namespace: 'button-unfilled',\n variant: 'icon',\n size: this.size,\n label: '',\n labelEmphasis: true,\n icon: 'ChevronDown',\n hasMenu: false,\n isLoading: false,\n })}\n </button>\n {this.hasBorder ? <span class=\"ds-button-split__outline\" aria-hidden=\"true\" /> : null}\n </div>\n ) : (\n primaryButton\n );\n\n return (\n <Host\n class={{\n 'button-unfilled-host': true,\n 'button-unfilled-host--icon': this.visualVariant === 'icon' && !this.split,\n 'ds-button-host--icon': this.visualVariant === 'icon' && !this.split,\n 'ds-button-split-host': this.split,\n 'ds-button-split-host--primary-icon': this.split && this.visualVariant === 'icon',\n [`button-unfilled-host--background-${this.background}`]:\n this.split && this.background !== undefined,\n 'ds-control--lg': this.size === 'lg',\n 'ds-control--md': this.size === 'md',\n 'ds-control--sm': this.size === 'sm',\n 'ds-control--xs': this.size === 'xs',\n 'ds-control--inset': this.isInset && !this.doubleInset,\n 'ds-control--inset-double': this.doubleInset,\n 'ds-table-caption-control': this.collapseLabel,\n 'ds-table-caption-control--compact': this.captionIconOnly,\n ...controlWidthClass(this.width),\n }}\n tabIndex={-1}\n >\n {this.collapseLabel ? (\n <ds-tooltip\n label={this.captionIconOnly ? this.label || this.accessibleName || '' : ''}\n side=\"top\"\n size=\"sm\"\n >\n {control}\n </ds-tooltip>\n ) : (\n control\n )}\n </Host>\n );\n }\n}\n",
|
|
666
720
|
"type": "registry:ui"
|
|
667
721
|
}
|
|
668
722
|
]
|
|
@@ -350,7 +350,7 @@
|
|
|
350
350
|
"complexPropertyNote": "Assign these non-primitive values as JavaScript properties: metrics, score.",
|
|
351
351
|
"peerDependencies": {
|
|
352
352
|
"required": [
|
|
353
|
-
"@ds-mo/tokens ^6.5.
|
|
353
|
+
"@ds-mo/tokens ^6.5.1",
|
|
354
354
|
"@ds-mo/icons ^7.0.0"
|
|
355
355
|
],
|
|
356
356
|
"frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
|
|
@@ -272,7 +272,7 @@
|
|
|
272
272
|
"complexPropertyNote": "Assign these non-primitive values as JavaScript properties: items.",
|
|
273
273
|
"peerDependencies": {
|
|
274
274
|
"required": [
|
|
275
|
-
"@ds-mo/tokens ^6.5.
|
|
275
|
+
"@ds-mo/tokens ^6.5.1",
|
|
276
276
|
"@ds-mo/icons ^7.0.0"
|
|
277
277
|
],
|
|
278
278
|
"frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
|
|
@@ -234,7 +234,7 @@
|
|
|
234
234
|
"complexPropertyNote": "Assign these non-primitive values as JavaScript properties: definition.",
|
|
235
235
|
"peerDependencies": {
|
|
236
236
|
"required": [
|
|
237
|
-
"@ds-mo/tokens ^6.5.
|
|
237
|
+
"@ds-mo/tokens ^6.5.1",
|
|
238
238
|
"@ds-mo/icons ^7.0.0"
|
|
239
239
|
],
|
|
240
240
|
"frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
|
|
@@ -759,7 +759,7 @@
|
|
|
759
759
|
"complexPropertyNote": "Assign these non-primitive values as JavaScript properties: anchor, boundary, filters, matchModes, values.",
|
|
760
760
|
"peerDependencies": {
|
|
761
761
|
"required": [
|
|
762
|
-
"@ds-mo/tokens ^6.5.
|
|
762
|
+
"@ds-mo/tokens ^6.5.1",
|
|
763
763
|
"@ds-mo/icons ^7.0.0"
|
|
764
764
|
],
|
|
765
765
|
"frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
|
|
@@ -500,7 +500,7 @@
|
|
|
500
500
|
"complexPropertyNote": "Assign these non-primitive values as JavaScript properties: anchor, boundary, items, sections.",
|
|
501
501
|
"peerDependencies": {
|
|
502
502
|
"required": [
|
|
503
|
-
"@ds-mo/tokens ^6.5.
|
|
503
|
+
"@ds-mo/tokens ^6.5.1",
|
|
504
504
|
"@ds-mo/icons ^7.0.0"
|
|
505
505
|
],
|
|
506
506
|
"frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
|