@ds-mo/ui 15.3.0 → 15.4.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 +1 -1
- package/dist/agent.json +506 -31
- package/dist/angular/ds-checkbox-group.d.ts +12 -0
- package/dist/angular/ds-checkbox-group.js +38 -0
- package/dist/angular/ds-checkbox.d.ts +1 -1
- package/dist/angular/ds-checkbox.js +3 -3
- package/dist/angular/ds-inline-banner-settings.d.ts +12 -0
- package/dist/angular/ds-inline-banner-settings.js +38 -0
- package/dist/angular/ds-radio.d.ts +1 -1
- package/dist/angular/ds-radio.js +3 -3
- package/dist/angular/ds-setting-row-checkbox.d.ts +12 -0
- package/dist/angular/ds-setting-row-checkbox.js +38 -0
- package/dist/angular/ds-setting-row-radio.d.ts +12 -0
- package/dist/angular/ds-setting-row-radio.js +38 -0
- package/dist/angular/ds-setting-row-toggle.d.ts +18 -0
- package/dist/angular/{ds-setting-row.js → ds-setting-row-toggle.js} +12 -12
- package/dist/angular/index.d.ts +1 -1
- package/dist/angular/index.js +5 -1
- package/dist/angular/proxies.d.ts +5 -1
- package/dist/angular/proxies.js +5 -1
- package/dist/components/ds-agent-activity.js +1 -1
- package/dist/components/ds-agent-questionnaire.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-badge.js +1 -1
- package/dist/components/ds-banner.js +1 -1
- package/dist/components/ds-bar-action.js +1 -1
- package/dist/components/ds-bar-nav.js +1 -1
- package/dist/components/ds-bar-page-title.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-breadcrumb.js +1 -1
- package/dist/components/ds-button-filled.js +1 -1
- package/dist/components/ds-button-inverted.js +1 -1
- package/dist/components/ds-button-inverted.js.map +1 -1
- package/dist/components/ds-button-unfilled.js +1 -1
- package/dist/components/ds-calendar.js +1 -1
- package/dist/components/ds-card-action-center.js +1 -1
- package/dist/components/ds-card-action-center.js.map +1 -1
- package/dist/components/ds-card-chart.js +1 -1
- package/dist/components/ds-card-navigation.js +1 -1
- package/dist/components/ds-card-navigation.js.map +1 -1
- package/dist/components/ds-card-overview.js +1 -1
- package/dist/components/ds-card-overview.js.map +1 -1
- package/dist/components/ds-card-setting.js +1 -1
- package/dist/components/ds-card-setting.js.map +1 -1
- package/dist/components/ds-card-settings-scope.js +1 -1
- package/dist/components/ds-card-settings-scope.js.map +1 -1
- package/dist/components/ds-chart-legend.js +1 -1
- package/dist/components/ds-chart-legend.js.map +1 -1
- package/dist/components/ds-chart.js +1 -1
- package/dist/components/{ds-setting-row.d.ts → ds-checkbox-group.d.ts} +4 -4
- package/dist/components/ds-checkbox-group.js +2 -0
- package/dist/components/ds-checkbox-group.js.map +1 -0
- 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-data-customize.js +1 -1
- package/dist/components/ds-data-filter.js +1 -1
- package/dist/components/ds-data-group.js +1 -1
- package/dist/components/ds-data-preferences.js +1 -1
- package/dist/components/ds-data-saved-views.js +1 -1
- package/dist/components/ds-data-search.js +1 -1
- package/dist/components/ds-data-search.js.map +1 -1
- package/dist/components/ds-data-sort.js +1 -1
- package/dist/components/ds-data-toolbar.js +1 -1
- package/dist/components/ds-divider.js +1 -1
- package/dist/components/ds-empty-state.js +1 -1
- package/dist/components/ds-field.js +1 -1
- package/dist/components/ds-filter-menu.js +1 -1
- package/dist/components/ds-inline-banner-settings.d.ts +11 -0
- package/dist/components/ds-inline-banner-settings.js +2 -0
- package/dist/components/ds-inline-banner-settings.js.map +1 -0
- package/dist/components/ds-input-date.js +1 -1
- package/dist/components/ds-input-date.js.map +1 -1
- package/dist/components/ds-input-time.js +1 -1
- package/dist/components/ds-input-time.js.map +1 -1
- package/dist/components/ds-input.js +1 -1
- package/dist/components/ds-map-cluster-marker.js +1 -1
- package/dist/components/ds-map-entity-marker.js +1 -1
- package/dist/components/ds-markdown.js +1 -1
- package/dist/components/ds-menu.js +1 -1
- package/dist/components/ds-message-actions.js +1 -1
- package/dist/components/ds-message-bubble.js +1 -1
- package/dist/components/ds-message-bubble.js.map +1 -1
- package/dist/components/ds-message-composer.js +1 -1
- package/dist/components/ds-message-composer.js.map +1 -1
- package/dist/components/ds-message-scroller.js +1 -1
- package/dist/components/ds-message.js +1 -1
- package/dist/components/ds-mobile-bar-nav.js +1 -1
- package/dist/components/ds-mobile-header.js +1 -1
- package/dist/components/ds-mobile-section-switcher.js +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-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-paper-texture.js +1 -1
- package/dist/components/ds-radio-tile.js +1 -1
- package/dist/components/ds-radio-tile.js.map +1 -1
- package/dist/components/ds-radio.js +1 -1
- package/dist/components/ds-score.js +1 -1
- package/dist/components/ds-scroll-overlay.js +1 -1
- package/dist/components/ds-scroll-overlay.js.map +1 -1
- package/dist/components/ds-select.js +1 -1
- package/dist/components/ds-setting-row-checkbox.d.ts +11 -0
- package/dist/components/ds-setting-row-checkbox.js +2 -0
- package/dist/components/ds-setting-row-checkbox.js.map +1 -0
- package/dist/components/ds-setting-row-radio.d.ts +11 -0
- package/dist/components/ds-setting-row-radio.js +2 -0
- package/dist/components/ds-setting-row-radio.js.map +1 -0
- package/dist/components/ds-setting-row-toggle.d.ts +11 -0
- package/dist/components/ds-setting-row-toggle.js +2 -0
- package/dist/components/ds-setting-row-toggle.js.map +1 -0
- package/dist/components/ds-shell-app.js +1 -1
- package/dist/components/ds-shell-app.js.map +1 -1
- package/dist/components/ds-shell-page.js +1 -1
- package/dist/components/ds-shell-tools.js +1 -1
- package/dist/components/ds-skeleton.js +1 -1
- package/dist/components/ds-slider.js +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-table.js +1 -1
- package/dist/components/ds-table.js.map +1 -1
- package/dist/components/ds-tag.js +1 -1
- package/dist/components/ds-text.js +1 -1
- package/dist/components/ds-textarea.js +1 -1
- package/dist/components/ds-textarea.js.map +1 -1
- package/dist/components/ds-time-picker.js +1 -1
- package/dist/components/ds-toast.js +1 -1
- package/dist/components/ds-tooltip-chart.js +1 -1
- package/dist/components/ds-tooltip.js +1 -1
- package/dist/components/ds-typing-indicator.js +1 -1
- package/dist/components/p-7TVdPhGR.js +2 -0
- package/dist/components/{p-DHapI2sf.js.map → p-7TVdPhGR.js.map} +1 -1
- package/dist/components/{p-7V1AhetH.js → p-B0BQCVkq.js} +2 -2
- package/dist/components/{p-Co5MiPNa.js → p-B0EpvBDs.js} +2 -2
- package/dist/components/{p-DFkw6wrS.js → p-B39iJO8F.js} +2 -2
- package/dist/components/p-B9TM6FqC.js +2 -0
- package/dist/components/{p-p_MwknM3.js.map → p-B9TM6FqC.js.map} +1 -1
- package/dist/components/{p-AmT4GlhM.js → p-B9y6azEw.js} +2 -2
- package/dist/components/p-BDdlJZyL.js +2 -0
- package/dist/components/{p-cuZva5tl.js.map → p-BDdlJZyL.js.map} +1 -1
- package/dist/components/{p-CrL9wxZg.js → p-BERXvOCf.js} +2 -2
- package/dist/components/{p-AM_ht6Im.js → p-BFHpU-uU.js} +2 -2
- package/dist/components/{p-B-HOVYoH.js → p-BQspV5U7.js} +2 -2
- package/dist/components/p-BWSIw8AQ.js +2 -0
- package/dist/components/p-BWSIw8AQ.js.map +1 -0
- package/dist/components/p-BhjqYTiY.js +2 -0
- package/dist/components/p-BhjqYTiY.js.map +1 -0
- package/dist/components/{p-C_gJD8l3.js → p-Bk3poU91.js} +2 -2
- package/dist/components/{p-Gb-vTuXr.js → p-BnuNaXR2.js} +2 -2
- package/dist/components/p-BwdnVqAY.js +2 -0
- package/dist/components/{p-BHI4LcGK.js.map → p-BwdnVqAY.js.map} +1 -1
- package/dist/components/p-C4huuwed.js +2 -0
- package/dist/components/{p-tJaC01aE.js.map → p-C4huuwed.js.map} +1 -1
- package/dist/components/{p-BsM37Prt.js → p-C8V4lkVy.js} +2 -2
- package/dist/components/p-CJ1NnOEW.js +2 -0
- package/dist/components/p-CJ1NnOEW.js.map +1 -0
- package/dist/components/p-CPamUzaj.js +2 -0
- package/dist/components/{p-BSuMDPaV.js.map → p-CPamUzaj.js.map} +1 -1
- package/dist/components/{p-BU1B6NW8.js → p-CUDocY23.js} +2 -2
- package/dist/components/{p-BU1B6NW8.js.map → p-CUDocY23.js.map} +1 -1
- package/dist/components/p-CX6ZxUQT.js +2 -0
- package/dist/components/p-CX6ZxUQT.js.map +1 -0
- package/dist/components/{p-C-c8SJ00.js → p-CZNZTcYS.js} +2 -2
- package/dist/components/{p-DQPzqcYR.js → p-CbCN9ew9.js} +2 -2
- package/dist/components/p-CeXf9-X3.js.map +1 -1
- package/dist/components/p-Cgn-BORA.js +2 -0
- package/dist/components/p-Cgn-BORA.js.map +1 -0
- package/dist/components/{p-CzQ_JF6A.js → p-Co1rUdOR.js} +2 -2
- package/dist/components/p-Co1rUdOR.js.map +1 -0
- package/dist/components/{p-D0KD-Nr_.js → p-CwdRaJER.js} +2 -2
- package/dist/components/p-D6FRqNhN.js +2 -0
- package/dist/components/p-D6FRqNhN.js.map +1 -0
- package/dist/components/{p-Cihjy4WY.js → p-D8OWhnID.js} +2 -2
- package/dist/components/p-DCyJ3_PL.js +2 -0
- package/dist/components/{p-fYZK3zqM.js.map → p-DCyJ3_PL.js.map} +1 -1
- package/dist/components/{p-BXSHN1OK.js → p-DIQiHX0q.js} +2 -2
- package/dist/components/{p-z8L-YMi3.js → p-DJDbskZf.js} +2 -2
- package/dist/components/p-DRdoGSGX.js +2 -0
- package/dist/components/{p-DWmYCOKz.js.map → p-DRdoGSGX.js.map} +1 -1
- package/dist/components/{p-Bm3KWMe4.js → p-DSZPO06T.js} +2 -2
- package/dist/components/{p-C3-dcROG.js → p-DSmDyI2o.js} +2 -2
- package/dist/components/{p-DcrdyDRw.js → p-DVEx-Xg9.js} +2 -2
- package/dist/components/{p-Bu4OmhKK.js → p-DXk1eml1.js} +2 -2
- package/dist/components/{p-B7QEpaMe.js → p-DYQa1DVF.js} +2 -2
- package/dist/components/p-DYQa1DVF.js.map +1 -0
- package/dist/components/p-DYsE6HLk.js +2 -0
- package/dist/components/p-DYsE6HLk.js.map +1 -0
- package/dist/components/p-DebLYW7A.js +2 -0
- package/dist/components/p-DebLYW7A.js.map +1 -0
- package/dist/components/{p-Bh1Fx0aW.js → p-DmSnHVW6.js} +2 -2
- package/dist/components/p-Dnt5xUBD.js +2 -0
- package/dist/components/{p-C4VeD49U.js.map → p-Dnt5xUBD.js.map} +1 -1
- package/dist/components/p-Doa2blZT.js +2 -0
- package/dist/components/{p-CztB8Pbq.js.map → p-Doa2blZT.js.map} +1 -1
- package/dist/components/{p-CCpJT31M.js → p-Dyqd-cub.js} +2 -2
- package/dist/components/{p-CCpJT31M.js.map → p-Dyqd-cub.js.map} +1 -1
- package/dist/components/p-DzvTC27M.js +2 -0
- package/dist/components/p-DzvTC27M.js.map +1 -0
- package/dist/components/p-JBki_jyY.js +2 -0
- package/dist/components/{p-BugKaVWc.js.map → p-JBki_jyY.js.map} +1 -1
- package/dist/components/p-MOJmB6vX.js +2 -0
- package/dist/components/{p-iGNHXFZA.js.map → p-MOJmB6vX.js.map} +1 -1
- package/dist/components/{p-BYJtvRQm.js → p-UJMEz8_O.js} +2 -2
- package/dist/components/{p-Bo7GxFBh.js → p-_IqSPt5V.js} +2 -2
- package/dist/components/p-g0jsfEXz.js +2 -0
- package/dist/components/{p-Fkkd3gMB.js.map → p-g0jsfEXz.js.map} +1 -1
- package/dist/components/{p-lADW-TI8.js → p-pp1IQN4Z.js} +2 -2
- package/dist/docs/components.json +701 -13
- package/dist/lib/shell/index.js +1 -1
- package/dist/lib/shell/index.js.map +1 -1
- package/dist/lint/index.js +1 -1
- 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 +2 -2
- 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 +4 -4
- package/dist/mcp-data/registry/bar-page-title.json +3 -3
- package/dist/mcp-data/registry/bar-title.json +3 -3
- 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 +1 -1
- package/dist/mcp-data/registry/button-inverted.json +1 -1
- package/dist/mcp-data/registry/button-unfilled.json +8 -8
- package/dist/mcp-data/registry/calendar.json +1 -1
- package/dist/mcp-data/registry/card-action-center.json +1 -1
- package/dist/mcp-data/registry/card-chart.json +1 -1
- package/dist/mcp-data/registry/card-navigation.json +1 -1
- package/dist/mcp-data/registry/card-overview.json +1 -1
- package/dist/mcp-data/registry/card-setting.json +22 -8
- package/dist/mcp-data/registry/card-settings-scope.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-group.json +246 -0
- package/dist/mcp-data/registry/checkbox.json +25 -5
- 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/data-customize.json +1 -1
- package/dist/mcp-data/registry/data-filter.json +1 -1
- package/dist/mcp-data/registry/data-group.json +1 -1
- package/dist/mcp-data/registry/data-preferences.json +1 -1
- package/dist/mcp-data/registry/data-saved-views.json +1 -1
- package/dist/mcp-data/registry/data-search.json +1 -1
- package/dist/mcp-data/registry/data-sort.json +1 -1
- package/dist/mcp-data/registry/data-toolbar.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/inline-banner-settings.json +175 -0
- package/dist/mcp-data/registry/input-date.json +1 -1
- package/dist/mcp-data/registry/input-time.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/map-cluster-marker.json +1 -1
- package/dist/mcp-data/registry/map-entity-marker.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 +4 -4
- package/dist/mcp-data/registry/message-composer.json +6 -6
- package/dist/mcp-data/registry/message-scroller.json +1 -1
- package/dist/mcp-data/registry/message.json +2 -2
- 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 +3 -3
- package/dist/mcp-data/registry/panel-sub-nav.json +1 -1
- package/dist/mcp-data/registry/panel-tool-header.json +3 -3
- package/dist/mcp-data/registry/panel-tool-search.json +2 -2
- package/dist/mcp-data/registry/panel-tools.json +3 -3
- package/dist/mcp-data/registry/paper-texture.json +1 -1
- package/dist/mcp-data/registry/radio-tile.json +5 -4
- package/dist/mcp-data/registry/radio.json +50 -8
- package/dist/mcp-data/registry/registry.json +518 -31
- package/dist/mcp-data/registry/score.json +1 -1
- package/dist/mcp-data/registry/scroll-overlay.json +1 -1
- package/dist/mcp-data/registry/select.json +1 -1
- package/dist/mcp-data/registry/setting-row-checkbox.json +197 -0
- package/dist/mcp-data/registry/setting-row-radio.json +196 -0
- package/dist/mcp-data/registry/{setting-row.json → setting-row-toggle.json} +45 -25
- package/dist/mcp-data/registry/shell-app.json +3 -3
- package/dist/mcp-data/registry/shell-page.json +1 -1
- package/dist/mcp-data/registry/shell-tools.json +1 -1
- 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 +3 -3
- package/dist/mcp-data/registry/tab-group.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/textarea.json +1 -1
- package/dist/mcp-data/registry/time-picker.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/components.d.ts +5 -1
- package/dist/react/components.js +5 -1
- package/dist/react/ds-checkbox-group.d.ts +9 -0
- package/dist/react/ds-checkbox-group.js +12 -0
- package/dist/react/ds-inline-banner-settings.d.ts +9 -0
- package/dist/react/ds-inline-banner-settings.js +12 -0
- package/dist/react/ds-setting-row-checkbox.d.ts +9 -0
- package/dist/react/ds-setting-row-checkbox.js +12 -0
- package/dist/react/ds-setting-row-radio.d.ts +9 -0
- package/dist/react/ds-setting-row-radio.js +12 -0
- package/dist/react/ds-setting-row-toggle.d.ts +12 -0
- package/dist/react/ds-setting-row-toggle.js +12 -0
- package/dist/types/components/BarPageTitle/BarPageTitle.d.ts +2 -0
- package/dist/types/components/BarTitle/bar-title-action-chrome.d.ts +4 -0
- package/dist/types/components/ButtonUnfilled/ButtonUnfilled.d.ts +5 -2
- package/dist/types/components/CardSetting/CardSetting.d.ts +12 -2
- package/dist/types/components/Checkbox/Checkbox.d.ts +2 -0
- package/dist/types/components/CheckboxGroup/CheckboxGroup.d.ts +20 -0
- package/dist/types/components/InlineBannerSettings/InlineBannerSettings.d.ts +6 -0
- package/dist/types/components/Radio/Radio.d.ts +8 -0
- package/dist/types/components/SettingRowCheckbox/SettingRowCheckbox.d.ts +19 -0
- package/dist/types/components/SettingRowRadio/SettingRowRadio.d.ts +19 -0
- package/dist/types/components/{SettingRow/SettingRow.d.ts → SettingRowToggle/SettingRowToggle.d.ts} +5 -2
- package/dist/types/components/Switch/Switch.d.ts +7 -0
- package/dist/types/components.d.ts +290 -20
- package/dist/vue/components.d.ts +5 -1
- package/dist/vue/components.js +5 -1
- package/dist/vue/{ds-setting-row.d.ts → ds-checkbox-group.d.ts} +1 -1
- package/dist/vue/ds-checkbox-group.js +12 -0
- package/dist/vue/ds-checkbox.js +1 -0
- package/dist/vue/ds-inline-banner-settings.d.ts +3 -0
- package/dist/vue/ds-inline-banner-settings.js +8 -0
- package/dist/vue/ds-radio.js +2 -0
- package/dist/vue/ds-setting-row-checkbox.d.ts +3 -0
- package/dist/vue/ds-setting-row-checkbox.js +11 -0
- package/dist/vue/ds-setting-row-radio.d.ts +3 -0
- package/dist/vue/ds-setting-row-radio.js +11 -0
- package/dist/vue/ds-setting-row-toggle.d.ts +3 -0
- package/dist/vue/ds-setting-row-toggle.js +15 -0
- package/package.json +3 -3
- package/dist/angular/ds-setting-row.d.ts +0 -18
- package/dist/components/ds-setting-row.js +0 -2
- package/dist/components/ds-setting-row.js.map +0 -1
- package/dist/components/p-3bsypMrY.js +0 -2
- package/dist/components/p-3bsypMrY.js.map +0 -1
- package/dist/components/p-B7QEpaMe.js.map +0 -1
- package/dist/components/p-B7bXN-vf.js +0 -2
- package/dist/components/p-B7bXN-vf.js.map +0 -1
- package/dist/components/p-BHI4LcGK.js +0 -2
- package/dist/components/p-BSuMDPaV.js +0 -2
- package/dist/components/p-BVwg5XVz.js +0 -2
- package/dist/components/p-BVwg5XVz.js.map +0 -1
- package/dist/components/p-BugKaVWc.js +0 -2
- package/dist/components/p-C4VeD49U.js +0 -2
- package/dist/components/p-CI7c9kp-.js +0 -2
- package/dist/components/p-CI7c9kp-.js.map +0 -1
- package/dist/components/p-CJD0kLeV.js +0 -2
- package/dist/components/p-CJD0kLeV.js.map +0 -1
- package/dist/components/p-Cc3ZUQlJ.js +0 -2
- package/dist/components/p-Cc3ZUQlJ.js.map +0 -1
- package/dist/components/p-CzQ_JF6A.js.map +0 -1
- package/dist/components/p-CztB8Pbq.js +0 -2
- package/dist/components/p-DCLRAH5i.js +0 -2
- package/dist/components/p-DCLRAH5i.js.map +0 -1
- package/dist/components/p-DHapI2sf.js +0 -2
- package/dist/components/p-DWmYCOKz.js +0 -2
- package/dist/components/p-DX2RyZba.js +0 -2
- package/dist/components/p-DX2RyZba.js.map +0 -1
- package/dist/components/p-Dcn1eDVt.js +0 -2
- package/dist/components/p-Dcn1eDVt.js.map +0 -1
- package/dist/components/p-Fkkd3gMB.js +0 -2
- package/dist/components/p-cuZva5tl.js +0 -2
- package/dist/components/p-fYZK3zqM.js +0 -2
- package/dist/components/p-iGNHXFZA.js +0 -2
- package/dist/components/p-p_MwknM3.js +0 -2
- package/dist/components/p-tJaC01aE.js +0 -2
- package/dist/react/ds-setting-row.d.ts +0 -12
- package/dist/react/ds-setting-row.js +0 -12
- package/dist/vue/ds-setting-row.js +0 -14
- /package/dist/components/{p-7V1AhetH.js.map → p-B0BQCVkq.js.map} +0 -0
- /package/dist/components/{p-Co5MiPNa.js.map → p-B0EpvBDs.js.map} +0 -0
- /package/dist/components/{p-DFkw6wrS.js.map → p-B39iJO8F.js.map} +0 -0
- /package/dist/components/{p-AmT4GlhM.js.map → p-B9y6azEw.js.map} +0 -0
- /package/dist/components/{p-CrL9wxZg.js.map → p-BERXvOCf.js.map} +0 -0
- /package/dist/components/{p-AM_ht6Im.js.map → p-BFHpU-uU.js.map} +0 -0
- /package/dist/components/{p-B-HOVYoH.js.map → p-BQspV5U7.js.map} +0 -0
- /package/dist/components/{p-C_gJD8l3.js.map → p-Bk3poU91.js.map} +0 -0
- /package/dist/components/{p-Gb-vTuXr.js.map → p-BnuNaXR2.js.map} +0 -0
- /package/dist/components/{p-BsM37Prt.js.map → p-C8V4lkVy.js.map} +0 -0
- /package/dist/components/{p-C-c8SJ00.js.map → p-CZNZTcYS.js.map} +0 -0
- /package/dist/components/{p-DQPzqcYR.js.map → p-CbCN9ew9.js.map} +0 -0
- /package/dist/components/{p-D0KD-Nr_.js.map → p-CwdRaJER.js.map} +0 -0
- /package/dist/components/{p-Cihjy4WY.js.map → p-D8OWhnID.js.map} +0 -0
- /package/dist/components/{p-BXSHN1OK.js.map → p-DIQiHX0q.js.map} +0 -0
- /package/dist/components/{p-z8L-YMi3.js.map → p-DJDbskZf.js.map} +0 -0
- /package/dist/components/{p-Bm3KWMe4.js.map → p-DSZPO06T.js.map} +0 -0
- /package/dist/components/{p-C3-dcROG.js.map → p-DSmDyI2o.js.map} +0 -0
- /package/dist/components/{p-DcrdyDRw.js.map → p-DVEx-Xg9.js.map} +0 -0
- /package/dist/components/{p-Bu4OmhKK.js.map → p-DXk1eml1.js.map} +0 -0
- /package/dist/components/{p-Bh1Fx0aW.js.map → p-DmSnHVW6.js.map} +0 -0
- /package/dist/components/{p-BYJtvRQm.js.map → p-UJMEz8_O.js.map} +0 -0
- /package/dist/components/{p-Bo7GxFBh.js.map → p-_IqSPt5V.js.map} +0 -0
- /package/dist/components/{p-lADW-TI8.js.map → p-pp1IQN4Z.js.map} +0 -0
|
@@ -564,7 +564,7 @@
|
|
|
564
564
|
"complexPropertyNote": "Assign these non-primitive values as JavaScript properties: actionItems, actions, breadcrumbs, primaryAction, sections.",
|
|
565
565
|
"peerDependencies": {
|
|
566
566
|
"required": [
|
|
567
|
-
"@ds-mo/tokens ^6.
|
|
567
|
+
"@ds-mo/tokens ^6.6.1",
|
|
568
568
|
"@ds-mo/icons ^8.1.1"
|
|
569
569
|
],
|
|
570
570
|
"frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
|
|
@@ -588,7 +588,7 @@
|
|
|
588
588
|
"files": [
|
|
589
589
|
{
|
|
590
590
|
"path": "src/wc/components/BarTitle/BarTitle.css",
|
|
591
|
-
"content": "@import '../../utils/radius.css';\n@import '../../utils/control-density.css';\n@import '../../utils/chrome-header.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(--_shell-page-header-background, var(--color-background-primary));\n}\n\n:host([placement='shell-bar']) {\n --_shell-page-header-background: var(--color-background-secondary);\n}\n\n:host-context(ds-shell-app:not([gradient-preset='none']))[placement='shell-bar'],\n:host-context(ds-shell-app:not([gradient-preset='none']))[placement='shell-bar'] .bar-title,\n:host-context(ds-shell-app.shell-app--paper-texture)[placement='shell-bar'],\n:host-context(ds-shell-app.shell-app--paper-texture)[placement='shell-bar'] .bar-title {\n background: transparent;\n}\n\n:host([data-shell-page-syncing]) {\n visibility: hidden;\n}\n\n.bar-title {\n position: relative;\n min-width: 0;\n box-sizing: border-box;\n background: var(--_shell-page-header-background, var(--color-background-primary));\n}\n\n.bar-title::after {\n content: '';\n position: absolute;\n inset: auto var(--ds-bar-title-divider-inset, var(--dimension-space-200)) 0;\n height: var(--dimension-stroke-width-012);\n background: var(--color-border-tertiary);\n pointer-events: none;\n}\n\n.bar-title--divider-hidden::after {\n display: none;\n}\n\n.bar-title__inner {\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: var(--dimension-space-100);\n padding: var(--dimension-space-200);\n box-sizing: border-box;\n}\n\n.bar-title__row {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: var(--dimension-space-100);\n min-height: var(--dimension-size-400);\n min-width: 0;\n}\n\n:host(.bar-title-host--expanded) .bar-title__row {\n gap: var(--dimension-space-400);\n}\n\n.bar-title__leading {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n gap: var(--dimension-space-
|
|
591
|
+
"content": "@import '../../utils/radius.css';\n@import '../../utils/control-density.css';\n@import '../../utils/chrome-header.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(--_shell-page-header-background, var(--color-background-primary));\n}\n\n:host([placement='shell-bar']) {\n --_shell-page-header-background: var(--color-background-secondary);\n}\n\n:host-context(ds-shell-app:not([gradient-preset='none']))[placement='shell-bar'],\n:host-context(ds-shell-app:not([gradient-preset='none']))[placement='shell-bar'] .bar-title,\n:host-context(ds-shell-app.shell-app--paper-texture)[placement='shell-bar'],\n:host-context(ds-shell-app.shell-app--paper-texture)[placement='shell-bar'] .bar-title {\n background: transparent;\n}\n\n:host([data-shell-page-syncing]) {\n visibility: hidden;\n}\n\n.bar-title {\n position: relative;\n min-width: 0;\n box-sizing: border-box;\n background: var(--_shell-page-header-background, var(--color-background-primary));\n}\n\n.bar-title::after {\n content: '';\n position: absolute;\n inset: auto var(--ds-bar-title-divider-inset, var(--dimension-space-200)) 0;\n height: var(--dimension-stroke-width-012);\n background: var(--color-border-tertiary);\n pointer-events: none;\n}\n\n.bar-title--divider-hidden::after {\n display: none;\n}\n\n.bar-title__inner {\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: var(--dimension-space-100);\n padding: var(--dimension-space-200);\n box-sizing: border-box;\n}\n\n.bar-title__row {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: var(--dimension-space-100);\n min-height: var(--dimension-size-400);\n min-width: 0;\n}\n\n:host(.bar-title-host--expanded) .bar-title__row {\n gap: var(--dimension-space-400);\n}\n\n.bar-title__leading {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n gap: var(--dimension-space-050);\n min-width: 0;\n}\n\n.bar-title__title-row {\n display: flex;\n align-items: center;\n gap: var(--dimension-space-100);\n min-width: 0;\n min-height: var(--dimension-size-400);\n}\n\n.bar-title__identity {\n display: flex;\n flex: 0 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__section-chevron {\n flex: 0 0 auto;\n}\n\n.bar-title__breadcrumb {\n display: block;\n width: 100%;\n min-width: 0;\n}\n\n.bar-title__heading {\n display: block;\n width: auto;\n min-width: 0;\n user-select: none;\n}\n\n.bar-title__divider {\n width: var(--dimension-stroke-width-012);\n height: var(--dimension-size-250);\n margin-inline-start: var(--dimension-space-100);\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 --ds-control-radius: var(--dimension-radius-half);\n\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: default;\n font-family: inherit;\n user-select: none;\n}\n\n.bar-title__section-label {\n min-width: 0;\n padding-inline: 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 flex: 0 0 auto;\n}\n\n.bar-title__description {\n display: block;\n min-width: 0;\n max-width: 100%;\n}\n\n:host(.bar-title-host--compact) .bar-title {\n height: var(--dimension-size-600);\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 flex: 1 1 auto;\n height: 100%;\n min-width: 0;\n padding: 0;\n gap: 0;\n}\n\n:host(.bar-title-host--compact) .bar-title__row {\n height: 100%;\n align-items: center;\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__divider {\n margin-inline-start: 0;\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",
|
|
592
592
|
"type": "registry:ui"
|
|
593
593
|
},
|
|
594
594
|
{
|
|
@@ -598,7 +598,7 @@
|
|
|
598
598
|
},
|
|
599
599
|
{
|
|
600
600
|
"path": "src/wc/components/BarTitle/bar-title-action-chrome.tsx",
|
|
601
|
-
"content": "import { h } from '@stencil/core';\nimport type { MenuItemData, MenuSection } from '../Menu/menu-types';\nimport { isBarTitleDivider } from './bar-title-types';\nimport type {\n BarTitleActionConfigItem,\n BarTitleMenuAction,\n BarTitlePrimaryAction,\n BarTitleSplitAction,\n} from './bar-title-types';\nimport { barTitleChoiceSections } from './bar-title-actions';\n\nexport type FocusableBarTitleButton = HTMLElement & {\n setFocus?: (segment?: 'primary' | 'menu') => Promise<void>;\n};\n\nexport function barTitleActionMenuDomId(\n classPrefix: string,\n instanceId: number,\n resolvedActionItems: BarTitleActionConfigItem[],\n id: string\n): string {\n const index = resolvedActionItems.findIndex(item => !isBarTitleDivider(item) && item.id === id);\n return `${classPrefix}-action-menu-${instanceId}-${index}`;\n}\n\nexport function barTitleActionMenuAnchor(\n id: string,\n overflowTrigger: FocusableBarTitleButton | null,\n actionTriggers: Map<string, FocusableBarTitleButton>\n): HTMLElement | undefined {\n if (id === '__overflow') return overflowTrigger ?? undefined;\n const trigger = actionTriggers.get(id);\n if (!trigger) return undefined;\n const splitMenu = trigger.querySelector<HTMLElement>('.ds-button-split__menu');\n return splitMenu ?? trigger;\n}\n\nexport async function restoreBarTitleActionFocus(options: {\n menuId: string;\n overflowTrigger: FocusableBarTitleButton | null;\n actionTriggers: Map<string, FocusableBarTitleButton>;\n resolvedActionItems: BarTitleActionConfigItem[];\n}): Promise<void> {\n if (options.menuId === '__overflow') {\n await options.overflowTrigger?.setFocus?.();\n return;\n }\n const trigger = options.actionTriggers.get(options.menuId);\n if (!trigger || !('setFocus' in trigger)) return;\n const split = options.resolvedActionItems.some(\n item => !isBarTitleDivider(item) && item.id === options.menuId && item.type === 'split'\n );\n await trigger.setFocus?.(split ? 'menu' : undefined);\n}\n\nfunction className(prefix: string, part: string): string {\n return `${prefix}__${part}`;\n}\n\nexport function renderBarTitleBack(options: {\n classPrefix: string;\n showBack: boolean;\n backAriaLabel: string;\n onBack: (event: MouseEvent) => void;\n}) {\n if (!options.showBack) return null;\n return (\n <ds-tooltip label=\"Go back\" side=\"bottom\" size=\"sm\">\n <ds-button-unfilled\n class={className(options.classPrefix, 'back')}\n variant=\"icon\"\n icon=\"ChevronLeft\"\n aria-label={options.backAriaLabel}\n size=\"md\"\n activeFill={false}\n hasBorder={false}\n onDsClick={(event: CustomEvent<MouseEvent>) => options.onBack(event.detail)}\n />\n </ds-tooltip>\n );\n}\n\nexport function renderBarTitleSectionTrigger(options: {\n classPrefix: string;\n triggerId: string;\n menuId: string;\n open: boolean;\n surfaceOpen: boolean;\n ariaLabel: string;\n selectedLabel: string;\n setTriggerEl: (el: HTMLButtonElement | null) => void;\n onToggle: (event: MouseEvent) => void;\n}) {\n const prefix = options.classPrefix;\n return (\n <div class={className(prefix, 'section-selector')}>\n <button\n ref={el => {\n options.setTriggerEl((el as HTMLButtonElement | null) ?? null);\n }}\n id={options.triggerId}\n class={{\n [className(prefix, 'section-trigger')]: true,\n [`${className(prefix, 'section-trigger')}--expanded`]: options.open,\n 'ds-interaction-fill--surface-open': options.surfaceOpen,\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={options.menuId}\n aria-expanded={String(options.open)}\n aria-label={options.ariaLabel}\n onClick={options.onToggle}\n >\n <ds-text\n class={`${className(prefix, 'section-label')} ds-interaction-fill__content`}\n as=\"span\"\n variant=\"text-body-medium\"\n emphasis\n color=\"primary\"\n lineTruncation={1}\n >\n {options.selectedLabel}\n </ds-text>\n <ds-icon\n class={`${className(prefix, 'section-chevron')} ds-interaction-fill__content`}\n name=\"ChevronUpDown\"\n size=\"md\"\n color=\"inherit\"\n aria-hidden=\"true\"\n />\n </button>\n </div>\n );\n}\n\nfunction renderVisibleAction(\n action: BarTitleActionConfigItem,\n options: {\n classPrefix: string;\n compact: boolean;\n actionItems: BarTitleActionConfigItem[] | undefined;\n primaryAction: BarTitlePrimaryAction | null;\n resolvedActionItems: BarTitleActionConfigItem[];\n instanceId: number;\n openActionMenuId: string;\n surfaceActionMenuId: string;\n actionTriggers: Map<string, FocusableBarTitleButton>;\n toggleActionMenu: (id: string, event: MouseEvent) => void;\n emitAction: (id: string) => void;\n }\n) {\n if (isBarTitleDivider(action) || action.type === 'overflow') return null;\n const appearance = action.appearance ?? (action.type === 'split' ? 'filled' : 'unfilled');\n const variant: 'icon' | 'icon-label' | 'label' =\n action.type === 'icon' ? 'icon' : action.icon ? 'icon-label' : 'label';\n const menu = action.type === 'menu';\n const menuId = menu\n ? barTitleActionMenuDomId(\n options.classPrefix,\n options.instanceId,\n options.resolvedActionItems,\n action.id\n )\n : undefined;\n const prefix = options.classPrefix;\n\n if (action.type === 'split') {\n const splitMenuId = barTitleActionMenuDomId(\n options.classPrefix,\n options.instanceId,\n options.resolvedActionItems,\n action.id\n );\n const splitProps = {\n key: action.id,\n ref: (el: FocusableBarTitleButton | undefined) => {\n if (el) options.actionTriggers.set(action.id, el);\n else options.actionTriggers.delete(action.id);\n },\n class: `${className(prefix, 'action')} ${className(prefix, 'split-action')}`,\n split: true,\n variant,\n label: action.label,\n icon: action.icon ?? '',\n menuAriaLabel: action.menuAriaLabel,\n controls: splitMenuId,\n expanded: options.openActionMenuId === action.id,\n surfaceOpen: options.surfaceActionMenuId === action.id,\n size: 'md' as const,\n type: action.buttonType ?? 'button',\n isInactive: action.isInactive,\n isLoading: action.isLoading,\n onDsClick: () => options.emitAction(action.id),\n onDsMenuClick: (event: CustomEvent<MouseEvent>) =>\n options.toggleActionMenu(action.id, event.detail),\n };\n return appearance === 'filled' ? (\n <ds-button-filled\n {...splitProps}\n intent={action.intent ?? 'brand'}\n contrast={action.contrast ?? 'bold'}\n />\n ) : (\n <ds-button-unfilled {...splitProps} />\n );\n }\n\n const buttonProps = {\n key: action.id,\n ref: (el: FocusableBarTitleButton | undefined) => {\n if (el) options.actionTriggers.set(action.id, el);\n else options.actionTriggers.delete(action.id);\n },\n class: `${className(prefix, 'action')} ${className(prefix, 'action')}--${action.type}${\n options.actionItems === undefined && action.id === options.primaryAction?.id\n ? ` ${className(prefix, 'primary-action')}`\n : ''\n }`,\n variant,\n icon: action.icon ?? '',\n label: action.label,\n ariaLabel: action.ariaLabel ?? (action.type === 'icon' ? action.label : undefined),\n size: 'md' as const,\n type: action.buttonType ?? 'button',\n isInactive: action.isInactive,\n isLoading: action.isLoading,\n controls: menuId,\n expanded: menu ? options.openActionMenuId === action.id : undefined,\n surfaceOpen: menu && options.surfaceActionMenuId === action.id,\n hasMenu: menu,\n onDsClick: (event: CustomEvent<MouseEvent>) => {\n if (menu) options.toggleActionMenu(action.id, event.detail);\n else options.emitAction(action.id);\n },\n };\n\n const button =\n appearance === 'filled' ? (\n <ds-button-filled\n {...buttonProps}\n intent={action.intent ?? 'brand'}\n contrast={action.contrast ?? 'bold'}\n />\n ) : (\n <ds-button-unfilled {...buttonProps} />\n );\n\n return action.type === 'icon' ? (\n <ds-tooltip key={action.id} label={action.label} side=\"bottom\" size=\"sm\">\n {button}\n </ds-tooltip>\n ) : (\n button\n );\n}\n\nexport function renderBarTitleActions(options: {\n classPrefix: string;\n compact: boolean;\n visibleActions: BarTitleActionConfigItem[];\n showOverflowTrigger: boolean;\n actionItems: BarTitleActionConfigItem[] | undefined;\n primaryAction: BarTitlePrimaryAction | null;\n resolvedActionItems: BarTitleActionConfigItem[];\n instanceId: number;\n openActionMenuId: string;\n surfaceActionMenuId: string;\n actionsAriaLabel: string;\n actionMenuTriggerId: string;\n actionMenuId: string;\n actionTriggers: Map<string, FocusableBarTitleButton>;\n setOverflowTriggerEl: (el: FocusableBarTitleButton | null) => void;\n toggleActionMenu: (id: string, event: MouseEvent) => void;\n emitAction: (id: string) => void;\n}) {\n if (options.visibleActions.length === 0 && !options.showOverflowTrigger) return null;\n const prefix = options.classPrefix;\n\n return (\n <div class={className(prefix, 'actions')}>\n {options.visibleActions.map(action => renderVisibleAction(action, options))}\n {options.showOverflowTrigger ? (\n <ds-tooltip label=\"Page options\" side=\"bottom\" size=\"sm\">\n <ds-button-unfilled\n ref={el => {\n options.setOverflowTriggerEl((el as FocusableBarTitleButton | null) ?? null);\n }}\n id={options.actionMenuTriggerId}\n class={className(prefix, 'more-actions')}\n variant=\"icon\"\n icon=\"Ellipses\"\n aria-label={options.actionsAriaLabel}\n size=\"md\"\n activeFill={!options.compact}\n hasBorder={options.visibleActions.length > 0}\n haspopup=\"menu\"\n controls={options.actionMenuId}\n expanded={options.openActionMenuId === '__overflow'}\n surfaceOpen={options.surfaceActionMenuId === '__overflow'}\n onDsClick={(event: CustomEvent<MouseEvent>) =>\n options.toggleActionMenu('__overflow', event.detail)\n }\n />\n </ds-tooltip>\n ) : null}\n </div>\n );\n}\n\nexport function renderBarTitleActionMenus(options: {\n classPrefix: string;\n visibleActions: BarTitleActionConfigItem[];\n instanceId: number;\n resolvedActionItems: BarTitleActionConfigItem[];\n sideOffset?: number | string;\n openActionMenuId: string;\n actionMenuInitialFocusVisible: boolean;\n overflowTrigger: FocusableBarTitleButton | null;\n actionTriggers: Map<string, FocusableBarTitleButton>;\n closeActionMenu: () => void;\n finishActionMenuClose: (event: CustomEvent<void>) => void;\n handleActionSelect: (event: CustomEvent<MenuItemData>) => void;\n}) {\n const prefix = options.classPrefix;\n return options.visibleActions.flatMap(action => {\n if (isBarTitleDivider(action) || (action.type !== 'menu' && action.type !== 'split')) {\n return [];\n }\n const menuAction = action as BarTitleMenuAction | BarTitleSplitAction;\n const menuLabel = menuAction.menuAriaLabel ?? menuAction.ariaLabel ?? menuAction.label;\n return [\n <ds-menu\n key={action.id}\n id={barTitleActionMenuDomId(\n options.classPrefix,\n options.instanceId,\n options.resolvedActionItems,\n action.id\n )}\n class={className(prefix, 'action-menu')}\n anchor={barTitleActionMenuAnchor(\n action.id,\n options.overflowTrigger,\n options.actionTriggers\n )}\n align=\"end\"\n sideOffset={options.sideOffset}\n menuLabel={menuLabel}\n open={options.openActionMenuId === action.id}\n initialFocusVisible={options.actionMenuInitialFocusVisible}\n sections={barTitleChoiceSections(menuAction.choices)}\n onDsClose={options.closeActionMenu}\n onDsAfterClose={options.finishActionMenuClose}\n onDsSelect={options.handleActionSelect}\n />,\n ];\n });\n}\n\nexport function renderBarTitleOverflowMenu(options: {\n classPrefix: string;\n showOverflowTrigger: boolean;\n actionMenuId: string;\n actionMenuTriggerId: string;\n sideOffset?: number | string;\n actionsAriaLabel: string;\n open: boolean;\n actionMenuInitialFocusVisible: boolean;\n actionMenuSections: MenuSection[];\n closeActionMenu: () => void;\n finishActionMenuClose: (event: CustomEvent<void>) => void;\n handleActionSelect: (event: CustomEvent<MenuItemData>) => void;\n}) {\n if (!options.showOverflowTrigger) return null;\n return (\n <ds-menu\n id={options.actionMenuId}\n class={className(options.classPrefix, 'action-menu')}\n anchorId={options.actionMenuTriggerId}\n align=\"end\"\n sideOffset={options.sideOffset}\n menuLabel={options.actionsAriaLabel}\n open={options.open}\n initialFocusVisible={options.actionMenuInitialFocusVisible}\n sections={options.actionMenuSections}\n onDsClose={options.closeActionMenu}\n onDsAfterClose={options.finishActionMenuClose}\n onDsSelect={options.handleActionSelect}\n />\n );\n}\n",
|
|
601
|
+
"content": "import { h } from '@stencil/core';\nimport type { MenuItemData, MenuSection } from '../Menu/menu-types';\nimport { isBarTitleDivider } from './bar-title-types';\nimport type {\n BarTitleActionConfigItem,\n BarTitleMenuAction,\n BarTitlePrimaryAction,\n BarTitleSplitAction,\n} from './bar-title-types';\nimport { barTitleChoiceSections } from './bar-title-actions';\n\nexport type FocusableBarTitleButton = HTMLElement & {\n setFocus?: (segment?: 'primary' | 'menu') => Promise<void>;\n};\n\nexport function barTitleActionMenuDomId(\n classPrefix: string,\n instanceId: number,\n resolvedActionItems: BarTitleActionConfigItem[],\n id: string\n): string {\n const index = resolvedActionItems.findIndex(item => !isBarTitleDivider(item) && item.id === id);\n return `${classPrefix}-action-menu-${instanceId}-${index}`;\n}\n\nexport function barTitleActionMenuAnchor(\n id: string,\n overflowTrigger: FocusableBarTitleButton | null,\n actionTriggers: Map<string, FocusableBarTitleButton>\n): HTMLElement | undefined {\n if (id === '__overflow') return overflowTrigger ?? undefined;\n const trigger = actionTriggers.get(id);\n if (!trigger) return undefined;\n const splitMenu = trigger.querySelector<HTMLElement>('.ds-button-split__menu');\n return splitMenu ?? trigger;\n}\n\nexport async function restoreBarTitleActionFocus(options: {\n menuId: string;\n overflowTrigger: FocusableBarTitleButton | null;\n actionTriggers: Map<string, FocusableBarTitleButton>;\n resolvedActionItems: BarTitleActionConfigItem[];\n}): Promise<void> {\n if (options.menuId === '__overflow') {\n await options.overflowTrigger?.setFocus?.();\n return;\n }\n const trigger = options.actionTriggers.get(options.menuId);\n if (!trigger || !('setFocus' in trigger)) return;\n const split = options.resolvedActionItems.some(\n item => !isBarTitleDivider(item) && item.id === options.menuId && item.type === 'split'\n );\n await trigger.setFocus?.(split ? 'menu' : undefined);\n}\n\nfunction className(prefix: string, part: string): string {\n return `${prefix}__${part}`;\n}\n\nexport function renderBarTitleBack(options: {\n classPrefix: string;\n showBack: boolean;\n backAriaLabel: string;\n background?: 'chrome';\n onBack: (event: MouseEvent) => void;\n}) {\n if (!options.showBack) return null;\n return (\n <ds-tooltip label=\"Go back\" side=\"bottom\" size=\"sm\">\n <ds-button-unfilled\n class={className(options.classPrefix, 'back')}\n variant=\"icon\"\n icon=\"ChevronLeft\"\n aria-label={options.backAriaLabel}\n size=\"md\"\n activeFill={false}\n hasBorder={false}\n background={options.background}\n onDsClick={(event: CustomEvent<MouseEvent>) => options.onBack(event.detail)}\n />\n </ds-tooltip>\n );\n}\n\nexport function renderBarTitleSectionTrigger(options: {\n classPrefix: string;\n triggerId: string;\n menuId: string;\n open: boolean;\n surfaceOpen: boolean;\n ariaLabel: string;\n selectedLabel: string;\n background?: 'chrome';\n labelColor?: 'primary' | 'inherit';\n setTriggerEl: (el: HTMLButtonElement | null) => void;\n onToggle: (event: MouseEvent) => void;\n}) {\n const prefix = options.classPrefix;\n return (\n <div class={className(prefix, 'section-selector')}>\n <button\n ref={el => {\n options.setTriggerEl((el as HTMLButtonElement | null) ?? null);\n }}\n id={options.triggerId}\n class={{\n [className(prefix, 'section-trigger')]: true,\n [`${className(prefix, 'section-trigger')}--expanded`]: options.open,\n 'ds-interaction-fill--surface-open': options.surfaceOpen,\n 'ds-interaction-fill--on-chrome': options.background === 'chrome',\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={options.menuId}\n aria-expanded={String(options.open)}\n aria-label={options.ariaLabel}\n onClick={options.onToggle}\n >\n <ds-text\n class={`${className(prefix, 'section-label')} ds-interaction-fill__content`}\n as=\"span\"\n variant=\"text-body-medium\"\n emphasis\n color={options.labelColor ?? 'primary'}\n lineTruncation={1}\n >\n {options.selectedLabel}\n </ds-text>\n <ds-icon\n class={`${className(prefix, 'section-chevron')} ds-interaction-fill__content`}\n name=\"ChevronUpDown\"\n size=\"md\"\n color=\"inherit\"\n aria-hidden=\"true\"\n />\n </button>\n </div>\n );\n}\n\nfunction renderVisibleAction(\n action: BarTitleActionConfigItem,\n options: {\n classPrefix: string;\n compact: boolean;\n actionItems: BarTitleActionConfigItem[] | undefined;\n primaryAction: BarTitlePrimaryAction | null;\n resolvedActionItems: BarTitleActionConfigItem[];\n instanceId: number;\n openActionMenuId: string;\n surfaceActionMenuId: string;\n actionTriggers: Map<string, FocusableBarTitleButton>;\n buttonBackground?: 'chrome';\n toggleActionMenu: (id: string, event: MouseEvent) => void;\n emitAction: (id: string) => void;\n }\n) {\n if (isBarTitleDivider(action) || action.type === 'overflow') return null;\n const appearance = action.appearance ?? (action.type === 'split' ? 'filled' : 'unfilled');\n const variant: 'icon' | 'icon-label' | 'label' =\n action.type === 'icon' ? 'icon' : action.icon ? 'icon-label' : 'label';\n const menu = action.type === 'menu';\n const menuId = menu\n ? barTitleActionMenuDomId(\n options.classPrefix,\n options.instanceId,\n options.resolvedActionItems,\n action.id\n )\n : undefined;\n const prefix = options.classPrefix;\n\n if (action.type === 'split') {\n const splitMenuId = barTitleActionMenuDomId(\n options.classPrefix,\n options.instanceId,\n options.resolvedActionItems,\n action.id\n );\n const splitProps = {\n key: action.id,\n ref: (el: FocusableBarTitleButton | undefined) => {\n if (el) options.actionTriggers.set(action.id, el);\n else options.actionTriggers.delete(action.id);\n },\n class: `${className(prefix, 'action')} ${className(prefix, 'split-action')}`,\n split: true,\n variant,\n label: action.label,\n icon: action.icon ?? '',\n menuAriaLabel: action.menuAriaLabel,\n controls: splitMenuId,\n expanded: options.openActionMenuId === action.id,\n surfaceOpen: options.surfaceActionMenuId === action.id,\n size: 'md' as const,\n type: action.buttonType ?? 'button',\n isInactive: action.isInactive,\n isLoading: action.isLoading,\n onDsClick: () => options.emitAction(action.id),\n onDsMenuClick: (event: CustomEvent<MouseEvent>) =>\n options.toggleActionMenu(action.id, event.detail),\n };\n return appearance === 'filled' ? (\n <ds-button-filled\n {...splitProps}\n intent={action.intent ?? 'brand'}\n contrast={action.contrast ?? 'bold'}\n />\n ) : (\n <ds-button-unfilled {...splitProps} background={options.buttonBackground} />\n );\n }\n\n const buttonProps = {\n key: action.id,\n ref: (el: FocusableBarTitleButton | undefined) => {\n if (el) options.actionTriggers.set(action.id, el);\n else options.actionTriggers.delete(action.id);\n },\n class: `${className(prefix, 'action')} ${className(prefix, 'action')}--${action.type}${\n options.actionItems === undefined && action.id === options.primaryAction?.id\n ? ` ${className(prefix, 'primary-action')}`\n : ''\n }`,\n variant,\n icon: action.icon ?? '',\n label: action.label,\n ariaLabel: action.ariaLabel ?? (action.type === 'icon' ? action.label : undefined),\n size: 'md' as const,\n type: action.buttonType ?? 'button',\n isInactive: action.isInactive,\n isLoading: action.isLoading,\n controls: menuId,\n expanded: menu ? options.openActionMenuId === action.id : undefined,\n surfaceOpen: menu && options.surfaceActionMenuId === action.id,\n hasMenu: menu,\n onDsClick: (event: CustomEvent<MouseEvent>) => {\n if (menu) options.toggleActionMenu(action.id, event.detail);\n else options.emitAction(action.id);\n },\n };\n\n const button =\n appearance === 'filled' ? (\n <ds-button-filled\n {...buttonProps}\n intent={action.intent ?? 'brand'}\n contrast={action.contrast ?? 'bold'}\n />\n ) : (\n <ds-button-unfilled {...buttonProps} background={options.buttonBackground} />\n );\n\n return action.type === 'icon' ? (\n <ds-tooltip key={action.id} label={action.label} side=\"bottom\" size=\"sm\">\n {button}\n </ds-tooltip>\n ) : (\n button\n );\n}\n\nexport function renderBarTitleActions(options: {\n classPrefix: string;\n compact: boolean;\n visibleActions: BarTitleActionConfigItem[];\n showOverflowTrigger: boolean;\n actionItems: BarTitleActionConfigItem[] | undefined;\n primaryAction: BarTitlePrimaryAction | null;\n resolvedActionItems: BarTitleActionConfigItem[];\n instanceId: number;\n openActionMenuId: string;\n surfaceActionMenuId: string;\n actionsAriaLabel: string;\n actionMenuTriggerId: string;\n actionMenuId: string;\n actionTriggers: Map<string, FocusableBarTitleButton>;\n buttonBackground?: 'chrome';\n setOverflowTriggerEl: (el: FocusableBarTitleButton | null) => void;\n toggleActionMenu: (id: string, event: MouseEvent) => void;\n emitAction: (id: string) => void;\n}) {\n if (options.visibleActions.length === 0 && !options.showOverflowTrigger) return null;\n const prefix = options.classPrefix;\n\n return (\n <div class={className(prefix, 'actions')}>\n {options.visibleActions.map(action => renderVisibleAction(action, options))}\n {options.showOverflowTrigger ? (\n <ds-tooltip label=\"Page options\" side=\"bottom\" size=\"sm\">\n <ds-button-unfilled\n ref={el => {\n options.setOverflowTriggerEl((el as FocusableBarTitleButton | null) ?? null);\n }}\n id={options.actionMenuTriggerId}\n class={className(prefix, 'more-actions')}\n variant=\"icon\"\n icon=\"Ellipses\"\n aria-label={options.actionsAriaLabel}\n size=\"md\"\n activeFill={!options.compact}\n hasBorder={options.visibleActions.length > 0}\n haspopup=\"menu\"\n controls={options.actionMenuId}\n expanded={options.openActionMenuId === '__overflow'}\n surfaceOpen={options.surfaceActionMenuId === '__overflow'}\n background={options.buttonBackground}\n onDsClick={(event: CustomEvent<MouseEvent>) =>\n options.toggleActionMenu('__overflow', event.detail)\n }\n />\n </ds-tooltip>\n ) : null}\n </div>\n );\n}\n\nexport function renderBarTitleActionMenus(options: {\n classPrefix: string;\n visibleActions: BarTitleActionConfigItem[];\n instanceId: number;\n resolvedActionItems: BarTitleActionConfigItem[];\n sideOffset?: number | string;\n openActionMenuId: string;\n actionMenuInitialFocusVisible: boolean;\n overflowTrigger: FocusableBarTitleButton | null;\n actionTriggers: Map<string, FocusableBarTitleButton>;\n closeActionMenu: () => void;\n finishActionMenuClose: (event: CustomEvent<void>) => void;\n handleActionSelect: (event: CustomEvent<MenuItemData>) => void;\n}) {\n const prefix = options.classPrefix;\n return options.visibleActions.flatMap(action => {\n if (isBarTitleDivider(action) || (action.type !== 'menu' && action.type !== 'split')) {\n return [];\n }\n const menuAction = action as BarTitleMenuAction | BarTitleSplitAction;\n const menuLabel = menuAction.menuAriaLabel ?? menuAction.ariaLabel ?? menuAction.label;\n return [\n <ds-menu\n key={action.id}\n id={barTitleActionMenuDomId(\n options.classPrefix,\n options.instanceId,\n options.resolvedActionItems,\n action.id\n )}\n class={className(prefix, 'action-menu')}\n anchor={barTitleActionMenuAnchor(\n action.id,\n options.overflowTrigger,\n options.actionTriggers\n )}\n align=\"end\"\n sideOffset={options.sideOffset}\n menuLabel={menuLabel}\n open={options.openActionMenuId === action.id}\n initialFocusVisible={options.actionMenuInitialFocusVisible}\n sections={barTitleChoiceSections(menuAction.choices)}\n onDsClose={options.closeActionMenu}\n onDsAfterClose={options.finishActionMenuClose}\n onDsSelect={options.handleActionSelect}\n />,\n ];\n });\n}\n\nexport function renderBarTitleOverflowMenu(options: {\n classPrefix: string;\n showOverflowTrigger: boolean;\n actionMenuId: string;\n actionMenuTriggerId: string;\n sideOffset?: number | string;\n actionsAriaLabel: string;\n open: boolean;\n actionMenuInitialFocusVisible: boolean;\n actionMenuSections: MenuSection[];\n closeActionMenu: () => void;\n finishActionMenuClose: (event: CustomEvent<void>) => void;\n handleActionSelect: (event: CustomEvent<MenuItemData>) => void;\n}) {\n if (!options.showOverflowTrigger) return null;\n return (\n <ds-menu\n id={options.actionMenuId}\n class={className(options.classPrefix, 'action-menu')}\n anchorId={options.actionMenuTriggerId}\n align=\"end\"\n sideOffset={options.sideOffset}\n menuLabel={options.actionsAriaLabel}\n open={options.open}\n initialFocusVisible={options.actionMenuInitialFocusVisible}\n sections={options.actionMenuSections}\n onDsClose={options.closeActionMenu}\n onDsAfterClose={options.finishActionMenuClose}\n onDsSelect={options.handleActionSelect}\n />\n );\n}\n",
|
|
602
602
|
"type": "registry:ui"
|
|
603
603
|
},
|
|
604
604
|
{
|
|
@@ -379,7 +379,7 @@
|
|
|
379
379
|
"complexPropertyNote": "Assign these non-primitive values as JavaScript properties: steps, submitAction.",
|
|
380
380
|
"peerDependencies": {
|
|
381
381
|
"required": [
|
|
382
|
-
"@ds-mo/tokens ^6.
|
|
382
|
+
"@ds-mo/tokens ^6.6.1",
|
|
383
383
|
"@ds-mo/icons ^8.1.1"
|
|
384
384
|
],
|
|
385
385
|
"frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
|
|
@@ -181,7 +181,7 @@
|
|
|
181
181
|
"complexPropertyNote": "Assign these non-primitive values as JavaScript properties: items.",
|
|
182
182
|
"peerDependencies": {
|
|
183
183
|
"required": [
|
|
184
|
-
"@ds-mo/tokens ^6.
|
|
184
|
+
"@ds-mo/tokens ^6.6.1",
|
|
185
185
|
"@ds-mo/icons ^8.1.1"
|
|
186
186
|
],
|
|
187
187
|
"frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"General content UI keeps the selected interaction fill and border for pressed or active emphasis.",
|
|
73
73
|
"Shell, navigation, and tool-rail composites use isActive with primary foreground across the complete control and no selected fill or border.",
|
|
74
74
|
"The omitted default surface treatment is for primary and secondary parent surfaces and uses the brand-active selected fill; pass faint explicitly on faint surfaces to use the neutral active fill.",
|
|
75
|
-
"Surface context must match the actual parent surface; translucent, inverted, media, and always-dark treatments are reserved for those surfaces.",
|
|
75
|
+
"Surface context must match the actual parent surface; chrome, translucent, inverted, media, and always-dark treatments are reserved for those surfaces. The chrome variant uses the chrome foreground, border, and interaction families and does not paint the parent surface.",
|
|
76
76
|
"Loading prevents duplicate activation without applying inactive opacity or removing the current keyboard focus.",
|
|
77
77
|
"Rounded changes only the control radius to the half-radius treatment; it does not change hierarchy, size, variant, or interaction semantics.",
|
|
78
78
|
"Physical press scaling is on by default. Disable it only when an owning composite must keep child or background geometry fixed; hover and pressed interaction washes remain available.",
|
|
@@ -200,11 +200,11 @@
|
|
|
200
200
|
},
|
|
201
201
|
"background": {
|
|
202
202
|
"type": "ButtonUnfilledBackground | undefined",
|
|
203
|
-
"resolvedType": "\"always-dark\" | \"bold\" | \"faint\" | \"inverted\" | \"media\" | \"medium\" | \"strong\" | \"translucent\" | undefined",
|
|
203
|
+
"resolvedType": "\"always-dark\" | \"bold\" | \"chrome\" | \"faint\" | \"inverted\" | \"media\" | \"medium\" | \"strong\" | \"translucent\" | undefined",
|
|
204
204
|
"attribute": "background",
|
|
205
205
|
"required": false,
|
|
206
206
|
"mutable": false,
|
|
207
|
-
"description": "Actual parent surface context. Omit on primary and secondary surfaces."
|
|
207
|
+
"description": "Actual parent surface context. Omit on primary and secondary surfaces; use\nchrome for shell surfaces."
|
|
208
208
|
},
|
|
209
209
|
"collapseLabel": {
|
|
210
210
|
"type": "boolean",
|
|
@@ -485,11 +485,11 @@
|
|
|
485
485
|
},
|
|
486
486
|
"background": {
|
|
487
487
|
"type": "ButtonUnfilledBackground | undefined",
|
|
488
|
-
"resolvedType": "\"always-dark\" | \"bold\" | \"faint\" | \"inverted\" | \"media\" | \"medium\" | \"strong\" | \"translucent\" | undefined",
|
|
488
|
+
"resolvedType": "\"always-dark\" | \"bold\" | \"chrome\" | \"faint\" | \"inverted\" | \"media\" | \"medium\" | \"strong\" | \"translucent\" | undefined",
|
|
489
489
|
"attribute": "background",
|
|
490
490
|
"required": false,
|
|
491
491
|
"mutable": false,
|
|
492
|
-
"description": "Actual parent surface context. Omit on primary and secondary surfaces."
|
|
492
|
+
"description": "Actual parent surface context. Omit on primary and secondary surfaces; use\nchrome for shell surfaces."
|
|
493
493
|
},
|
|
494
494
|
"collapseLabel": {
|
|
495
495
|
"type": "boolean",
|
|
@@ -775,7 +775,7 @@
|
|
|
775
775
|
},
|
|
776
776
|
"peerDependencies": {
|
|
777
777
|
"required": [
|
|
778
|
-
"@ds-mo/tokens ^6.
|
|
778
|
+
"@ds-mo/tokens ^6.6.1",
|
|
779
779
|
"@ds-mo/icons ^8.1.1"
|
|
780
780
|
],
|
|
781
781
|
"frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
|
|
@@ -797,12 +797,12 @@
|
|
|
797
797
|
"files": [
|
|
798
798
|
{
|
|
799
799
|
"path": "src/wc/components/ButtonUnfilled/ButtonUnfilled.css",
|
|
800
|
-
"content": "@import '../../utils/radius.css';\n@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",
|
|
800
|
+
"content": "@import '../../utils/radius.css';\n@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:host(.button-unfilled-host--background-chrome) {\n --ds-button-split-border: var(--color-chrome-border-secondary);\n --ds-button-split-divider: var(--color-chrome-divider);\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.button-unfilled--background-chrome {\n --ds-button-unfilled-fg: var(--color-chrome-foreground-secondary);\n --ds-button-unfilled-fg-active: var(--color-chrome-foreground-primary);\n --ds-button-unfilled-dot-ring: var(--color-chrome-background-theme);\n --ds-button-unfilled-border: var(--color-chrome-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",
|
|
801
801
|
"type": "registry:ui"
|
|
802
802
|
},
|
|
803
803
|
{
|
|
804
804
|
"path": "src/wc/components/ButtonUnfilled/ButtonUnfilled.tsx",
|
|
805
|
-
"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 state forwarded to aria-expanded.\n * Using expanded alone for surface-open styling is deprecated; set surfaceOpen\n * explicitly to separate the rendered surface lifecycle from disclosure state.\n */\n @Prop() expanded: boolean | undefined;\n\n /**\n * The associated menu, picker, or panel is visible, including its exit motion.\n * Holds only the pressed wash; does not set ARIA, selection, or press scaling.\n * In split mode this applies only to the menu segment. Explicit false disables\n * the legacy expanded-derived wash; omission preserves that compatibility path.\n */\n @Prop() surfaceOpen: 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 private get resolvedSurfaceOpen(): boolean {\n const legacy = this.expanded === true && (this.split || this.resolvedHaspopup !== undefined);\n return (this.surfaceOpen ?? legacy) && !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-interaction-fill--surface-open': 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.resolvedSurfaceOpen,\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.resolvedSurfaceOpen, 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",
|
|
805
|
+
"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 | 'chrome';\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 /**\n * Actual parent surface context. Omit on primary and secondary surfaces; use\n * chrome for shell surfaces.\n */\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 state forwarded to aria-expanded.\n * Using expanded alone for surface-open styling is deprecated; set surfaceOpen\n * explicitly to separate the rendered surface lifecycle from disclosure state.\n */\n @Prop() expanded: boolean | undefined;\n\n /**\n * The associated menu, picker, or panel is visible, including its exit motion.\n * Holds only the pressed wash; does not set ARIA, selection, or press scaling.\n * In split mode this applies only to the menu segment. Explicit false disables\n * the legacy expanded-derived wash; omission preserves that compatibility path.\n */\n @Prop() surfaceOpen: 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 private get resolvedSurfaceOpen(): boolean {\n const legacy = this.expanded === true && (this.split || this.resolvedHaspopup !== undefined);\n return (this.surfaceOpen ?? legacy) && !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 'ds-interaction-fill--on-chrome': bg === 'chrome',\n 'button-unfilled--active': this.visuallyActive,\n 'button-unfilled--expanded': expanded,\n 'ds-interaction-fill--surface-open': 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 'button-unfilled--background-chrome': bg === 'chrome',\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.resolvedSurfaceOpen,\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.resolvedSurfaceOpen, 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",
|
|
806
806
|
"type": "registry:ui"
|
|
807
807
|
}
|
|
808
808
|
]
|
|
@@ -198,7 +198,7 @@
|
|
|
198
198
|
"complexPropertyNote": "Assign these non-primitive values as JavaScript properties: sections.",
|
|
199
199
|
"peerDependencies": {
|
|
200
200
|
"required": [
|
|
201
|
-
"@ds-mo/tokens ^6.
|
|
201
|
+
"@ds-mo/tokens ^6.6.1",
|
|
202
202
|
"@ds-mo/icons ^8.1.1"
|
|
203
203
|
],
|
|
204
204
|
"frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
|
|
@@ -376,7 +376,7 @@
|
|
|
376
376
|
"complexPropertyNote": "Assign these non-primitive values as JavaScript properties: metrics, score.",
|
|
377
377
|
"peerDependencies": {
|
|
378
378
|
"required": [
|
|
379
|
-
"@ds-mo/tokens ^6.
|
|
379
|
+
"@ds-mo/tokens ^6.6.1",
|
|
380
380
|
"@ds-mo/icons ^8.1.1"
|
|
381
381
|
],
|
|
382
382
|
"frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
|
|
@@ -49,7 +49,10 @@
|
|
|
49
49
|
"component:ds-select",
|
|
50
50
|
"component:ds-switch",
|
|
51
51
|
"component:ds-text",
|
|
52
|
-
"component:ds-setting-row"
|
|
52
|
+
"component:ds-setting-row-toggle",
|
|
53
|
+
"component:ds-setting-row-radio",
|
|
54
|
+
"component:ds-setting-row-checkbox",
|
|
55
|
+
"component:ds-inline-banner-settings"
|
|
53
56
|
],
|
|
54
57
|
"accessibility": [
|
|
55
58
|
"Provide a concise heading that identifies the settings section; CardSetting renders it as an h2.",
|
|
@@ -64,26 +67,30 @@
|
|
|
64
67
|
"The editing property is controlled; CardSetting never changes it internally.",
|
|
65
68
|
"dsAction emits edit, save, or cancel with the original pointer event. The parent decides whether and when editing changes.",
|
|
66
69
|
"When another section requests edit, the parent keeps one active section and resolves any dirty current section before switching.",
|
|
70
|
+
"Project persistent informational copy into the banner slot so it sits above the padded content body and does not receive content-area padding.",
|
|
67
71
|
"The parent owns read-only versus editable body composition, dirty state, validation, persistence, loading, success, and error consequences.",
|
|
68
72
|
"A save request keeps the section editing while validation or persistence is pending; the parent exits only after success.",
|
|
69
73
|
"A cancel request does not persist changes; the parent restores its chosen value snapshot and exits editing.",
|
|
70
74
|
"The immediate variant keeps the resting card surface and omits header actions even if editing is supplied. The application applies and persists each control change independently."
|
|
71
75
|
],
|
|
72
76
|
"responsiveBehavior": [
|
|
73
|
-
"Choose sm, md, or lg from the parent layout.
|
|
77
|
+
"Choose sm, md, or lg from the parent layout. Empty editable cards use the matching minimum height. Cards with body content, and immediate cards, fit that content.",
|
|
74
78
|
"The surface never exceeds its parent width, while the parent owns wrapping, columns, stacking, and breakpoint changes.",
|
|
75
79
|
"At narrow widths, keep the fixed header actions visible and let application-owned body layouts collapse before allowing horizontal overflow."
|
|
76
80
|
],
|
|
77
81
|
"frameworkCaveats": {
|
|
78
82
|
"customElements": [
|
|
83
|
+
"Project ds-inline-banner-settings with slot=\"banner\". Leave setting rows and other controls in the default slot.",
|
|
79
84
|
"Set editing as a JavaScript property and inspect dsAction.detail.action before updating the controlled state.",
|
|
80
85
|
"When one section emits edit, update every sibling CardSetting so only the requested section remains editing."
|
|
81
86
|
],
|
|
82
87
|
"react": [
|
|
88
|
+
"Pass slot=\"banner\" on ds-inline-banner-settings. Leave setting rows and other controls in the default slot.",
|
|
83
89
|
"Pass editing from parent state and inspect onDsAction event detail; do not treat Save as successful until validation and persistence complete.",
|
|
84
90
|
"Store one active section id and derive each CardSetting editing prop from that id."
|
|
85
91
|
],
|
|
86
92
|
"angular": [
|
|
93
|
+
"Set slot=\"banner\" on ds-inline-banner-settings. Leave setting rows and other controls in the default slot.",
|
|
87
94
|
"Bind [editing] and inspect $event.detail.action from (dsAction); do not treat Save as successful until validation and persistence complete.",
|
|
88
95
|
"Store one active section id and derive each CardSetting editing binding from that id."
|
|
89
96
|
]
|
|
@@ -118,12 +125,19 @@
|
|
|
118
125
|
"reason": "The component owns its surface radius; retain the shared recipe and customize an outer wrapper when needed.",
|
|
119
126
|
"props": []
|
|
120
127
|
},
|
|
128
|
+
{
|
|
129
|
+
"properties": [
|
|
130
|
+
"padding"
|
|
131
|
+
],
|
|
132
|
+
"reason": "Content-area padding-block belongs on the body. The banner slot sits above that padding and does not receive it.",
|
|
133
|
+
"props": []
|
|
134
|
+
},
|
|
121
135
|
{
|
|
122
136
|
"properties": [
|
|
123
137
|
"width",
|
|
124
138
|
"min-height"
|
|
125
139
|
],
|
|
126
|
-
"reason": "Card width selects the component geometry; immediate cards fit
|
|
140
|
+
"reason": "Card width selects the component geometry. Empty editable cards keep the matching minimum height; cards with body content and immediate cards fit that content. Let the parent constrain available space.",
|
|
127
141
|
"props": [
|
|
128
142
|
"cardWidth",
|
|
129
143
|
"variant"
|
|
@@ -150,7 +164,7 @@
|
|
|
150
164
|
"default": "'md'",
|
|
151
165
|
"required": false,
|
|
152
166
|
"mutable": false,
|
|
153
|
-
"description": "Card width token (`sm` / `md` / `lg`).
|
|
167
|
+
"description": "Card width token (`sm` / `md` / `lg`). Empty editable cards use the matching\nminimum-height token. Cards with body content, and immediate cards, fit\nthat content."
|
|
154
168
|
},
|
|
155
169
|
"editLabel": {
|
|
156
170
|
"type": "string",
|
|
@@ -224,7 +238,7 @@
|
|
|
224
238
|
"default": "'md'",
|
|
225
239
|
"required": false,
|
|
226
240
|
"mutable": false,
|
|
227
|
-
"description": "Card width token (`sm` / `md` / `lg`).
|
|
241
|
+
"description": "Card width token (`sm` / `md` / `lg`). Empty editable cards use the matching\nminimum-height token. Cards with body content, and immediate cards, fit\nthat content."
|
|
228
242
|
},
|
|
229
243
|
"editLabel": {
|
|
230
244
|
"type": "string",
|
|
@@ -308,7 +322,7 @@
|
|
|
308
322
|
},
|
|
309
323
|
"peerDependencies": {
|
|
310
324
|
"required": [
|
|
311
|
-
"@ds-mo/tokens ^6.
|
|
325
|
+
"@ds-mo/tokens ^6.6.1",
|
|
312
326
|
"@ds-mo/icons ^8.1.1"
|
|
313
327
|
],
|
|
314
328
|
"frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
|
|
@@ -327,12 +341,12 @@
|
|
|
327
341
|
"files": [
|
|
328
342
|
{
|
|
329
343
|
"path": "src/wc/components/CardSetting/CardSetting.css",
|
|
330
|
-
"content": "@import '../../utils/radius.css';\n@import '../../utils/chrome-header.css';\n@import '../../utils/forced-colors.css';\n\n:host {\n position: relative;\n display: flex;\n flex-direction: column;\n box-sizing: border-box;\n width: var(--_card-setting-width);\n min-height: var(--_card-setting-min-height);\n max-width: 100%;\n overflow: hidden;\n border: none;\n border-radius: var(--ds-radius-card);\n background-color: var(--color-background-primary);\n box-shadow: var(--effect-shadow-elevated-sm);\n}\n\n:host::after {\n content: '';\n position: absolute;\n inset: 0;\n z-index: 4;\n border-radius: inherit;\n box-shadow: var(--effect-highlight-elevated-sm);\n pointer-events: none;\n}\n\n:host(.card-setting--editing) {\n background-color: var(--color-background-bold-brand);\n box-shadow: 0 0 0 var(--dimension-stroke-width-025) var(--color-border-bold-brand);\n}\n\n:host(.card-setting--editing)::after {\n box-shadow: none;\n}\n\n.card-setting__header {\n flex: 0 0 auto;\n border-bottom: var(--dimension-stroke-width-012) solid var(--color-border-tertiary);\n}\n\n:host(.card-setting--editing) .card-setting__header {\n border-bottom-color: transparent;\n}\n\n.card-setting__copy {\n align-items: center;\n}\n\nds-text.card-setting__title {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n -webkit-user-select: none;\n user-select: none;\n}\n\n.card-setting__actions {\n flex-shrink: 0;\n}\n\n.card-
|
|
344
|
+
"content": "@import '../../utils/radius.css';\n@import '../../utils/chrome-header.css';\n@import '../../utils/forced-colors.css';\n\n:host {\n position: relative;\n display: flex;\n flex-direction: column;\n box-sizing: border-box;\n width: var(--_card-setting-width);\n min-height: var(--_card-setting-min-height);\n max-width: 100%;\n overflow: hidden;\n border: none;\n border-radius: var(--ds-radius-card);\n background-color: var(--color-background-primary);\n box-shadow: var(--effect-shadow-elevated-sm);\n}\n\n:host::after {\n content: '';\n position: absolute;\n inset: 0;\n z-index: 4;\n border-radius: inherit;\n box-shadow: var(--effect-highlight-elevated-sm);\n pointer-events: none;\n}\n\n:host(.card-setting--editing) {\n background-color: var(--color-background-bold-brand);\n box-shadow: 0 0 0 var(--dimension-stroke-width-025) var(--color-border-bold-brand);\n}\n\n:host(.card-setting--editing)::after {\n box-shadow: none;\n}\n\n.card-setting__header {\n flex: 0 0 auto;\n border-bottom: var(--dimension-stroke-width-012) solid var(--color-border-tertiary);\n}\n\n:host(.card-setting--editing) .card-setting__header {\n border-bottom-color: transparent;\n}\n\n.card-setting__copy {\n align-items: center;\n}\n\nds-text.card-setting__title {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n -webkit-user-select: none;\n user-select: none;\n}\n\n.card-setting__actions {\n flex-shrink: 0;\n}\n\n.card-setting__panel {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n min-height: 0;\n box-sizing: border-box;\n background-color: var(--color-background-primary);\n border-radius: 0 0 var(--ds-radius-card) var(--ds-radius-card);\n}\n\n:host(.card-setting--editing) .card-setting__panel {\n border-radius: var(--ds-radius-card);\n}\n\n.card-setting__banner {\n flex: 0 0 auto;\n min-width: 0;\n}\n\n.card-setting__banner--empty {\n display: none;\n}\n\n.card-setting__body {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n min-height: 0;\n box-sizing: border-box;\n padding-block: var(--dimension-space-100);\n}\n\n@media (forced-colors: active) {\n :host {\n box-shadow: none;\n outline: var(--dimension-stroke-width-012) solid var(--ds-forced-color-content);\n outline-offset: calc(-1 * var(--dimension-stroke-width-012));\n }\n\n :host::after {\n box-shadow: none;\n }\n}\n",
|
|
331
345
|
"type": "registry:ui"
|
|
332
346
|
},
|
|
333
347
|
{
|
|
334
348
|
"path": "src/wc/components/CardSetting/CardSetting.tsx",
|
|
335
|
-
"content": "import { Component, Event, EventEmitter, h, Host, Prop } from '@stencil/core';\n\nexport type CardSettingVariant = 'editable' | 'immediate';\nexport type CardSettingWidth = 'sm' | 'md' | 'lg';\nexport type CardSettingAction = 'edit' | 'save' | 'cancel';\n\nexport interface CardSettingActionDetail {\n action: CardSettingAction;\n originalEvent: MouseEvent;\n}\n\nconst CARD_WIDTH_VARS: Record<CardSettingWidth, string> = {\n sm: 'var(--dimension-card-width-sm)',\n md: 'var(--dimension-card-width-md)',\n lg: 'var(--dimension-card-width-lg)',\n};\n\nconst CARD_HEIGHT_VARS: Record<CardSettingWidth, string> = {\n sm: 'var(--dimension-card-height-sm)',\n md: 'var(--dimension-card-height-md)',\n lg: 'var(--dimension-card-height-lg)',\n};\n\nconst FAINT_BRAND_TITLE_COLOR = 'var(--color-foreground-faint-brand)';\n\n@Component({\n tag: 'ds-card-setting',\n styleUrl: 'CardSetting.css',\n scoped: true,\n})\nexport class CardSetting {\n /** Section heading shown in the card header. */\n @Prop() heading!: string;\n\n /**\n * Card width token (`sm` / `md` / `lg`).
|
|
349
|
+
"content": "import { Component, Element, Event, EventEmitter, h, Host, Prop, State } from '@stencil/core';\n\nexport type CardSettingVariant = 'editable' | 'immediate';\nexport type CardSettingWidth = 'sm' | 'md' | 'lg';\nexport type CardSettingAction = 'edit' | 'save' | 'cancel';\n\nexport interface CardSettingActionDetail {\n action: CardSettingAction;\n originalEvent: MouseEvent;\n}\n\nconst CARD_WIDTH_VARS: Record<CardSettingWidth, string> = {\n sm: 'var(--dimension-card-width-sm)',\n md: 'var(--dimension-card-width-md)',\n lg: 'var(--dimension-card-width-lg)',\n};\n\nconst CARD_HEIGHT_VARS: Record<CardSettingWidth, string> = {\n sm: 'var(--dimension-card-height-sm)',\n md: 'var(--dimension-card-height-md)',\n lg: 'var(--dimension-card-height-lg)',\n};\n\nconst FAINT_BRAND_TITLE_COLOR = 'var(--color-foreground-faint-brand)';\n\nconst isRenderableNode = (node: Node): boolean => {\n if (node.nodeType === Node.ELEMENT_NODE) {\n return (node as Element).tagName !== 'SLOT';\n }\n return node.nodeType === Node.TEXT_NODE && Boolean(node.textContent?.trim());\n};\n\nconst slotName = (node: Node): string | null =>\n node.nodeType === Node.ELEMENT_NODE ? (node as Element).getAttribute('slot') : null;\n\nconst isDefaultSlottedNode = (node: Node): boolean => isRenderableNode(node) && !slotName(node);\n\nconst isBannerSlottedNode = (node: Node): boolean =>\n isRenderableNode(node) && slotName(node) === 'banner';\n\nconst slotHasRenderableContent = (slot: HTMLSlotElement | null): boolean =>\n Boolean(slot?.assignedNodes({ flatten: true }).some(isRenderableNode));\n\n@Component({\n tag: 'ds-card-setting',\n styleUrl: 'CardSetting.css',\n scoped: true,\n})\nexport class CardSetting {\n @Element() el!: HTMLElement;\n\n /** Section heading shown in the card header. */\n @Prop() heading!: string;\n\n /**\n * Card width token (`sm` / `md` / `lg`). Empty editable cards use the matching\n * minimum-height token. Cards with body content, and immediate cards, fit\n * that content.\n */\n @Prop() cardWidth: CardSettingWidth = 'md';\n\n /** Immediate settings omit edit actions and apply changes through their own controls. */\n @Prop() variant: CardSettingVariant = 'editable';\n\n /** Controlled edit state — parent owns single-edit orchestration. */\n @Prop() editing = false;\n @Prop() editLabel: string = 'Edit';\n @Prop() cancelLabel: string = 'Cancel';\n @Prop() saveLabel: string = 'Save';\n\n /** Emits a controlled edit, save, or cancel request. */\n @Event() dsAction!: EventEmitter<CardSettingActionDetail>;\n\n @State() private hasBannerContent = false;\n @State() private hasBodyContent = false;\n\n componentWillLoad() {\n const nodes = Array.from(this.el.childNodes);\n this.hasBannerContent = nodes.some(isBannerSlottedNode);\n this.hasBodyContent = nodes.some(isDefaultSlottedNode);\n }\n\n componentDidLoad() {\n this.syncBannerContent();\n this.syncBodyContent();\n }\n\n private emitAction(action: CardSettingAction, originalEvent: MouseEvent) {\n this.dsAction.emit({ action, originalEvent });\n }\n\n private readSlotContent(\n event: Event | undefined,\n slotSelector: string,\n containerSelector: string\n ): boolean {\n const slot =\n event?.target instanceof HTMLSlotElement\n ? event.target\n : this.el.querySelector<HTMLSlotElement>(slotSelector);\n if (slotHasRenderableContent(slot)) return true;\n const container = this.el.querySelector(containerSelector);\n return Array.from(container?.childNodes ?? []).some(isRenderableNode);\n }\n\n private syncBannerContent = (event?: Event) => {\n const hasContent = this.readSlotContent(\n event,\n ':scope > .card-setting__panel > .card-setting__banner > slot',\n ':scope > .card-setting__panel > .card-setting__banner'\n );\n if (hasContent !== this.hasBannerContent) this.hasBannerContent = hasContent;\n };\n\n private syncBodyContent = (event?: Event) => {\n const hasContent = this.readSlotContent(\n event,\n ':scope > .card-setting__panel > .card-setting__body > slot',\n ':scope > .card-setting__panel > .card-setting__body'\n );\n if (hasContent !== this.hasBodyContent) this.hasBodyContent = hasContent;\n };\n\n private get hugContent(): boolean {\n return this.variant === 'immediate' || this.hasBannerContent || this.hasBodyContent;\n }\n\n render() {\n const editing = this.variant === 'editable' && this.editing;\n\n return (\n <Host\n class={{\n 'card-setting': true,\n 'card-setting--editing': editing,\n 'card-setting--immediate': this.variant === 'immediate',\n 'card-setting--empty': !this.hugContent,\n }}\n style={{\n '--_card-setting-width': CARD_WIDTH_VARS[this.cardWidth],\n '--_card-setting-min-height': this.hugContent ? '0' : CARD_HEIGHT_VARS[this.cardWidth],\n }}\n >\n <header class=\"card-setting__header ds-chrome-header\">\n {/* eslint-disable-next-line compomo/prefer-direct-ds-text -- Shared header copy owns the control-density geometry around the semantic heading. */}\n <div class=\"card-setting__copy ds-chrome-header__copy ds-control--md\">\n <ds-text\n class=\"card-setting__title ds-chrome-header__heading\"\n variant=\"text-title-small\"\n emphasis\n color={editing ? FAINT_BRAND_TITLE_COLOR : 'primary'}\n as=\"h2\"\n >\n {this.heading}\n </ds-text>\n </div>\n {this.variant === 'editable' && (\n <div class=\"card-setting__actions ds-chrome-header__trailing\">\n {!editing ? (\n <ds-button-unfilled\n variant=\"icon\"\n type=\"button\"\n icon=\"Pencil\"\n aria-label={this.editLabel}\n onDsClick={(event: CustomEvent<MouseEvent>) =>\n this.emitAction('edit', event.detail)\n }\n />\n ) : (\n [\n <ds-button-unfilled\n key=\"cancel\"\n variant=\"icon\"\n type=\"button\"\n icon=\"Cross\"\n background=\"bold\"\n aria-label={this.cancelLabel}\n onDsClick={(event: CustomEvent<MouseEvent>) =>\n this.emitAction('cancel', event.detail)\n }\n />,\n <ds-button-filled\n key=\"save\"\n variant=\"icon\"\n type=\"button\"\n icon=\"Check\"\n intent=\"brand\"\n contrast=\"faint\"\n aria-label={this.saveLabel}\n onDsClick={(event: CustomEvent<MouseEvent>) =>\n this.emitAction('save', event.detail)\n }\n />,\n ]\n )}\n </div>\n )}\n </header>\n <div class=\"card-setting__panel\">\n <div\n class={{\n 'card-setting__banner': true,\n 'card-setting__banner--empty': !this.hasBannerContent,\n }}\n >\n <slot name=\"banner\" onSlotchange={this.syncBannerContent} />\n </div>\n <div class=\"card-setting__body\">\n <slot onSlotchange={this.syncBodyContent} />\n </div>\n </div>\n </Host>\n );\n }\n}\n",
|
|
336
350
|
"type": "registry:ui"
|
|
337
351
|
}
|
|
338
352
|
]
|
|
@@ -277,7 +277,7 @@
|
|
|
277
277
|
"complexPropertyNote": "Assign these non-primitive values as JavaScript properties: items.",
|
|
278
278
|
"peerDependencies": {
|
|
279
279
|
"required": [
|
|
280
|
-
"@ds-mo/tokens ^6.
|
|
280
|
+
"@ds-mo/tokens ^6.6.1",
|
|
281
281
|
"@ds-mo/icons ^8.1.1"
|
|
282
282
|
],
|
|
283
283
|
"frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
|
|
@@ -239,7 +239,7 @@
|
|
|
239
239
|
"complexPropertyNote": "Assign these non-primitive values as JavaScript properties: definition.",
|
|
240
240
|
"peerDependencies": {
|
|
241
241
|
"required": [
|
|
242
|
-
"@ds-mo/tokens ^6.
|
|
242
|
+
"@ds-mo/tokens ^6.6.1",
|
|
243
243
|
"@ds-mo/icons ^8.1.1"
|
|
244
244
|
],
|
|
245
245
|
"frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
|