@ds-mo/ui 15.2.0 → 15.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.package-ready.json +1 -1
- package/dist/agent-patterns.json +3 -3
- package/dist/agent.json +446 -65
- package/dist/angular/ds-card-setting.d.ts +1 -1
- package/dist/angular/ds-card-setting.js +3 -3
- package/dist/angular/ds-input-time.d.ts +1 -1
- package/dist/angular/ds-input-time.js +3 -3
- package/dist/angular/ds-input.d.ts +5 -1
- package/dist/angular/ds-input.js +10 -4
- package/dist/angular/ds-map-entity-marker.d.ts +1 -1
- package/dist/angular/ds-map-entity-marker.js +3 -3
- package/dist/angular/ds-radio-tile.d.ts +15 -0
- package/dist/angular/ds-radio-tile.js +43 -0
- package/dist/angular/ds-setting-row.d.ts +18 -0
- package/dist/angular/ds-setting-row.js +42 -0
- package/dist/angular/ds-slider.d.ts +1 -1
- package/dist/angular/ds-slider.js +3 -3
- package/dist/angular/ds-textarea.d.ts +1 -1
- package/dist/angular/ds-textarea.js +3 -3
- package/dist/angular/ds-time-picker.d.ts +1 -1
- package/dist/angular/ds-time-picker.js +3 -3
- package/dist/angular/index.d.ts +1 -1
- package/dist/angular/index.js +2 -0
- package/dist/angular/number-value-accessor.d.ts +9 -0
- package/dist/angular/number-value-accessor.js +39 -0
- package/dist/angular/proxies.d.ts +2 -0
- package/dist/angular/proxies.js +2 -0
- package/dist/angular/radio-value-accessor.d.ts +1 -1
- package/dist/angular/radio-value-accessor.js +2 -2
- package/dist/angular/select-value-accessor.d.ts +1 -1
- package/dist/angular/select-value-accessor.js +2 -2
- package/dist/angular/text-value-accessor.d.ts +1 -1
- package/dist/angular/text-value-accessor.js +2 -2
- 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-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-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-chart.js +1 -1
- package/dist/components/ds-card-navigation.js +1 -1
- package/dist/components/ds-card-overview.js +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-chart-legend.js +1 -1
- package/dist/components/ds-chart.js +1 -1
- package/dist/components/ds-checkbox.js +1 -1
- package/dist/components/ds-chip.js +1 -1
- package/dist/components/ds-code-block.js +1 -1
- package/dist/components/ds-conversation-list-item.js +1 -1
- package/dist/components/ds-conversation-list-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-customize.js.map +1 -1
- package/dist/components/ds-data-filter.js +1 -1
- package/dist/components/ds-data-filter.js.map +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-preferences.js.map +1 -1
- package/dist/components/ds-data-saved-views.js +1 -1
- package/dist/components/ds-data-saved-views.js.map +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-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-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-map-entity-marker.js.map +1 -1
- package/dist/components/ds-markdown.js +1 -1
- package/dist/components/ds-menu.js +1 -1
- package/dist/components/ds-message-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-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-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.d.ts +11 -0
- package/dist/components/ds-radio-tile.js +2 -0
- package/dist/components/ds-radio-tile.js.map +1 -0
- 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.d.ts +11 -0
- package/dist/components/ds-setting-row.js +2 -0
- package/dist/components/ds-setting-row.js.map +1 -0
- package/dist/components/ds-shell-app.js +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-slider.js.map +1 -1
- package/dist/components/ds-swatch-picker.js +1 -1
- package/dist/components/ds-switch.js +1 -1
- package/dist/components/ds-tab-group.js +1 -1
- package/dist/components/ds-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-Br5e83Fr.js → p-3bsypMrY.js} +2 -2
- package/dist/components/{p-xhn1cZgU.js → p-AM_ht6Im.js} +2 -2
- package/dist/components/{p-B6qQaYkB.js → p-AmT4GlhM.js} +2 -2
- package/dist/components/{p-CuWPWC3t.js → p-B-HOVYoH.js} +2 -2
- package/dist/components/{p-p0FVyEFa.js → p-B7QEpaMe.js} +2 -2
- package/dist/components/{p-BX506yEW.js → p-B7bXN-vf.js} +2 -2
- package/dist/components/p-BHI4LcGK.js +2 -0
- package/dist/components/p-BHI4LcGK.js.map +1 -0
- package/dist/components/{p-CNZ6-kWd.js → p-BSuMDPaV.js} +2 -2
- package/dist/components/{p-Dqfc6Nvd.js → p-BU1B6NW8.js} +2 -2
- package/dist/components/{p-ZYWnJaye.js → p-BVwg5XVz.js} +2 -2
- package/dist/components/{p-C_Ma6Xa-.js → p-BXSHN1OK.js} +2 -2
- package/dist/components/{p-ER5M085B.js → p-BYJtvRQm.js} +2 -2
- package/dist/components/{p-DFO5lV_A.js → p-Bh1Fx0aW.js} +2 -2
- package/dist/components/{p-C1gaWjOm.js → p-Bm3KWMe4.js} +2 -2
- package/dist/components/{p-CR-Jjdcn.js → p-Bo7GxFBh.js} +2 -2
- package/dist/components/{p-BtnTQp4K.js → p-BsM37Prt.js} +2 -2
- package/dist/components/p-Bu4OmhKK.js +2 -0
- package/dist/components/{p-Dlp1HqgS.js.map → p-Bu4OmhKK.js.map} +1 -1
- package/dist/components/{p-C0JkLR83.js → p-BugKaVWc.js} +2 -2
- package/dist/components/p-C-c8SJ00.js +2 -0
- package/dist/components/p-C-c8SJ00.js.map +1 -0
- package/dist/components/{p-uADksYMl.js → p-C3-dcROG.js} +2 -2
- package/dist/components/p-C4VeD49U.js +2 -0
- package/dist/components/{p-BR5OC2PX.js.map → p-C4VeD49U.js.map} +1 -1
- package/dist/components/{p-DsLXlxt3.js → p-CCpJT31M.js} +2 -2
- package/dist/components/p-CCpJT31M.js.map +1 -0
- package/dist/components/{p-D7K1ZHML.js → p-CI7c9kp-.js} +2 -2
- package/dist/components/{p-mV4vSjSK.js → p-CJD0kLeV.js} +2 -2
- package/dist/components/{p-BOhefRMt.js → p-C_gJD8l3.js} +2 -2
- package/dist/components/{p-ZwRLjD5M.js → p-Cihjy4WY.js} +2 -2
- package/dist/components/p-Co5MiPNa.js +2 -0
- package/dist/components/{p-lamoJZE4.js.map → p-Co5MiPNa.js.map} +1 -1
- package/dist/components/{p-5SVmAjXY.js → p-CrL9wxZg.js} +2 -2
- package/dist/components/{p-CGidq1iC.js → p-CuwopElg.js} +2 -2
- package/dist/components/p-CwUXroLs.js +2 -0
- package/dist/components/{p-etg-Uk1u.js.map → p-CwUXroLs.js.map} +1 -1
- package/dist/components/{p-mux14tWZ.js → p-CzQ_JF6A.js} +2 -2
- package/dist/components/{p-BLuqpHvp.js → p-CztB8Pbq.js} +2 -2
- package/dist/components/{p-Cn6AfzeF.js → p-D0KD-Nr_.js} +2 -2
- package/dist/components/{p-D5HxZrMA.js → p-DCLRAH5i.js} +2 -2
- package/dist/components/{p-Cu8o2rOz.js → p-DFkw6wrS.js} +2 -2
- package/dist/components/{p-YrnU2fM7.js → p-DHapI2sf.js} +2 -2
- package/dist/components/p-DQPzqcYR.js +2 -0
- package/dist/components/p-DQPzqcYR.js.map +1 -0
- package/dist/components/{p-CTGgXIXM.js → p-DWmYCOKz.js} +2 -2
- package/dist/components/p-DX2RyZba.js +2 -0
- package/dist/components/{p-mxZoWfnS.js.map → p-DX2RyZba.js.map} +1 -1
- package/dist/components/{p-vfCu7XSc.js → p-DZ58Sg5a.js} +2 -2
- package/dist/components/{p-C6Aavz9h.js → p-Dcn1eDVt.js} +2 -2
- package/dist/components/{p-UY63jmrO.js → p-DcrdyDRw.js} +2 -2
- package/dist/components/p-DhKvqh5G.js +2 -0
- package/dist/components/p-DhKvqh5G.js.map +1 -0
- package/dist/components/p-Fkkd3gMB.js +2 -0
- package/dist/components/{p-BfF4RZdp.js.map → p-Fkkd3gMB.js.map} +1 -1
- package/dist/components/{p-QWukusRL.js → p-Gb-vTuXr.js} +2 -2
- package/dist/components/p-TVkFIMXz.js +2 -0
- package/dist/components/p-TVkFIMXz.js.map +1 -0
- package/dist/components/p-cuZva5tl.js +2 -0
- package/dist/components/{p-CZ7hxDy_.js.map → p-cuZva5tl.js.map} +1 -1
- package/dist/components/p-fYZK3zqM.js +2 -0
- package/dist/components/{p-BZ_e69zx.js.map → p-fYZK3zqM.js.map} +1 -1
- package/dist/components/{p-BzYW1IqO.js → p-iGNHXFZA.js} +2 -2
- package/dist/components/{p-BLSSaVWm.js → p-lADW-TI8.js} +2 -2
- package/dist/components/{p-BJJh-Bf7.js → p-p_MwknM3.js} +2 -2
- package/dist/components/{p-CRk0TjQv.js → p-tJaC01aE.js} +2 -2
- package/dist/components/{p-B3CZvMXs.js → p-z8L-YMi3.js} +2 -2
- package/dist/docs/components.json +1472 -94
- package/dist/framework/angular.d.ts +1 -0
- package/dist/framework/angular.js +1 -0
- package/dist/lint/index.js +1 -1
- package/dist/mcp-data/registry/agent-activity.json +2 -2
- package/dist/mcp-data/registry/agent-questionnaire.json +2 -2
- package/dist/mcp-data/registry/agent-response.json +2 -2
- package/dist/mcp-data/registry/agent-source-list.json +2 -2
- package/dist/mcp-data/registry/agent-tool-call.json +2 -2
- package/dist/mcp-data/registry/attachment-list.json +2 -2
- package/dist/mcp-data/registry/avatar.json +2 -2
- package/dist/mcp-data/registry/badge.json +2 -2
- package/dist/mcp-data/registry/banner.json +2 -2
- package/dist/mcp-data/registry/bar-action.json +2 -2
- package/dist/mcp-data/registry/bar-nav.json +2 -2
- package/dist/mcp-data/registry/bar-page-title.json +2 -2
- package/dist/mcp-data/registry/bar-title.json +2 -2
- package/dist/mcp-data/registry/bar-workflow.json +2 -2
- package/dist/mcp-data/registry/breadcrumb.json +2 -2
- package/dist/mcp-data/registry/button-filled.json +2 -2
- package/dist/mcp-data/registry/button-inverted.json +2 -2
- package/dist/mcp-data/registry/button-unfilled.json +2 -2
- package/dist/mcp-data/registry/calendar.json +2 -2
- package/dist/mcp-data/registry/card-action-center.json +2 -2
- package/dist/mcp-data/registry/card-chart.json +2 -2
- package/dist/mcp-data/registry/card-navigation.json +2 -2
- package/dist/mcp-data/registry/card-overview.json +2 -2
- package/dist/mcp-data/registry/card-setting.json +36 -15
- package/dist/mcp-data/registry/card-settings-scope.json +2 -2
- package/dist/mcp-data/registry/chart-legend.json +2 -2
- package/dist/mcp-data/registry/chart.json +2 -2
- package/dist/mcp-data/registry/checkbox.json +2 -2
- package/dist/mcp-data/registry/chip.json +2 -2
- package/dist/mcp-data/registry/code-block.json +2 -2
- package/dist/mcp-data/registry/conversation-list-item.json +2 -2
- package/dist/mcp-data/registry/conversation-list-section.json +2 -2
- package/dist/mcp-data/registry/conversation-list.json +2 -2
- package/dist/mcp-data/registry/data-customize.json +3 -3
- package/dist/mcp-data/registry/data-filter.json +2 -2
- package/dist/mcp-data/registry/data-group.json +2 -2
- package/dist/mcp-data/registry/data-preferences.json +2 -2
- package/dist/mcp-data/registry/data-saved-views.json +2 -2
- package/dist/mcp-data/registry/data-search.json +2 -2
- package/dist/mcp-data/registry/data-sort.json +2 -2
- package/dist/mcp-data/registry/data-toolbar.json +2 -2
- package/dist/mcp-data/registry/divider.json +2 -2
- package/dist/mcp-data/registry/empty-state.json +27 -14
- package/dist/mcp-data/registry/field.json +6 -5
- package/dist/mcp-data/registry/filter-menu.json +2 -2
- package/dist/mcp-data/registry/icon.json +2 -2
- package/dist/mcp-data/registry/input-date.json +2 -2
- package/dist/mcp-data/registry/input-time.json +26 -7
- package/dist/mcp-data/registry/input.json +265 -15
- package/dist/mcp-data/registry/loader.json +2 -2
- package/dist/mcp-data/registry/map-cluster-marker.json +3 -3
- package/dist/mcp-data/registry/map-entity-marker.json +56 -56
- package/dist/mcp-data/registry/markdown.json +2 -2
- package/dist/mcp-data/registry/menu.json +2 -2
- package/dist/mcp-data/registry/message-actions.json +2 -2
- package/dist/mcp-data/registry/message-bubble.json +2 -2
- package/dist/mcp-data/registry/message-composer.json +2 -2
- package/dist/mcp-data/registry/message-scroller.json +2 -2
- package/dist/mcp-data/registry/message.json +2 -2
- package/dist/mcp-data/registry/mobile-bar-nav.json +2 -2
- package/dist/mcp-data/registry/mobile-header.json +2 -2
- package/dist/mcp-data/registry/mobile-section-switcher.json +2 -2
- package/dist/mcp-data/registry/mobile-sheet-nav.json +2 -2
- package/dist/mcp-data/registry/modal.json +2 -2
- package/dist/mcp-data/registry/pagination.json +2 -2
- package/dist/mcp-data/registry/panel-nav.json +2 -2
- package/dist/mcp-data/registry/panel-sub-nav.json +2 -2
- package/dist/mcp-data/registry/panel-tool-header.json +2 -2
- package/dist/mcp-data/registry/panel-tool-search.json +2 -2
- package/dist/mcp-data/registry/panel-tools.json +2 -2
- package/dist/mcp-data/registry/paper-texture.json +2 -2
- package/dist/mcp-data/registry/radio-tile.json +398 -0
- package/dist/mcp-data/registry/radio.json +2 -2
- package/dist/mcp-data/registry/registry.json +453 -66
- package/dist/mcp-data/registry/score.json +2 -2
- package/dist/mcp-data/registry/scroll-overlay.json +2 -2
- package/dist/mcp-data/registry/select.json +2 -2
- package/dist/mcp-data/registry/setting-row.json +213 -0
- package/dist/mcp-data/registry/shell-app.json +2 -2
- package/dist/mcp-data/registry/shell-page.json +2 -2
- package/dist/mcp-data/registry/shell-tools.json +2 -2
- package/dist/mcp-data/registry/skeleton.json +2 -2
- package/dist/mcp-data/registry/slider.json +32 -12
- package/dist/mcp-data/registry/swatch-picker.json +2 -2
- package/dist/mcp-data/registry/switch.json +2 -2
- package/dist/mcp-data/registry/tab-group.json +2 -2
- package/dist/mcp-data/registry/table.json +5 -5
- package/dist/mcp-data/registry/tag.json +2 -2
- package/dist/mcp-data/registry/text.json +2 -2
- package/dist/mcp-data/registry/textarea.json +72 -5
- package/dist/mcp-data/registry/time-picker.json +28 -9
- package/dist/mcp-data/registry/toast.json +2 -2
- package/dist/mcp-data/registry/tooltip-chart.json +2 -2
- package/dist/mcp-data/registry/tooltip.json +2 -2
- package/dist/mcp-data/registry/typing-indicator.json +2 -2
- package/dist/react/components.d.ts +2 -0
- package/dist/react/components.js +2 -0
- package/dist/react/ds-input.d.ts +2 -0
- package/dist/react/ds-input.js +2 -0
- package/dist/react/ds-radio-tile.d.ts +12 -0
- package/dist/react/ds-radio-tile.js +12 -0
- package/dist/react/ds-setting-row.d.ts +12 -0
- package/dist/react/ds-setting-row.js +12 -0
- package/dist/types/components/CardSetting/CardSetting.d.ts +5 -3
- package/dist/types/components/CardSetting/index.d.ts +1 -1
- package/dist/types/components/EmptyState/EmptyState.d.ts +3 -0
- package/dist/types/components/Field/Field.d.ts +4 -0
- package/dist/types/components/Input/Input.d.ts +50 -1
- package/dist/types/components/InputTime/InputTime.d.ts +3 -0
- package/dist/types/components/MapEntityMarker/MapEntityMarker.d.ts +5 -5
- package/dist/types/components/RadioTile/RadioTile.d.ts +40 -0
- package/dist/types/components/RadioTile/index.d.ts +2 -0
- package/dist/types/components/SettingRow/SettingRow.d.ts +18 -0
- package/dist/types/components/Slider/Slider.d.ts +8 -1
- package/dist/types/components/Slider/index.d.ts +1 -1
- package/dist/types/components/Textarea/Textarea.d.ts +12 -0
- package/dist/types/components/TimePicker/TimePicker.d.ts +4 -0
- package/dist/types/components.d.ts +456 -35
- package/dist/types/utils/text-constraints.d.ts +20 -0
- package/dist/vue/components.d.ts +2 -0
- package/dist/vue/components.js +2 -0
- package/dist/vue/ds-card-setting.js +1 -0
- package/dist/vue/ds-input-time.js +1 -0
- package/dist/vue/ds-input.js +17 -0
- package/dist/vue/ds-map-entity-marker.js +2 -2
- package/dist/vue/ds-radio-tile.d.ts +3 -0
- package/dist/vue/ds-radio-tile.js +24 -0
- package/dist/vue/ds-setting-row.d.ts +3 -0
- package/dist/vue/ds-setting-row.js +14 -0
- package/dist/vue/ds-slider.d.ts +1 -1
- package/dist/vue/ds-slider.js +2 -1
- package/dist/vue/ds-textarea.js +4 -0
- package/dist/vue/ds-time-picker.js +1 -0
- package/package.json +5 -5
- package/dist/components/p-BCnzbfma.js +0 -2
- package/dist/components/p-BCnzbfma.js.map +0 -1
- package/dist/components/p-BR5OC2PX.js +0 -2
- package/dist/components/p-BZ_e69zx.js +0 -2
- package/dist/components/p-BfF4RZdp.js +0 -2
- package/dist/components/p-Bv9rSkp0.js +0 -2
- package/dist/components/p-Bv9rSkp0.js.map +0 -1
- package/dist/components/p-C6zycbhC.js +0 -2
- package/dist/components/p-C6zycbhC.js.map +0 -1
- package/dist/components/p-CZ7hxDy_.js +0 -2
- package/dist/components/p-Dlp1HqgS.js +0 -2
- package/dist/components/p-DsLXlxt3.js.map +0 -1
- package/dist/components/p-etg-Uk1u.js +0 -2
- package/dist/components/p-lamoJZE4.js +0 -2
- package/dist/components/p-mxZoWfnS.js +0 -2
- package/dist/components/p-xtGGIZmU.js +0 -2
- package/dist/components/p-xtGGIZmU.js.map +0 -1
- /package/dist/components/{p-Br5e83Fr.js.map → p-3bsypMrY.js.map} +0 -0
- /package/dist/components/{p-xhn1cZgU.js.map → p-AM_ht6Im.js.map} +0 -0
- /package/dist/components/{p-B6qQaYkB.js.map → p-AmT4GlhM.js.map} +0 -0
- /package/dist/components/{p-CuWPWC3t.js.map → p-B-HOVYoH.js.map} +0 -0
- /package/dist/components/{p-p0FVyEFa.js.map → p-B7QEpaMe.js.map} +0 -0
- /package/dist/components/{p-BX506yEW.js.map → p-B7bXN-vf.js.map} +0 -0
- /package/dist/components/{p-CNZ6-kWd.js.map → p-BSuMDPaV.js.map} +0 -0
- /package/dist/components/{p-Dqfc6Nvd.js.map → p-BU1B6NW8.js.map} +0 -0
- /package/dist/components/{p-ZYWnJaye.js.map → p-BVwg5XVz.js.map} +0 -0
- /package/dist/components/{p-C_Ma6Xa-.js.map → p-BXSHN1OK.js.map} +0 -0
- /package/dist/components/{p-ER5M085B.js.map → p-BYJtvRQm.js.map} +0 -0
- /package/dist/components/{p-DFO5lV_A.js.map → p-Bh1Fx0aW.js.map} +0 -0
- /package/dist/components/{p-C1gaWjOm.js.map → p-Bm3KWMe4.js.map} +0 -0
- /package/dist/components/{p-CR-Jjdcn.js.map → p-Bo7GxFBh.js.map} +0 -0
- /package/dist/components/{p-BtnTQp4K.js.map → p-BsM37Prt.js.map} +0 -0
- /package/dist/components/{p-C0JkLR83.js.map → p-BugKaVWc.js.map} +0 -0
- /package/dist/components/{p-uADksYMl.js.map → p-C3-dcROG.js.map} +0 -0
- /package/dist/components/{p-D7K1ZHML.js.map → p-CI7c9kp-.js.map} +0 -0
- /package/dist/components/{p-mV4vSjSK.js.map → p-CJD0kLeV.js.map} +0 -0
- /package/dist/components/{p-BOhefRMt.js.map → p-C_gJD8l3.js.map} +0 -0
- /package/dist/components/{p-ZwRLjD5M.js.map → p-Cihjy4WY.js.map} +0 -0
- /package/dist/components/{p-5SVmAjXY.js.map → p-CrL9wxZg.js.map} +0 -0
- /package/dist/components/{p-CGidq1iC.js.map → p-CuwopElg.js.map} +0 -0
- /package/dist/components/{p-mux14tWZ.js.map → p-CzQ_JF6A.js.map} +0 -0
- /package/dist/components/{p-BLuqpHvp.js.map → p-CztB8Pbq.js.map} +0 -0
- /package/dist/components/{p-Cn6AfzeF.js.map → p-D0KD-Nr_.js.map} +0 -0
- /package/dist/components/{p-D5HxZrMA.js.map → p-DCLRAH5i.js.map} +0 -0
- /package/dist/components/{p-Cu8o2rOz.js.map → p-DFkw6wrS.js.map} +0 -0
- /package/dist/components/{p-YrnU2fM7.js.map → p-DHapI2sf.js.map} +0 -0
- /package/dist/components/{p-CTGgXIXM.js.map → p-DWmYCOKz.js.map} +0 -0
- /package/dist/components/{p-vfCu7XSc.js.map → p-DZ58Sg5a.js.map} +0 -0
- /package/dist/components/{p-C6Aavz9h.js.map → p-Dcn1eDVt.js.map} +0 -0
- /package/dist/components/{p-UY63jmrO.js.map → p-DcrdyDRw.js.map} +0 -0
- /package/dist/components/{p-QWukusRL.js.map → p-Gb-vTuXr.js.map} +0 -0
- /package/dist/components/{p-BzYW1IqO.js.map → p-iGNHXFZA.js.map} +0 -0
- /package/dist/components/{p-BLSSaVWm.js.map → p-lADW-TI8.js.map} +0 -0
- /package/dist/components/{p-BJJh-Bf7.js.map → p-p_MwknM3.js.map} +0 -0
- /package/dist/components/{p-CRk0TjQv.js.map → p-tJaC01aE.js.map} +0 -0
- /package/dist/components/{p-B3CZvMXs.js.map → p-z8L-YMi3.js.map} +0 -0
|
@@ -258,8 +258,8 @@
|
|
|
258
258
|
},
|
|
259
259
|
"peerDependencies": {
|
|
260
260
|
"required": [
|
|
261
|
-
"@ds-mo/tokens ^6.5.
|
|
262
|
-
"@ds-mo/icons ^8.1.
|
|
261
|
+
"@ds-mo/tokens ^6.5.2",
|
|
262
|
+
"@ds-mo/icons ^8.1.1"
|
|
263
263
|
],
|
|
264
264
|
"frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
|
|
265
265
|
}
|
|
@@ -166,8 +166,8 @@
|
|
|
166
166
|
},
|
|
167
167
|
"peerDependencies": {
|
|
168
168
|
"required": [
|
|
169
|
-
"@ds-mo/tokens ^6.5.
|
|
170
|
-
"@ds-mo/icons ^8.1.
|
|
169
|
+
"@ds-mo/tokens ^6.5.2",
|
|
170
|
+
"@ds-mo/icons ^8.1.1"
|
|
171
171
|
],
|
|
172
172
|
"frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
|
|
173
173
|
}
|
|
@@ -1089,8 +1089,8 @@
|
|
|
1089
1089
|
"complexPropertyNote": "Assign these non-primitive values as JavaScript properties: boundary, options, sections.",
|
|
1090
1090
|
"peerDependencies": {
|
|
1091
1091
|
"required": [
|
|
1092
|
-
"@ds-mo/tokens ^6.5.
|
|
1093
|
-
"@ds-mo/icons ^8.1.
|
|
1092
|
+
"@ds-mo/tokens ^6.5.2",
|
|
1093
|
+
"@ds-mo/icons ^8.1.1"
|
|
1094
1094
|
],
|
|
1095
1095
|
"frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
|
|
1096
1096
|
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
3
|
+
"name": "setting-row",
|
|
4
|
+
"title": "SettingRow",
|
|
5
|
+
"description": "Two-column immediate binary setting with descriptive copy and an accessible switch.",
|
|
6
|
+
"type": "registry:ui",
|
|
7
|
+
"meta": {
|
|
8
|
+
"library": "@ds-mo/ui",
|
|
9
|
+
"distribution": "npm",
|
|
10
|
+
"storybook": "https://zainadeel.github.io/compomo/?path=/story/setting-row",
|
|
11
|
+
"source": "src/wc/components/SettingRow/SettingRow.tsx",
|
|
12
|
+
"intentStatus": "complete",
|
|
13
|
+
"intent": {
|
|
14
|
+
"audience": "general",
|
|
15
|
+
"status": "experimental",
|
|
16
|
+
"summary": "Two-column immediate binary setting with descriptive copy and an accessible switch.",
|
|
17
|
+
"useWhen": [
|
|
18
|
+
"A settings list pairs a setting name and explanation with one immediate on/off control."
|
|
19
|
+
],
|
|
20
|
+
"avoidWhen": [
|
|
21
|
+
"The value needs a text input, multiple choices, or an explicit Save workflow."
|
|
22
|
+
],
|
|
23
|
+
"commonlyComposedWith": [
|
|
24
|
+
"component:ds-card-setting",
|
|
25
|
+
"component:ds-switch",
|
|
26
|
+
"component:ds-text"
|
|
27
|
+
],
|
|
28
|
+
"accessibility": [
|
|
29
|
+
"The visible label names the switch and the optional description supplies its accessible description.",
|
|
30
|
+
"Switch owns focus, keyboard activation, checked state, and disabled semantics. The row adds no second tab stop.",
|
|
31
|
+
"For a settings list, the owner supplies list semantics and marks each row as a list item."
|
|
32
|
+
],
|
|
33
|
+
"states": [
|
|
34
|
+
"The application accepts or rejects change requests by updating the controlled checked value and owns persistence and errors.",
|
|
35
|
+
"Name the enabled setting consistently; the label must not change when the switch is toggled."
|
|
36
|
+
],
|
|
37
|
+
"responsiveBehavior": [
|
|
38
|
+
"The copy wraps while the switch keeps its natural size in the trailing column, including at narrow widths."
|
|
39
|
+
],
|
|
40
|
+
"references": [
|
|
41
|
+
{
|
|
42
|
+
"label": "Usage states",
|
|
43
|
+
"path": "src/wc/components/SettingRow/SettingRow.stories.ts"
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
"styling": {
|
|
47
|
+
"rationale": "The row owns copy/control spacing; its parent owns the section surface and width.",
|
|
48
|
+
"protected": [
|
|
49
|
+
{
|
|
50
|
+
"properties": [
|
|
51
|
+
"padding",
|
|
52
|
+
"gap"
|
|
53
|
+
],
|
|
54
|
+
"reason": "Preserve the shared settings-row spacing recipe.",
|
|
55
|
+
"props": []
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
"customProperties": []
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"api": {
|
|
62
|
+
"props": {
|
|
63
|
+
"checked": {
|
|
64
|
+
"type": "boolean",
|
|
65
|
+
"resolvedType": "boolean",
|
|
66
|
+
"attribute": "checked",
|
|
67
|
+
"default": "false",
|
|
68
|
+
"required": false,
|
|
69
|
+
"mutable": false,
|
|
70
|
+
"description": "Controlled enabled state."
|
|
71
|
+
},
|
|
72
|
+
"description": {
|
|
73
|
+
"type": "string",
|
|
74
|
+
"resolvedType": "string | undefined",
|
|
75
|
+
"attribute": "description",
|
|
76
|
+
"required": false,
|
|
77
|
+
"mutable": false,
|
|
78
|
+
"description": "Supporting copy explaining the setting and its alternative."
|
|
79
|
+
},
|
|
80
|
+
"disabled": {
|
|
81
|
+
"type": "boolean",
|
|
82
|
+
"resolvedType": "boolean",
|
|
83
|
+
"attribute": "disabled",
|
|
84
|
+
"default": "false",
|
|
85
|
+
"required": false,
|
|
86
|
+
"mutable": false,
|
|
87
|
+
"description": "Prevent changes while the setting is unavailable."
|
|
88
|
+
},
|
|
89
|
+
"label": {
|
|
90
|
+
"type": "string",
|
|
91
|
+
"resolvedType": "string",
|
|
92
|
+
"attribute": "label",
|
|
93
|
+
"required": true,
|
|
94
|
+
"mutable": false,
|
|
95
|
+
"description": "Name of the enabled setting."
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"events": [
|
|
99
|
+
{
|
|
100
|
+
"name": "dsChange",
|
|
101
|
+
"detail": "boolean",
|
|
102
|
+
"bubbles": true,
|
|
103
|
+
"cancelable": true,
|
|
104
|
+
"composed": true,
|
|
105
|
+
"description": "Requests the next value; the application owns acceptance and persistence."
|
|
106
|
+
}
|
|
107
|
+
],
|
|
108
|
+
"methods": [],
|
|
109
|
+
"slots": []
|
|
110
|
+
},
|
|
111
|
+
"props": {
|
|
112
|
+
"checked": {
|
|
113
|
+
"type": "boolean",
|
|
114
|
+
"resolvedType": "boolean",
|
|
115
|
+
"attribute": "checked",
|
|
116
|
+
"default": "false",
|
|
117
|
+
"required": false,
|
|
118
|
+
"mutable": false,
|
|
119
|
+
"description": "Controlled enabled state."
|
|
120
|
+
},
|
|
121
|
+
"description": {
|
|
122
|
+
"type": "string",
|
|
123
|
+
"resolvedType": "string | undefined",
|
|
124
|
+
"attribute": "description",
|
|
125
|
+
"required": false,
|
|
126
|
+
"mutable": false,
|
|
127
|
+
"description": "Supporting copy explaining the setting and its alternative."
|
|
128
|
+
},
|
|
129
|
+
"disabled": {
|
|
130
|
+
"type": "boolean",
|
|
131
|
+
"resolvedType": "boolean",
|
|
132
|
+
"attribute": "disabled",
|
|
133
|
+
"default": "false",
|
|
134
|
+
"required": false,
|
|
135
|
+
"mutable": false,
|
|
136
|
+
"description": "Prevent changes while the setting is unavailable."
|
|
137
|
+
},
|
|
138
|
+
"label": {
|
|
139
|
+
"type": "string",
|
|
140
|
+
"resolvedType": "string",
|
|
141
|
+
"attribute": "label",
|
|
142
|
+
"required": true,
|
|
143
|
+
"mutable": false,
|
|
144
|
+
"description": "Name of the enabled setting."
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
"events": [
|
|
148
|
+
{
|
|
149
|
+
"name": "dsChange",
|
|
150
|
+
"detail": "boolean",
|
|
151
|
+
"bubbles": true,
|
|
152
|
+
"cancelable": true,
|
|
153
|
+
"composed": true,
|
|
154
|
+
"description": "Requests the next value; the application owns acceptance and persistence."
|
|
155
|
+
}
|
|
156
|
+
],
|
|
157
|
+
"methods": [],
|
|
158
|
+
"slots": [],
|
|
159
|
+
"exports": {
|
|
160
|
+
"customElement": "ds-setting-row",
|
|
161
|
+
"react": "DsSettingRow",
|
|
162
|
+
"vue": "DsSettingRow",
|
|
163
|
+
"angular": "DsSettingRow"
|
|
164
|
+
},
|
|
165
|
+
"consumption": {
|
|
166
|
+
"install": "npm install @ds-mo/ui @ds-mo/tokens @ds-mo/icons",
|
|
167
|
+
"cssSetup": "import '@ds-mo/tokens';\nimport '@ds-mo/tokens/reset';\nimport '@ds-mo/tokens/globals';",
|
|
168
|
+
"customElements": {
|
|
169
|
+
"import": "import '@ds-mo/ui/dist/components/ds-setting-row.js';",
|
|
170
|
+
"example": "<ds-setting-row></ds-setting-row>"
|
|
171
|
+
},
|
|
172
|
+
"react": {
|
|
173
|
+
"import": "import { DsSettingRow } from '@ds-mo/ui/react';",
|
|
174
|
+
"example": "<DsSettingRow />"
|
|
175
|
+
},
|
|
176
|
+
"vue": {
|
|
177
|
+
"import": "import { DsSettingRow } from '@ds-mo/ui/vue';",
|
|
178
|
+
"example": "<DsSettingRow />"
|
|
179
|
+
},
|
|
180
|
+
"angular": {
|
|
181
|
+
"import": "import { DsSettingRow } from '@ds-mo/ui/angular/ds-setting-row';",
|
|
182
|
+
"example": "<ds-setting-row></ds-setting-row>"
|
|
183
|
+
},
|
|
184
|
+
"peerDependencies": {
|
|
185
|
+
"required": [
|
|
186
|
+
"@ds-mo/tokens ^6.5.2",
|
|
187
|
+
"@ds-mo/icons ^8.1.1"
|
|
188
|
+
],
|
|
189
|
+
"frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
"dependencies": [
|
|
194
|
+
"@ds-mo/ui",
|
|
195
|
+
"@ds-mo/tokens"
|
|
196
|
+
],
|
|
197
|
+
"registryDependencies": [
|
|
198
|
+
"switch",
|
|
199
|
+
"text"
|
|
200
|
+
],
|
|
201
|
+
"files": [
|
|
202
|
+
{
|
|
203
|
+
"path": "src/wc/components/SettingRow/SettingRow.css",
|
|
204
|
+
"content": ":host {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n align-items: start;\n box-sizing: border-box;\n min-width: 0;\n padding: var(--dimension-space-100) var(--dimension-space-200);\n gap: var(--dimension-space-200);\n}\n\n.setting-row__copy {\n display: flex;\n flex-direction: column;\n min-width: 0;\n gap: var(--dimension-space-050);\n overflow-wrap: anywhere;\n -webkit-user-select: none;\n user-select: none;\n}\n",
|
|
205
|
+
"type": "registry:ui"
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
"path": "src/wc/components/SettingRow/SettingRow.tsx",
|
|
209
|
+
"content": "import { Component, Event, EventEmitter, h, Host, Prop } from '@stencil/core';\n\nlet settingRowSequence = 0;\n\n/** A labeled binary setting that applies immediately through its application owner. */\n@Component({\n tag: 'ds-setting-row',\n styleUrl: 'SettingRow.css',\n scoped: true,\n})\nexport class SettingRow {\n /** Name of the enabled setting. */\n @Prop() label!: string;\n /** Supporting copy explaining the setting and its alternative. */\n @Prop() description?: string;\n /** Controlled enabled state. */\n @Prop() checked = false;\n /** Prevent changes while the setting is unavailable. */\n @Prop() disabled = false;\n\n /** Requests the next value; the application owns acceptance and persistence. */\n @Event() dsChange!: EventEmitter<boolean>;\n\n private readonly rowId = `ds-setting-row-${++settingRowSequence}`;\n\n private handleChange = (event: CustomEvent<boolean>) => {\n event.stopPropagation();\n // Keep the composed switch controlled until the owner accepts this request.\n (event.target as HTMLDsSwitchElement).checked = this.checked;\n this.dsChange.emit(event.detail);\n };\n\n render() {\n return (\n <Host>\n <div class=\"setting-row__copy\">\n <ds-text\n textId={`${this.rowId}-label`}\n variant=\"text-body-medium\"\n color=\"primary\"\n emphasis\n >\n {this.label}\n </ds-text>\n {this.description && (\n <ds-text\n textId={`${this.rowId}-description`}\n variant=\"text-body-medium\"\n color=\"secondary\"\n >\n {this.description}\n </ds-text>\n )}\n </div>\n <ds-switch\n checked={this.checked}\n disabled={this.disabled}\n aria-labelledby={`${this.rowId}-label`}\n aria-describedby={this.description ? `${this.rowId}-description` : undefined}\n onDsChange={this.handleChange}\n />\n </Host>\n );\n }\n}\n",
|
|
210
|
+
"type": "registry:ui"
|
|
211
|
+
}
|
|
212
|
+
]
|
|
213
|
+
}
|
|
@@ -690,8 +690,8 @@
|
|
|
690
690
|
"complexPropertyNote": "Assign these non-primitive values as JavaScript properties: navigation, pageChrome, paperTexture, tools.",
|
|
691
691
|
"peerDependencies": {
|
|
692
692
|
"required": [
|
|
693
|
-
"@ds-mo/tokens ^6.5.
|
|
694
|
-
"@ds-mo/icons ^8.1.
|
|
693
|
+
"@ds-mo/tokens ^6.5.2",
|
|
694
|
+
"@ds-mo/icons ^8.1.1"
|
|
695
695
|
],
|
|
696
696
|
"frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
|
|
697
697
|
}
|
|
@@ -332,8 +332,8 @@
|
|
|
332
332
|
},
|
|
333
333
|
"peerDependencies": {
|
|
334
334
|
"required": [
|
|
335
|
-
"@ds-mo/tokens ^6.5.
|
|
336
|
-
"@ds-mo/icons ^8.1.
|
|
335
|
+
"@ds-mo/tokens ^6.5.2",
|
|
336
|
+
"@ds-mo/icons ^8.1.1"
|
|
337
337
|
],
|
|
338
338
|
"frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
|
|
339
339
|
}
|
|
@@ -457,8 +457,8 @@
|
|
|
457
457
|
"complexPropertyNote": "Assign these non-primitive values as JavaScript properties: accessories, headers, items.",
|
|
458
458
|
"peerDependencies": {
|
|
459
459
|
"required": [
|
|
460
|
-
"@ds-mo/tokens ^6.5.
|
|
461
|
-
"@ds-mo/icons ^8.1.
|
|
460
|
+
"@ds-mo/tokens ^6.5.2",
|
|
461
|
+
"@ds-mo/icons ^8.1.1"
|
|
462
462
|
],
|
|
463
463
|
"frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
|
|
464
464
|
}
|
|
@@ -300,8 +300,8 @@
|
|
|
300
300
|
},
|
|
301
301
|
"peerDependencies": {
|
|
302
302
|
"required": [
|
|
303
|
-
"@ds-mo/tokens ^6.5.
|
|
304
|
-
"@ds-mo/icons ^8.1.
|
|
303
|
+
"@ds-mo/tokens ^6.5.2",
|
|
304
|
+
"@ds-mo/icons ^8.1.1"
|
|
305
305
|
],
|
|
306
306
|
"frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
|
|
307
307
|
}
|
|
@@ -59,14 +59,15 @@
|
|
|
59
59
|
"Assign a two-number array through the JavaScript value property to create a range; values are ordered, clamped, stepped, and prevented from crossing.",
|
|
60
60
|
"minStepsBetweenValues reserves a minimum stepped distance between range thumbs.",
|
|
61
61
|
"The initial normalized value is the native form-reset baseline and range values submit as repeated entries under the same name.",
|
|
62
|
-
"Focused, filled, dirty, touched, dragging, valid, disabled, read-only, and orientation data hooks expose interaction state without changing the value contract."
|
|
62
|
+
"Focused, filled, dirty, touched, dragging, valid, disabled, read-only, and orientation data hooks expose interaction state without changing the value contract.",
|
|
63
|
+
"Explicit ticks define the only selectable snap points and may carry labels. Marks sit below a horizontal track, or beside a vertical track, with labels beyond the marks. Horizontal labels center on their marks and shift inward only when they reach the control edges. Without ticks, step=\"any\" permits smooth adjustment; ordinary stepped behavior remains available. Arrow keys traverse adjacent ticks and Home/End reach the available extremes."
|
|
63
64
|
],
|
|
64
65
|
"responsiveBehavior": [
|
|
65
66
|
"The visible label uses the same primary emphasized text-body-small recipe as Field at every density; the value uses the same primary metric without emphasis.",
|
|
66
67
|
"Horizontal Slider fills the width supplied by its parent; the parent chooses an appropriate readable track length.",
|
|
67
68
|
"Vertical Slider owns a token-based default length that may be overridden with --ds-slider-vertical-length in layout-specific compositions.",
|
|
68
69
|
"Use md in ordinary forms and sm or xs only when the surrounding control density uses the same recipe.",
|
|
69
|
-
"Track thickness scales with density
|
|
70
|
+
"Track thickness scales with density. The unfilled track has a neutral border, the filled range uses brand color, and the thumb uses the primary surface with subtle elevation.",
|
|
70
71
|
"Horizontal value direction is left-to-right; the design system does not author RTL-specific component behavior."
|
|
71
72
|
],
|
|
72
73
|
"frameworkCaveats": {
|
|
@@ -78,7 +79,10 @@
|
|
|
78
79
|
"Use DsSlider with a number or two-number value array and handle onDsChange and onDsCommit custom events."
|
|
79
80
|
],
|
|
80
81
|
"angular": [
|
|
81
|
-
"Use DsSlider with
|
|
82
|
+
"Use DsSlider with SelectValueAccessor for Angular Forms; it preserves either a number or a two-number array."
|
|
83
|
+
],
|
|
84
|
+
"vue": [
|
|
85
|
+
"Use v-model for a number or a two-number array. Assign ticks through property binding."
|
|
82
86
|
]
|
|
83
87
|
},
|
|
84
88
|
"references": [
|
|
@@ -307,8 +311,8 @@
|
|
|
307
311
|
"description": "Accessible label for the lower thumb in a range slider."
|
|
308
312
|
},
|
|
309
313
|
"step": {
|
|
310
|
-
"type": "number",
|
|
311
|
-
"resolvedType": "number",
|
|
314
|
+
"type": "number | 'any'",
|
|
315
|
+
"resolvedType": "\"any\" | number",
|
|
312
316
|
"attribute": "step",
|
|
313
317
|
"default": "1",
|
|
314
318
|
"required": false,
|
|
@@ -323,6 +327,14 @@
|
|
|
323
327
|
"mutable": false,
|
|
324
328
|
"description": "Align the thumb edge with full-width rail endpoints, or its center with inset rail endpoints."
|
|
325
329
|
},
|
|
330
|
+
"ticks": {
|
|
331
|
+
"type": "SliderTick[]",
|
|
332
|
+
"resolvedType": "SliderTick[]",
|
|
333
|
+
"default": "[]",
|
|
334
|
+
"required": false,
|
|
335
|
+
"mutable": false,
|
|
336
|
+
"description": "Explicit ticks are the selectable snap points. Empty ticks with step='any' allow smooth adjustment."
|
|
337
|
+
},
|
|
326
338
|
"value": {
|
|
327
339
|
"type": "SliderValue",
|
|
328
340
|
"resolvedType": "number | number[]",
|
|
@@ -564,8 +576,8 @@
|
|
|
564
576
|
"description": "Accessible label for the lower thumb in a range slider."
|
|
565
577
|
},
|
|
566
578
|
"step": {
|
|
567
|
-
"type": "number",
|
|
568
|
-
"resolvedType": "number",
|
|
579
|
+
"type": "number | 'any'",
|
|
580
|
+
"resolvedType": "\"any\" | number",
|
|
569
581
|
"attribute": "step",
|
|
570
582
|
"default": "1",
|
|
571
583
|
"required": false,
|
|
@@ -580,6 +592,14 @@
|
|
|
580
592
|
"mutable": false,
|
|
581
593
|
"description": "Align the thumb edge with full-width rail endpoints, or its center with inset rail endpoints."
|
|
582
594
|
},
|
|
595
|
+
"ticks": {
|
|
596
|
+
"type": "SliderTick[]",
|
|
597
|
+
"resolvedType": "SliderTick[]",
|
|
598
|
+
"default": "[]",
|
|
599
|
+
"required": false,
|
|
600
|
+
"mutable": false,
|
|
601
|
+
"description": "Explicit ticks are the selectable snap points. Empty ticks with step='any' allow smooth adjustment."
|
|
602
|
+
},
|
|
583
603
|
"value": {
|
|
584
604
|
"type": "SliderValue",
|
|
585
605
|
"resolvedType": "number | number[]",
|
|
@@ -672,11 +692,11 @@
|
|
|
672
692
|
"import": "import { DsSlider } from '@ds-mo/ui/angular/ds-slider';",
|
|
673
693
|
"example": "<ds-slider></ds-slider>"
|
|
674
694
|
},
|
|
675
|
-
"complexPropertyNote": "Assign these non-primitive values as JavaScript properties: formatOptions, valueTexts.",
|
|
695
|
+
"complexPropertyNote": "Assign these non-primitive values as JavaScript properties: formatOptions, ticks, valueTexts.",
|
|
676
696
|
"peerDependencies": {
|
|
677
697
|
"required": [
|
|
678
|
-
"@ds-mo/tokens ^6.5.
|
|
679
|
-
"@ds-mo/icons ^8.1.
|
|
698
|
+
"@ds-mo/tokens ^6.5.2",
|
|
699
|
+
"@ds-mo/icons ^8.1.1"
|
|
680
700
|
],
|
|
681
701
|
"frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
|
|
682
702
|
}
|
|
@@ -692,12 +712,12 @@
|
|
|
692
712
|
"files": [
|
|
693
713
|
{
|
|
694
714
|
"path": "src/wc/components/Slider/Slider.css",
|
|
695
|
-
"content": "@import '../../utils/control-inactive.css';\n@import '../../utils/field-stack.css';\n@import '../../utils/forced-colors.css';\n\n:host {\n --ds-slider-control-size: var(--dimension-size-400);\n --ds-slider-thumb-size: var(--dimension-size-200);\n --ds-slider-track-size: var(--dimension-size-100);\n --ds-slider-track-stroke: var(--dimension-stroke-width-012);\n --ds-slider-vertical-length: calc(var(--dimension-size-800) * 3);\n box-sizing: border-box;\n width: 100%;\n color: var(--color-foreground-primary);\n}\n\n:host(.slider--sm) {\n --ds-slider-control-size: var(--dimension-size-300);\n --ds-slider-thumb-size: var(--dimension-size-150);\n --ds-slider-track-size: var(--dimension-size-075);\n}\n\n:host(.slider--xs) {\n --ds-slider-control-size: var(--dimension-size-200);\n --ds-slider-thumb-size: var(--dimension-size-100);\n --ds-slider-track-size: var(--dimension-size-050);\n}\n\n:host(.slider--vertical) {\n width: fit-content;\n min-width: var(--dimension-form-width-xs);\n}\n\n.slider__label-row {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: var(--dimension-space-100);\n min-width: 0;\n}\n\n.slider__label {\n min-width: 0;\n}\n\n.slider__value {\n flex-shrink: 0;\n}\n\n.slider__control {\n position: relative;\n width: 100%;\n height: var(--ds-slider-control-size);\n border-radius: var(--dimension-radius-half);\n cursor: default;\n touch-action: none;\n user-select: none;\n}\n\n:host(.slider--vertical) .slider__control {\n align-self: center;\n width: var(--ds-slider-control-size);\n height: var(--ds-slider-vertical-length);\n}\n\n:host(.slider--readonly) .slider__control {\n cursor: default;\n}\n\n/* Inactive: `.ds-control-inactive` (50% opacity) on the host. */\n:host(.ds-control-inactive) .slider__control {\n cursor: not-allowed;\n}\n\n.slider__rail {\n position: absolute;\n top: 50%;\n right: 0;\n left: 0;\n height: var(--ds-slider-track-size);\n overflow: hidden;\n border-radius: var(--dimension-radius-025);\n background-color: transparent;\n box-shadow: inset 0 0 0 var(--ds-slider-track-stroke) var(--color-border-secondary);\n transform: translateY(-50%);\n pointer-events: none;\n}\n\n:host(.slider--thumb-center) .slider__rail {\n right: calc(var(--ds-slider-thumb-size) / 2);\n left: calc(var(--ds-slider-thumb-size) / 2);\n}\n\n.slider__indicator {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: calc(\n var(--ds-slider-thumb-size) / 2 + (var(--ds-slider-end-pct, 0) / 100) *\n (100% - var(--ds-slider-thumb-size))\n );\n border-radius: inherit;\n background-color: var(--color-background-bold-brand);\n}\n\n:host(.slider--range) .slider__indicator {\n left: calc(\n var(--ds-slider-thumb-size) / 2 + (var(--ds-slider-start-pct, 0) / 100) *\n (100% - var(--ds-slider-thumb-size))\n );\n width: calc(\n ((var(--ds-slider-end-pct, 0) - var(--ds-slider-start-pct, 0)) / 100) *\n (100% - var(--ds-slider-thumb-size))\n );\n}\n\n:host(.slider--thumb-center) .slider__indicator {\n left: calc(var(--ds-slider-start-pct, 0) * 1%);\n width: calc((var(--ds-slider-end-pct, 0) - var(--ds-slider-start-pct, 0)) * 1%);\n}\n\n.slider__thumb {\n position: absolute;\n top: 50%;\n left: calc((var(--ds-slider-thumb-pct, 0) / 100) * (100% - var(--ds-slider-thumb-size)));\n width: var(--ds-slider-thumb-size);\n height: var(--ds-slider-thumb-size);\n transform: translateY(-50%);\n z-index: 1;\n}\n\n.slider__thumb--active {\n z-index: 2;\n}\n\n.slider__input {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n margin: 0;\n padding: 0;\n border: 0;\n opacity: 0;\n appearance: none;\n pointer-events: none;\n z-index: 2;\n}\n\n.slider__thumb-visual {\n position: absolute;\n inset: 0;\n box-sizing: border-box;\n overflow: visible;\n border-radius: var(--dimension-radius-025);\n background-color: var(--color-background-primary);\n box-shadow: var(--effect-elevation-elevated-sm);\n pointer-events: none;\n transition:\n background-color var(--effect-motion-short-2),\n box-shadow var(--effect-motion-short-2);\n}\n\n.slider__thumb-wash {\n position: absolute;\n inset: 0;\n border-radius: inherit;\n background-color: transparent;\n transition: background-color var(--effect-motion-short-2);\n}\n\n@media (hover: hover) and (pointer: fine) {\n :host(:not(.slider--readonly):not(.ds-control-inactive))\n .slider__thumb:hover\n .slider__thumb-wash {\n background-color: var(--color-interaction-hover);\n }\n}\n\n:host([data-dragging]:not(.slider--readonly):not(.ds-control-inactive))\n .slider__thumb--active\n .slider__thumb-wash {\n background-color: var(--color-interaction-pressed);\n}\n\n.slider__input:focus-visible + .slider__thumb-visual,\n:host([data-review-focus]) .slider__thumb[data-index='0'] .slider__thumb-visual {\n outline: var(--dimension-stroke-width-025) solid var(--color-interaction-focus);\n outline-offset: var(--dimension-space-025);\n}\n\n:host(.slider--vertical) .slider__rail {\n top: 0;\n right: auto;\n bottom: 0;\n left: 50%;\n width: var(--ds-slider-track-size);\n height: auto;\n transform: translateX(-50%);\n}\n\n:host(.slider--vertical.slider--thumb-center) .slider__rail {\n top: calc(var(--ds-slider-thumb-size) / 2);\n bottom: calc(var(--ds-slider-thumb-size) / 2);\n}\n\n:host(.slider--vertical) .slider__indicator {\n top: auto;\n right: 0;\n bottom: 0;\n left: 0;\n width: auto;\n height: calc(\n var(--ds-slider-thumb-size) / 2 + (var(--ds-slider-end-pct, 0) / 100) *\n (100% - var(--ds-slider-thumb-size))\n );\n}\n\n:host(.slider--vertical.slider--range) .slider__indicator {\n bottom: calc(\n var(--ds-slider-thumb-size) / 2 + (var(--ds-slider-start-pct, 0) / 100) *\n (100% - var(--ds-slider-thumb-size))\n );\n height: calc(\n ((var(--ds-slider-end-pct, 0) - var(--ds-slider-start-pct, 0)) / 100) *\n (100% - var(--ds-slider-thumb-size))\n );\n}\n\n:host(.slider--vertical.slider--thumb-center) .slider__indicator {\n bottom: calc(var(--ds-slider-start-pct, 0) * 1%);\n height: calc((var(--ds-slider-end-pct, 0) - var(--ds-slider-start-pct, 0)) * 1%);\n}\n\n:host(.slider--vertical) .slider__thumb {\n top: auto;\n bottom: calc((var(--ds-slider-thumb-pct, 0) / 100) * (100% - var(--ds-slider-thumb-size)));\n left: 50%;\n transform: translateX(-50%);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .slider__thumb-visual,\n .slider__thumb-wash {\n transition: none;\n }\n}\n\n@media (forced-colors: active) {\n .slider__rail {\n border: var(--ds-slider-track-stroke) solid var(--ds-forced-color-content);\n box-shadow: none;\n }\n\n .slider__indicator {\n background-color: var(--ds-forced-color-selected);\n }\n\n .slider__thumb-visual {\n border: var(--dimension-stroke-width-012) solid var(--ds-forced-color-control-boundary);\n background-color: var(--ds-forced-color-surface);\n box-shadow: none;\n }\n\n .slider__input:focus-visible + .slider__thumb-visual,\n :host([data-review-focus]) .slider__thumb[data-index='0'] .slider__thumb-visual {\n outline-color: var(--ds-forced-color-selected);\n }\n}\n",
|
|
715
|
+
"content": "@import '../../utils/control-inactive.css';\n@import '../../utils/field-stack.css';\n@import '../../utils/forced-colors.css';\n\n:host {\n --ds-slider-control-size: var(--dimension-size-400);\n --ds-slider-thumb-size: var(--dimension-size-200);\n --ds-slider-track-size: var(--dimension-size-100);\n --ds-slider-track-stroke: var(--dimension-stroke-width-012);\n --ds-slider-vertical-length: calc(var(--dimension-size-800) * 3);\n box-sizing: border-box;\n width: 100%;\n color: var(--color-foreground-primary);\n}\n\n:host(.slider--sm) {\n --ds-slider-control-size: var(--dimension-size-300);\n --ds-slider-thumb-size: var(--dimension-size-150);\n --ds-slider-track-size: var(--dimension-size-075);\n}\n\n:host(.slider--xs) {\n --ds-slider-control-size: var(--dimension-size-200);\n --ds-slider-thumb-size: var(--dimension-size-100);\n --ds-slider-track-size: var(--dimension-size-050);\n}\n\n:host(.slider--vertical) {\n width: fit-content;\n min-width: var(--dimension-form-width-xs);\n}\n\n.slider__label-row {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: var(--dimension-space-100);\n min-width: 0;\n}\n\n.slider__label {\n min-width: 0;\n}\n\n.slider__value {\n flex-shrink: 0;\n}\n\n.slider__control {\n position: relative;\n width: 100%;\n height: var(--ds-slider-control-size);\n border-radius: var(--dimension-radius-half);\n cursor: default;\n touch-action: none;\n user-select: none;\n}\n\n:host(.slider--vertical) .slider__control {\n align-self: center;\n width: var(--ds-slider-control-size);\n height: var(--ds-slider-vertical-length);\n}\n\n:host(.slider--readonly) .slider__control {\n cursor: default;\n}\n\n/* Inactive: `.ds-control-inactive` (50% opacity) on the host. */\n:host(.ds-control-inactive) .slider__control {\n cursor: not-allowed;\n}\n\n.slider__rail {\n position: absolute;\n top: 50%;\n right: 0;\n left: 0;\n height: var(--ds-slider-track-size);\n overflow: hidden;\n border-radius: var(--dimension-radius-025);\n background-color: transparent;\n box-shadow: inset 0 0 0 var(--ds-slider-track-stroke) var(--color-border-secondary);\n transform: translateY(-50%);\n pointer-events: none;\n}\n\n:host(.slider--thumb-center) .slider__rail {\n right: calc(var(--ds-slider-thumb-size) / 2);\n left: calc(var(--ds-slider-thumb-size) / 2);\n}\n\n.slider__indicator {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: calc(\n var(--ds-slider-thumb-size) / 2 + (var(--ds-slider-end-pct, 0) / 100) *\n (100% - var(--ds-slider-thumb-size))\n );\n border-radius: inherit;\n background-color: var(--color-background-bold-brand);\n}\n\n:host(.slider--range) .slider__indicator {\n left: calc(\n var(--ds-slider-thumb-size) / 2 + (var(--ds-slider-start-pct, 0) / 100) *\n (100% - var(--ds-slider-thumb-size))\n );\n width: calc(\n ((var(--ds-slider-end-pct, 0) - var(--ds-slider-start-pct, 0)) / 100) *\n (100% - var(--ds-slider-thumb-size))\n );\n}\n\n:host(.slider--thumb-center) .slider__indicator {\n left: calc(var(--ds-slider-start-pct, 0) * 1%);\n width: calc((var(--ds-slider-end-pct, 0) - var(--ds-slider-start-pct, 0)) * 1%);\n}\n\n.slider__thumb {\n position: absolute;\n top: 50%;\n left: calc((var(--ds-slider-thumb-pct, 0) / 100) * (100% - var(--ds-slider-thumb-size)));\n width: var(--ds-slider-thumb-size);\n height: var(--ds-slider-thumb-size);\n transform: translateY(-50%);\n z-index: 1;\n}\n\n.slider__thumb--active {\n z-index: 2;\n}\n\n.slider__input {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n margin: 0;\n padding: 0;\n border: 0;\n opacity: 0;\n appearance: none;\n pointer-events: none;\n z-index: 2;\n}\n\n.slider__thumb-visual {\n position: absolute;\n inset: 0;\n box-sizing: border-box;\n overflow: visible;\n border-radius: var(--dimension-radius-025);\n background-color: var(--color-background-primary);\n box-shadow: var(--effect-elevation-elevated-sm);\n pointer-events: none;\n transition:\n background-color var(--effect-motion-short-2),\n box-shadow var(--effect-motion-short-2);\n}\n\n.slider__thumb-wash {\n position: absolute;\n inset: 0;\n border-radius: inherit;\n background-color: transparent;\n transition: background-color var(--effect-motion-short-2);\n}\n\n@media (hover: hover) and (pointer: fine) {\n :host(:not(.slider--readonly):not(.ds-control-inactive))\n .slider__thumb:hover\n .slider__thumb-wash {\n background-color: var(--color-interaction-hover);\n }\n}\n\n:host([data-dragging]:not(.slider--readonly):not(.ds-control-inactive))\n .slider__thumb--active\n .slider__thumb-wash {\n background-color: var(--color-interaction-pressed);\n}\n\n.slider__input:focus-visible + .slider__thumb-visual,\n:host([data-review-focus]) .slider__thumb[data-index='0'] .slider__thumb-visual {\n outline: var(--dimension-stroke-width-025) solid var(--color-interaction-focus);\n outline-offset: var(--dimension-space-025);\n}\n\n:host(.slider--vertical) .slider__rail {\n top: 0;\n right: auto;\n bottom: 0;\n left: 50%;\n width: var(--ds-slider-track-size);\n height: auto;\n transform: translateX(-50%);\n}\n\n:host(.slider--vertical.slider--thumb-center) .slider__rail {\n top: calc(var(--ds-slider-thumb-size) / 2);\n bottom: calc(var(--ds-slider-thumb-size) / 2);\n}\n\n:host(.slider--vertical) .slider__indicator {\n top: auto;\n right: 0;\n bottom: 0;\n left: 0;\n width: auto;\n height: calc(\n var(--ds-slider-thumb-size) / 2 + (var(--ds-slider-end-pct, 0) / 100) *\n (100% - var(--ds-slider-thumb-size))\n );\n}\n\n:host(.slider--vertical.slider--range) .slider__indicator {\n bottom: calc(\n var(--ds-slider-thumb-size) / 2 + (var(--ds-slider-start-pct, 0) / 100) *\n (100% - var(--ds-slider-thumb-size))\n );\n height: calc(\n ((var(--ds-slider-end-pct, 0) - var(--ds-slider-start-pct, 0)) / 100) *\n (100% - var(--ds-slider-thumb-size))\n );\n}\n\n:host(.slider--vertical.slider--thumb-center) .slider__indicator {\n bottom: calc(var(--ds-slider-start-pct, 0) * 1%);\n height: calc((var(--ds-slider-end-pct, 0) - var(--ds-slider-start-pct, 0)) * 1%);\n}\n\n:host(.slider--vertical) .slider__thumb {\n top: auto;\n bottom: calc((var(--ds-slider-thumb-pct, 0) / 100) * (100% - var(--ds-slider-thumb-size)));\n left: 50%;\n transform: translateX(-50%);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .slider__thumb-visual,\n .slider__thumb-wash {\n transition: none;\n }\n}\n\n@media (forced-colors: active) {\n .slider__rail {\n border: var(--ds-slider-track-stroke) solid var(--ds-forced-color-content);\n box-shadow: none;\n }\n\n .slider__indicator {\n background-color: var(--ds-forced-color-selected);\n }\n\n .slider__thumb-visual {\n border: var(--dimension-stroke-width-012) solid var(--ds-forced-color-control-boundary);\n background-color: var(--ds-forced-color-surface);\n box-shadow: none;\n }\n\n .slider__input:focus-visible + .slider__thumb-visual,\n :host([data-review-focus]) .slider__thumb[data-index='0'] .slider__thumb-visual {\n outline-color: var(--ds-forced-color-selected);\n }\n}\n\n.slider__tick {\n position: absolute;\n top: calc(\n 50% + var(--ds-slider-track-size) / 2 + var(--dimension-space-050) + var(--dimension-space-012)\n );\n left: calc(\n var(--ds-slider-thumb-size) / 2 + (var(--ds-slider-tick-pct) / 100) *\n (100% - var(--ds-slider-thumb-size))\n );\n transform: translateX(-50%);\n pointer-events: none;\n}\n.slider__tick-mark {\n display: block;\n width: var(--dimension-stroke-width-025);\n height: var(--dimension-stroke-width-025);\n border-radius: var(--dimension-radius-half);\n background: var(--color-foreground-tertiary);\n}\n.slider__tick-label {\n width: max-content;\n max-width: none;\n position: absolute;\n top: calc(100% + var(--dimension-space-050));\n left: 50%;\n transform: translateX(-50%);\n white-space: nowrap;\n}\n:host(:not(.slider--vertical)) .slider__control {\n container-type: inline-size;\n}\n:host(:not(.slider--vertical)) .slider__tick-label {\n /* Center on the tick, clamping only when the text reaches the control edges. */\n --ds-slider-label-anchor: calc(\n var(--ds-slider-thumb-size) / 2 + (var(--ds-slider-tick-pct) / 100) *\n (100cqw - var(--ds-slider-thumb-size))\n );\n transform: translateX(\n clamp(\n calc(-1 * var(--ds-slider-label-anchor)),\n -50%,\n calc(100cqw - var(--ds-slider-label-anchor) - 100%)\n )\n );\n}\n:host(.slider--tick-labels:not(.slider--vertical)) .slider__control {\n margin-bottom: var(--dimension-space-200);\n}\n:host(.slider--vertical) .slider__tick {\n top: auto;\n bottom: calc(\n var(--ds-slider-thumb-size) / 2 + (var(--ds-slider-tick-pct) / 100) *\n (100% - var(--ds-slider-thumb-size))\n );\n left: calc(50% + var(--ds-slider-track-size) / 2 + var(--dimension-space-050));\n transform: translateY(50%);\n}\n:host(.slider--vertical) .slider__tick-label {\n top: 50%;\n left: calc(100% + var(--dimension-space-050));\n transform: translateY(-50%);\n}\n",
|
|
696
716
|
"type": "registry:ui"
|
|
697
717
|
},
|
|
698
718
|
{
|
|
699
719
|
"path": "src/wc/components/Slider/Slider.tsx",
|
|
700
|
-
"content": "import {\n AttachInternals,\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 {\n restoreNumberArrayFormState,\n restoreStringFormState,\n setFormControlValue,\n setRepeatedFormControlValue,\n} from '../../utils';\n\nexport type SliderValue = number | number[];\nexport type SliderSize = 'md' | 'sm' | 'xs';\nexport type SliderOrientation = 'horizontal' | 'vertical';\nexport type SliderThumbAlignment = 'edge' | 'center';\n\nlet sliderId = 0;\nlet sliderExternalLabelId = 0;\n\n@Component({\n tag: 'ds-slider',\n styleUrl: 'Slider.css',\n scoped: true,\n formAssociated: true,\n})\nexport class Slider {\n @Element() el!: HTMLElement;\n @AttachInternals() internals!: ElementInternals;\n\n /** Current value. Assign a two-number array through the JavaScript property for a range slider. */\n @Prop({ mutable: true }) value: SliderValue = 0;\n @Prop() min: number = 0;\n @Prop() max: number = 100;\n @Prop() step: number = 1;\n /** Minimum number of steps kept between two range thumbs. */\n @Prop() minStepsBetweenValues: number = 0;\n /** Visible field label. Supply aria-label when the label is intentionally hidden. */\n @Prop() label: string | undefined;\n /** Show the formatted current value beside the visible label. */\n @Prop() showValue: boolean = true;\n @Prop() size: SliderSize = 'md';\n @Prop() orientation: SliderOrientation = 'horizontal';\n /** Align the thumb edge with full-width rail endpoints, or its center with inset rail endpoints. */\n @Prop() thumbAlignment: SliderThumbAlignment = 'edge';\n @Prop({ reflect: true }) name: string | undefined;\n @Prop({ reflect: true }) form: string | undefined;\n @Prop({ reflect: true }) disabled: boolean = false;\n /** Keep the value focusable and submittable while preventing changes. */\n @Prop({ reflect: true }) readOnly: boolean = false;\n @Prop() isInactive: boolean = false;\n /** Direct accessible name for a single-thumb slider without a visible label. */\n @Prop({ attribute: 'aria-label' }) ariaLabel: string | null = null;\n /** Id references for a visible single-thumb slider label. */\n @Prop({ attribute: 'aria-labelledby' }) ariaLabelledby: string | undefined;\n /** Id references for supporting guidance or error text. */\n @Prop({ attribute: 'aria-describedby' }) ariaDescribedby: string | undefined;\n /** Accessible label for the lower thumb in a range slider. */\n @Prop() startLabel: string = 'Minimum value';\n /** Accessible label for the upper thumb in a range slider. */\n @Prop() endLabel: string = 'Maximum value';\n /** Human-readable value text for a single slider or both range thumbs. */\n @Prop() valueText: string | undefined;\n /** Per-thumb human-readable value text for a range slider. Assign through the JavaScript property. */\n @Prop() valueTexts: string[] = [];\n /** Locale used by Intl.NumberFormat for the visible value. */\n @Prop() locale: string | undefined;\n /** Intl.NumberFormat options. Assign objects through the JavaScript property. */\n @Prop() formatOptions: Intl.NumberFormatOptions | undefined;\n @Prop() valuePrefix: string = '';\n @Prop() valueSuffix: string = '';\n @Prop() rangeSeparator: string = '–';\n /** Id applied to the first native range input. */\n @Prop() inputId: string | undefined;\n\n /** Emitted continuously while the value changes. */\n @Event() dsChange!: EventEmitter<SliderValue>;\n /** Emitted when a pointer or keyboard value change is committed. */\n @Event() dsCommit!: EventEmitter<SliderValue>;\n\n @State() private formDisabled = false;\n @State() private dragging = false;\n @State() private focused = false;\n @State() private touched = false;\n @State() private activeThumbIndex = 0;\n @State() private externalLabelledby: string | undefined;\n\n private readonly generatedId = `ds-slider-${++sliderId}`;\n private readonly labelId = `${this.generatedId}-label`;\n private initialValue: SliderValue = 0;\n private lastCommittedValue: SliderValue = 0;\n private pointerId: number | null = null;\n private pointerStartValue: SliderValue = 0;\n private controlEl: HTMLDivElement | null = null;\n\n componentWillLoad() {\n this.initialValue = this.cloneValue(this.publicValue);\n this.lastCommittedValue = this.cloneValue(this.publicValue);\n this.syncFormValue();\n }\n\n componentDidLoad() {\n this.syncNativeLabels();\n }\n\n @Watch('value')\n @Watch('min')\n @Watch('max')\n @Watch('step')\n @Watch('minStepsBetweenValues')\n @Watch('name')\n @Watch('disabled')\n @Watch('isInactive')\n syncFormValue() {\n const values = this.resolvedValues;\n if (this.isRange) {\n setRepeatedFormControlValue(this.internals, this.name, values, {\n inactive: this.isDisabled,\n });\n } else {\n const value = String(values[0]);\n setFormControlValue(this.internals, this.name ? value : null, {\n inactive: this.isDisabled,\n state: value,\n });\n }\n }\n\n formDisabledCallback(disabled: boolean) {\n this.formDisabled = disabled;\n this.syncFormValue();\n }\n\n formResetCallback() {\n this.value = this.cloneValue(this.initialValue);\n this.lastCommittedValue = this.cloneValue(this.initialValue);\n this.dragging = false;\n this.focused = false;\n this.touched = false;\n }\n\n formStateRestoreCallback(state: string | File | FormData | null) {\n if (this.isRange) {\n const restored = restoreNumberArrayFormState(state, 2);\n this.value = restored.length ? restored : this.cloneValue(this.initialValue);\n } else {\n const restored = Number(restoreStringFormState(state, 'NaN'));\n if (Number.isFinite(restored)) this.value = restored;\n }\n this.lastCommittedValue = this.cloneValue(this.publicValue);\n }\n\n @Method()\n async setFocus(index: number = 0) {\n const inputs = this.el.querySelectorAll<HTMLInputElement>('.slider__input');\n inputs[Math.max(0, Math.min(index, inputs.length - 1))]?.focus();\n }\n\n private get isDisabled(): boolean {\n return this.disabled || this.isInactive || this.formDisabled;\n }\n\n private get isRange(): boolean {\n return Array.isArray(this.value);\n }\n\n private get safeStep(): number {\n return Number.isFinite(this.step) && this.step > 0 ? this.step : 1;\n }\n\n private get safeMin(): number {\n return Number.isFinite(this.min) ? this.min : 0;\n }\n\n private get safeMax(): number {\n const minimum = this.safeMin;\n return Number.isFinite(this.max) && this.max > minimum ? this.max : minimum + this.safeStep;\n }\n\n private get minimumGap(): number {\n const steps = Number.isFinite(this.minStepsBetweenValues)\n ? Math.max(0, Math.floor(this.minStepsBetweenValues))\n : 0;\n return steps * this.safeStep;\n }\n\n private get resolvedValues(): number[] {\n const minimum = this.safeMin;\n const maximum = this.safeMax;\n if (!this.isRange) return [this.snap(Number(this.value))];\n\n const raw = this.value as number[];\n let lower = this.snap(Number(raw[0] ?? minimum));\n let upper = this.snap(Number(raw[1] ?? maximum));\n if (lower > upper) [lower, upper] = [upper, lower];\n\n const gap = Math.min(this.minimumGap, maximum - minimum);\n if (upper - lower < gap) {\n upper = Math.min(maximum, this.snap(lower + gap));\n lower = Math.max(minimum, this.snap(upper - gap));\n }\n return [lower, upper];\n }\n\n private get publicValue(): SliderValue {\n const values = this.resolvedValues;\n return this.isRange ? [...values] : values[0];\n }\n\n private cloneValue(value: SliderValue): SliderValue {\n return Array.isArray(value) ? [...value] : value;\n }\n\n private valuesEqual(a: SliderValue, b: SliderValue): boolean {\n if (Array.isArray(a) && Array.isArray(b)) {\n return a.length === b.length && a.every((value, index) => value === b[index]);\n }\n return !Array.isArray(a) && !Array.isArray(b) && a === b;\n }\n\n private decimalPlaces(value: number): number {\n const text = String(value).toLowerCase();\n if (text.includes('e-')) return Number(text.split('e-')[1]) || 0;\n return text.includes('.') ? text.split('.')[1].length : 0;\n }\n\n private snap(value: number): number {\n const minimum = this.safeMin;\n const maximum = this.safeMax;\n const candidate = Number.isFinite(value) ? value : minimum;\n const stepped = minimum + Math.round((candidate - minimum) / this.safeStep) * this.safeStep;\n const precision = Math.min(\n 10,\n Math.max(\n this.decimalPlaces(minimum),\n this.decimalPlaces(maximum),\n this.decimalPlaces(this.safeStep)\n )\n );\n return Number(Math.min(maximum, Math.max(minimum, stepped)).toFixed(precision));\n }\n\n private percent(value: number): number {\n return ((value - this.safeMin) / (this.safeMax - this.safeMin)) * 100;\n }\n\n private allowedMin(index: number, values = this.resolvedValues): number {\n return this.isRange && index === 1\n ? Math.min(this.safeMax, values[0] + this.minimumGap)\n : this.safeMin;\n }\n\n private allowedMax(index: number, values = this.resolvedValues): number {\n return this.isRange && index === 0\n ? Math.max(this.safeMin, values[1] - this.minimumGap)\n : this.safeMax;\n }\n\n private setValueAt(index: number, next: number): boolean {\n const previous = this.publicValue;\n const values = this.resolvedValues;\n const constrained = Math.min(\n this.allowedMax(index, values),\n Math.max(this.allowedMin(index, values), this.snap(next))\n );\n values[index] = constrained;\n const nextValue: SliderValue = this.isRange ? [...values] : values[0];\n if (this.valuesEqual(previous, nextValue)) return false;\n\n this.value = nextValue;\n this.dsChange.emit(this.cloneValue(nextValue));\n return true;\n }\n\n private commitIfChanged() {\n const current = this.publicValue;\n if (this.valuesEqual(current, this.lastCommittedValue)) return;\n this.lastCommittedValue = this.cloneValue(current);\n this.dsCommit.emit(this.cloneValue(current));\n }\n\n private syncNativeLabels() {\n if (this.label || this.ariaLabel || this.ariaLabelledby || this.isRange) return;\n const ids = (Array.from(this.internals.labels) as HTMLLabelElement[]).map(label => {\n if (!label.id) label.id = `ds-slider-label-${++sliderExternalLabelId}`;\n return label.id;\n });\n if (ids.length) this.externalLabelledby = ids.join(' ');\n }\n\n private formattedValue(value: number, index: number): string {\n const authored = this.valueTexts[index] ?? this.valueText;\n if (authored) return authored;\n let number: string;\n try {\n number = new Intl.NumberFormat(this.locale, this.formatOptions).format(value);\n } catch {\n number = String(value);\n }\n return `${this.valuePrefix}${number}${this.valueSuffix}`;\n }\n\n private ariaValueText(value: number, index: number): string | undefined {\n if (\n this.valueTexts[index] ||\n this.valueText ||\n this.valuePrefix ||\n this.valueSuffix ||\n this.formatOptions\n ) {\n return this.formattedValue(value, index);\n }\n return undefined;\n }\n\n private handleNativeInput = (event: Event, index: number) => {\n const input = event.target as HTMLInputElement;\n this.activeThumbIndex = index;\n if (this.readOnly || this.isDisabled) {\n input.value = String(this.resolvedValues[index]);\n return;\n }\n this.setValueAt(index, Number(input.value));\n };\n\n private handleNativeChange = () => {\n if (!this.readOnly && !this.isDisabled) this.commitIfChanged();\n };\n\n private handleKeyDown = (event: KeyboardEvent) => {\n if (!this.readOnly) return;\n if (\n [\n 'ArrowLeft',\n 'ArrowRight',\n 'ArrowUp',\n 'ArrowDown',\n 'Home',\n 'End',\n 'PageUp',\n 'PageDown',\n ].includes(event.key)\n ) {\n event.preventDefault();\n }\n };\n\n private handleFocus = (index: number) => {\n this.activeThumbIndex = index;\n this.focused = true;\n };\n\n private handleBlur = (event: FocusEvent) => {\n const next = event.relatedTarget;\n if (next instanceof Node && this.el.contains(next)) return;\n this.focused = false;\n this.touched = true;\n };\n\n private handleHostClick = (event: MouseEvent) => {\n if (event.target !== this.el || this.isDisabled) return;\n const inputs = this.el.querySelectorAll<HTMLInputElement>('.slider__input');\n inputs[Math.min(this.activeThumbIndex, inputs.length - 1)]?.focus();\n };\n\n private pointerPercent(event: PointerEvent): number {\n const control = this.controlEl;\n if (!control) return 0;\n const rect = control.getBoundingClientRect();\n const thumb = this.el.querySelector<HTMLElement>('.slider__thumb');\n const thumbSize = thumb\n ? this.orientation === 'horizontal'\n ? thumb.offsetWidth\n : thumb.offsetHeight\n : 0;\n // Both alignment modes keep the complete thumb inside the control. Edge\n // alignment lets the rail span the control while center alignment insets\n // the rail to the same thumb-center travel.\n const inset = thumbSize / 2;\n\n if (this.orientation === 'vertical') {\n const travel = Math.max(1, rect.height - inset * 2);\n return Math.min(1, Math.max(0, (rect.bottom - inset - event.clientY) / travel));\n }\n\n const travel = Math.max(1, rect.width - inset * 2);\n const percent = (event.clientX - rect.left - inset) / travel;\n return Math.min(1, Math.max(0, percent));\n }\n\n private valueFromPointer(event: PointerEvent): number {\n return this.snap(this.safeMin + this.pointerPercent(event) * (this.safeMax - this.safeMin));\n }\n\n private closestThumbIndex(value: number, target: EventTarget | null): number {\n const targetElement =\n target instanceof HTMLElement ? target.closest<HTMLElement>('.slider__thumb') : null;\n if (targetElement?.dataset['index']) return Number(targetElement.dataset['index']);\n if (!this.isRange) return 0;\n\n const values = this.resolvedValues;\n const lowerDistance = Math.abs(value - values[0]);\n const upperDistance = Math.abs(value - values[1]);\n if (lowerDistance === upperDistance) return value >= values[0] ? 1 : 0;\n return lowerDistance < upperDistance ? 0 : 1;\n }\n\n private handlePointerDown = (event: PointerEvent) => {\n if (event.button !== 0 || this.isDisabled || this.readOnly) return;\n event.preventDefault();\n const value = this.valueFromPointer(event);\n const index = this.closestThumbIndex(value, event.target);\n this.activeThumbIndex = index;\n this.pointerId = event.pointerId;\n this.pointerStartValue = this.cloneValue(this.publicValue);\n this.dragging = true;\n this.setValueAt(index, value);\n this.controlEl?.setPointerCapture(event.pointerId);\n requestAnimationFrame(() => {\n const input = this.el.querySelectorAll<HTMLInputElement>('.slider__input')[index];\n input?.focus({ preventScroll: true });\n });\n };\n\n private handlePointerMove = (event: PointerEvent) => {\n if (this.pointerId !== event.pointerId || !this.dragging) return;\n event.preventDefault();\n this.setValueAt(this.activeThumbIndex, this.valueFromPointer(event));\n };\n\n private endPointerInteraction(event: PointerEvent, canceled: boolean) {\n if (this.pointerId !== event.pointerId) return;\n if (this.controlEl?.hasPointerCapture(event.pointerId))\n this.controlEl.releasePointerCapture(event.pointerId);\n this.pointerId = null;\n this.dragging = false;\n this.touched = true;\n if (!canceled && !this.valuesEqual(this.pointerStartValue, this.publicValue))\n this.commitIfChanged();\n }\n\n private renderThumb(value: number, index: number) {\n const inputId =\n index === 0\n ? (this.inputId ?? `${this.generatedId}-input`)\n : `${this.inputId ?? `${this.generatedId}-input`}-end`;\n const rangeLabel = index === 0 ? this.startLabel : this.endLabel;\n const labelledby = this.isRange\n ? undefined\n : (this.ariaLabelledby ?? (this.label ? this.labelId : this.externalLabelledby));\n const directLabel = this.isRange ? rangeLabel : labelledby ? undefined : this.ariaLabel;\n\n return (\n <div\n class={{\n slider__thumb: true,\n 'slider__thumb--active': index === this.activeThumbIndex,\n }}\n data-index={String(index)}\n style={{ '--ds-slider-thumb-pct': String(this.percent(value)) } as Record<string, string>}\n >\n <input\n class=\"slider__input\"\n type=\"range\"\n id={inputId}\n min={this.allowedMin(index)}\n max={this.allowedMax(index)}\n step={this.safeStep}\n value={value}\n disabled={this.isDisabled}\n aria-label={directLabel}\n aria-labelledby={labelledby}\n aria-describedby={this.ariaDescribedby}\n aria-valuetext={this.ariaValueText(value, index)}\n aria-orientation={this.orientation === 'vertical' ? 'vertical' : undefined}\n aria-readonly={this.readOnly ? 'true' : undefined}\n onInput={(event: Event) => this.handleNativeInput(event, index)}\n onChange={this.handleNativeChange}\n onKeyDown={this.handleKeyDown}\n onFocus={() => this.handleFocus(index)}\n onBlur={this.handleBlur}\n />\n <span class=\"slider__thumb-visual\" aria-hidden=\"true\">\n <span class=\"slider__thumb-wash\" />\n </span>\n </div>\n );\n }\n\n render() {\n const values = this.resolvedValues;\n const first = values[0];\n const last = values[values.length - 1];\n const firstInputId = this.inputId ?? `${this.generatedId}-input`;\n const dirty = !this.valuesEqual(this.publicValue, this.initialValue);\n const valueDisplay = values\n .map((value, index) => this.formattedValue(value, index))\n .join(` ${this.rangeSeparator} `);\n\n return (\n <Host\n aria-disabled={this.isDisabled ? 'true' : undefined}\n class={{\n slider: true,\n 'ds-field-stack': true,\n [`slider--${this.size}`]: true,\n [`slider--${this.orientation}`]: true,\n [`slider--thumb-${this.thumbAlignment}`]: true,\n 'slider--range': this.isRange,\n 'slider--readonly': this.readOnly,\n 'ds-control-inactive': this.isDisabled,\n }}\n data-orientation={this.orientation}\n data-disabled={this.isDisabled ? '' : undefined}\n data-readonly={this.readOnly ? '' : undefined}\n data-dragging={this.dragging ? '' : undefined}\n data-focused={this.focused ? '' : undefined}\n data-filled=\"\"\n data-dirty={dirty ? '' : undefined}\n data-touched={this.touched ? '' : undefined}\n data-valid={!this.isDisabled ? '' : undefined}\n onClick={this.handleHostClick}\n >\n {(this.label || this.showValue) && (\n <div class=\"slider__label-row\">\n {this.label && (\n <ds-text\n class=\"slider__label\"\n as=\"label\"\n variant=\"text-body-small\"\n color=\"primary\"\n emphasis\n for={firstInputId}\n textId={this.labelId}\n >\n {this.label}\n </ds-text>\n )}\n {this.showValue && (\n <ds-text\n class=\"slider__value\"\n as=\"span\"\n variant=\"text-body-small\"\n color=\"primary\"\n fontFeature=\"tabular-nums\"\n >\n {valueDisplay}\n </ds-text>\n )}\n </div>\n )}\n <div\n class=\"slider__control\"\n ref={element => {\n this.controlEl = element ?? null;\n }}\n style={\n {\n '--ds-slider-start-pct': String(this.isRange ? this.percent(first) : 0),\n '--ds-slider-end-pct': String(this.percent(last)),\n } as Record<string, string>\n }\n onPointerDown={this.handlePointerDown}\n onPointerMove={this.handlePointerMove}\n onPointerUp={(event: PointerEvent) => this.endPointerInteraction(event, false)}\n onPointerCancel={(event: PointerEvent) => this.endPointerInteraction(event, true)}\n >\n <div class=\"slider__rail\" aria-hidden=\"true\">\n <div class=\"slider__indicator\" />\n </div>\n {values.map((value, index) => this.renderThumb(value, index))}\n </div>\n </Host>\n );\n }\n}\n",
|
|
720
|
+
"content": "import {\n AttachInternals,\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 {\n restoreNumberArrayFormState,\n restoreStringFormState,\n setFormControlValue,\n setRepeatedFormControlValue,\n} from '../../utils';\n\nexport interface SliderTick {\n value: number;\n label?: string;\n}\n\nexport type SliderValue = number | number[];\nexport type SliderSize = 'md' | 'sm' | 'xs';\nexport type SliderOrientation = 'horizontal' | 'vertical';\nexport type SliderThumbAlignment = 'edge' | 'center';\n\nlet sliderId = 0;\nlet sliderExternalLabelId = 0;\n\n@Component({\n tag: 'ds-slider',\n styleUrl: 'Slider.css',\n scoped: true,\n formAssociated: true,\n})\nexport class Slider {\n @Element() el!: HTMLElement;\n @AttachInternals() internals!: ElementInternals;\n\n /** Current value. Assign a two-number array through the JavaScript property for a range slider. */\n @Prop({ mutable: true }) value: SliderValue = 0;\n @Prop() min: number = 0;\n @Prop() max: number = 100;\n @Prop() step: number | 'any' = 1;\n /** Explicit ticks are the selectable snap points. Empty ticks with step='any' allow smooth adjustment. */\n @Prop() ticks: SliderTick[] = [];\n /** Minimum number of steps kept between two range thumbs. */\n @Prop() minStepsBetweenValues: number = 0;\n /** Visible field label. Supply aria-label when the label is intentionally hidden. */\n @Prop() label: string | undefined;\n /** Show the formatted current value beside the visible label. */\n @Prop() showValue: boolean = true;\n @Prop() size: SliderSize = 'md';\n @Prop() orientation: SliderOrientation = 'horizontal';\n /** Align the thumb edge with full-width rail endpoints, or its center with inset rail endpoints. */\n @Prop() thumbAlignment: SliderThumbAlignment = 'edge';\n @Prop({ reflect: true }) name: string | undefined;\n @Prop({ reflect: true }) form: string | undefined;\n @Prop({ reflect: true }) disabled: boolean = false;\n /** Keep the value focusable and submittable while preventing changes. */\n @Prop({ reflect: true }) readOnly: boolean = false;\n @Prop() isInactive: boolean = false;\n /** Direct accessible name for a single-thumb slider without a visible label. */\n @Prop({ attribute: 'aria-label' }) ariaLabel: string | null = null;\n /** Id references for a visible single-thumb slider label. */\n @Prop({ attribute: 'aria-labelledby' }) ariaLabelledby: string | undefined;\n /** Id references for supporting guidance or error text. */\n @Prop({ attribute: 'aria-describedby' }) ariaDescribedby: string | undefined;\n /** Accessible label for the lower thumb in a range slider. */\n @Prop() startLabel: string = 'Minimum value';\n /** Accessible label for the upper thumb in a range slider. */\n @Prop() endLabel: string = 'Maximum value';\n /** Human-readable value text for a single slider or both range thumbs. */\n @Prop() valueText: string | undefined;\n /** Per-thumb human-readable value text for a range slider. Assign through the JavaScript property. */\n @Prop() valueTexts: string[] = [];\n /** Locale used by Intl.NumberFormat for the visible value. */\n @Prop() locale: string | undefined;\n /** Intl.NumberFormat options. Assign objects through the JavaScript property. */\n @Prop() formatOptions: Intl.NumberFormatOptions | undefined;\n @Prop() valuePrefix: string = '';\n @Prop() valueSuffix: string = '';\n @Prop() rangeSeparator: string = '–';\n /** Id applied to the first native range input. */\n @Prop() inputId: string | undefined;\n\n /** Emitted continuously while the value changes. */\n @Event() dsChange!: EventEmitter<SliderValue>;\n /** Emitted when a pointer or keyboard value change is committed. */\n @Event() dsCommit!: EventEmitter<SliderValue>;\n\n @State() private formDisabled = false;\n @State() private dragging = false;\n @State() private focused = false;\n @State() private touched = false;\n @State() private activeThumbIndex = 0;\n @State() private externalLabelledby: string | undefined;\n\n private readonly generatedId = `ds-slider-${++sliderId}`;\n private readonly labelId = `${this.generatedId}-label`;\n private initialValue: SliderValue = 0;\n private lastCommittedValue: SliderValue = 0;\n private pointerId: number | null = null;\n private pointerStartValue: SliderValue = 0;\n private controlEl: HTMLDivElement | null = null;\n\n componentWillLoad() {\n this.initialValue = this.cloneValue(this.publicValue);\n this.lastCommittedValue = this.cloneValue(this.publicValue);\n this.syncFormValue();\n }\n\n componentDidLoad() {\n this.syncNativeLabels();\n }\n\n @Watch('value')\n @Watch('min')\n @Watch('max')\n @Watch('step')\n @Watch('ticks')\n @Watch('minStepsBetweenValues')\n @Watch('name')\n @Watch('disabled')\n @Watch('isInactive')\n syncFormValue() {\n const values = this.resolvedValues;\n if (this.isRange) {\n setRepeatedFormControlValue(this.internals, this.name, values, {\n inactive: this.isDisabled,\n });\n } else {\n const value = String(values[0]);\n setFormControlValue(this.internals, this.name ? value : null, {\n inactive: this.isDisabled,\n state: value,\n });\n }\n }\n\n formDisabledCallback(disabled: boolean) {\n this.formDisabled = disabled;\n this.syncFormValue();\n }\n\n formResetCallback() {\n this.value = this.cloneValue(this.initialValue);\n this.lastCommittedValue = this.cloneValue(this.initialValue);\n this.dragging = false;\n this.focused = false;\n this.touched = false;\n }\n\n formStateRestoreCallback(state: string | File | FormData | null) {\n if (this.isRange) {\n const restored = restoreNumberArrayFormState(state, 2);\n this.value = restored.length ? restored : this.cloneValue(this.initialValue);\n } else {\n const restored = Number(restoreStringFormState(state, 'NaN'));\n if (Number.isFinite(restored)) this.value = restored;\n }\n this.lastCommittedValue = this.cloneValue(this.publicValue);\n }\n\n @Method()\n async setFocus(index: number = 0) {\n const inputs = this.el.querySelectorAll<HTMLInputElement>('.slider__input');\n inputs[Math.max(0, Math.min(index, inputs.length - 1))]?.focus();\n }\n\n private get isDisabled(): boolean {\n return this.disabled || this.isInactive || this.formDisabled;\n }\n\n private get isRange(): boolean {\n return Array.isArray(this.value);\n }\n\n private get safeStep(): number {\n const step = Number(this.step);\n return Number.isFinite(step) && step > 0 ? step : 1;\n }\n\n private get resolvedTicks(): SliderTick[] {\n const unique = new Map<number, SliderTick>();\n for (const tick of this.ticks) {\n if (Number.isFinite(tick.value) && tick.value >= this.safeMin && tick.value <= this.safeMax)\n unique.set(tick.value, tick);\n }\n return [...unique.values()].sort((a, b) => a.value - b.value);\n }\n\n private get safeMin(): number {\n return Number.isFinite(this.min) ? this.min : 0;\n }\n\n private get safeMax(): number {\n const minimum = this.safeMin;\n return Number.isFinite(this.max) && this.max > minimum ? this.max : minimum + this.safeStep;\n }\n\n private get minimumGap(): number {\n const steps = Number.isFinite(this.minStepsBetweenValues)\n ? Math.max(0, Math.floor(this.minStepsBetweenValues))\n : 0;\n const ticks = this.resolvedTicks;\n const span = ticks.length\n ? ticks[ticks.length - 1].value - ticks[0].value\n : this.safeMax - this.safeMin;\n return Math.min(span, steps * this.safeStep);\n }\n\n private get resolvedValues(): number[] {\n const minimum = this.safeMin;\n const maximum = this.safeMax;\n if (!this.isRange) return [this.snap(Number(this.value))];\n\n const raw = this.value as number[];\n let lower = this.snap(Number(raw[0] ?? minimum));\n let upper = this.snap(Number(raw[1] ?? maximum));\n if (lower > upper) [lower, upper] = [upper, lower];\n\n const gap = Math.min(this.minimumGap, maximum - minimum);\n if (upper - lower < gap) {\n upper = Math.min(maximum, this.snap(lower + gap));\n lower = Math.max(minimum, this.snap(upper - gap));\n const ticks = this.resolvedTicks;\n if (ticks.length && upper - lower < gap) {\n upper =\n ticks.find(tick => tick.value >= lower + gap)?.value ?? ticks[ticks.length - 1].value;\n lower =\n [...ticks].reverse().find(tick => tick.value <= upper - gap)?.value ?? ticks[0].value;\n }\n }\n return [lower, upper];\n }\n\n private get publicValue(): SliderValue {\n const values = this.resolvedValues;\n return this.isRange ? [...values] : values[0];\n }\n\n private cloneValue(value: SliderValue): SliderValue {\n return Array.isArray(value) ? [...value] : value;\n }\n\n private valuesEqual(a: SliderValue, b: SliderValue): boolean {\n if (Array.isArray(a) && Array.isArray(b)) {\n return a.length === b.length && a.every((value, index) => value === b[index]);\n }\n return !Array.isArray(a) && !Array.isArray(b) && a === b;\n }\n\n private decimalPlaces(value: number): number {\n const text = String(value).toLowerCase();\n if (text.includes('e-')) return Number(text.split('e-')[1]) || 0;\n return text.includes('.') ? text.split('.')[1].length : 0;\n }\n\n private snap(value: number, minimum = this.safeMin, maximum = this.safeMax): number {\n const ticks = this.resolvedTicks.filter(tick => tick.value >= minimum && tick.value <= maximum);\n if (ticks.length)\n return ticks.reduce((nearest, tick) =>\n Math.abs(tick.value - value) < Math.abs(nearest.value - value) ? tick : nearest\n ).value;\n if (this.step === 'any')\n return Math.min(maximum, Math.max(minimum, Number.isFinite(value) ? value : minimum));\n const candidate = Number.isFinite(value) ? value : minimum;\n const stepped = minimum + Math.round((candidate - minimum) / this.safeStep) * this.safeStep;\n const precision = Math.min(\n 10,\n Math.max(\n this.decimalPlaces(minimum),\n this.decimalPlaces(maximum),\n this.decimalPlaces(this.safeStep)\n )\n );\n return Number(Math.min(maximum, Math.max(minimum, stepped)).toFixed(precision));\n }\n\n private percent(value: number): number {\n return ((value - this.safeMin) / (this.safeMax - this.safeMin)) * 100;\n }\n\n private allowedMin(index: number, values = this.resolvedValues): number {\n return this.isRange && index === 1\n ? Math.min(this.safeMax, values[0] + this.minimumGap)\n : this.safeMin;\n }\n\n private allowedMax(index: number, values = this.resolvedValues): number {\n return this.isRange && index === 0\n ? Math.max(this.safeMin, values[1] - this.minimumGap)\n : this.safeMax;\n }\n\n private setValueAt(index: number, next: number): boolean {\n const previous = this.publicValue;\n const values = this.resolvedValues;\n const constrained = Math.min(\n this.allowedMax(index, values),\n Math.max(\n this.allowedMin(index, values),\n this.snap(next, this.allowedMin(index, values), this.allowedMax(index, values))\n )\n );\n values[index] = constrained;\n const nextValue: SliderValue = this.isRange ? [...values] : values[0];\n if (this.valuesEqual(previous, nextValue)) return false;\n\n this.value = nextValue;\n this.dsChange.emit(this.cloneValue(nextValue));\n return true;\n }\n\n private commitIfChanged() {\n const current = this.publicValue;\n if (this.valuesEqual(current, this.lastCommittedValue)) return;\n this.lastCommittedValue = this.cloneValue(current);\n this.dsCommit.emit(this.cloneValue(current));\n }\n\n private syncNativeLabels() {\n if (this.label || this.ariaLabel || this.ariaLabelledby || this.isRange) return;\n const ids = (Array.from(this.internals.labels) as HTMLLabelElement[]).map(label => {\n if (!label.id) label.id = `ds-slider-label-${++sliderExternalLabelId}`;\n return label.id;\n });\n if (ids.length) this.externalLabelledby = ids.join(' ');\n }\n\n private formattedValue(value: number, index: number): string {\n const authored =\n this.valueTexts[index] ??\n this.valueText ??\n this.resolvedTicks.find(tick => tick.value === value)?.label;\n if (authored) return authored;\n let number: string;\n try {\n number = new Intl.NumberFormat(this.locale, this.formatOptions).format(value);\n } catch {\n number = String(value);\n }\n return `${this.valuePrefix}${number}${this.valueSuffix}`;\n }\n\n private ariaValueText(value: number, index: number): string | undefined {\n if (\n this.resolvedTicks.some(tick => tick.value === value && tick.label) ||\n this.valueTexts[index] ||\n this.valueText ||\n this.valuePrefix ||\n this.valueSuffix ||\n this.formatOptions\n ) {\n return this.formattedValue(value, index);\n }\n return undefined;\n }\n\n private handleNativeInput = (event: Event, index: number) => {\n const input = event.target as HTMLInputElement;\n this.activeThumbIndex = index;\n if (this.readOnly || this.isDisabled) {\n input.value = String(this.resolvedValues[index]);\n return;\n }\n this.setValueAt(index, Number(input.value));\n };\n\n private handleNativeChange = () => {\n if (!this.readOnly && !this.isDisabled) this.commitIfChanged();\n };\n\n private handleKeyDown = (event: KeyboardEvent, index: number) => {\n const keys = [\n 'ArrowLeft',\n 'ArrowRight',\n 'ArrowUp',\n 'ArrowDown',\n 'Home',\n 'End',\n 'PageUp',\n 'PageDown',\n ];\n if (!this.readOnly && this.resolvedTicks.length && keys.includes(event.key)) {\n event.preventDefault();\n if (this.isDisabled) return;\n const ticks = this.resolvedTicks.filter(\n tick => tick.value >= this.allowedMin(index) && tick.value <= this.allowedMax(index)\n );\n const current = this.resolvedValues[index];\n const forward = ['ArrowRight', 'ArrowUp', 'PageUp'].includes(event.key);\n const next =\n event.key === 'Home'\n ? ticks[0]\n : event.key === 'End'\n ? ticks[ticks.length - 1]\n : forward\n ? ticks.find(tick => tick.value > current)\n : [...ticks].reverse().find(tick => tick.value < current);\n if (next && this.setValueAt(index, next.value)) this.commitIfChanged();\n return;\n }\n if (!this.readOnly) return;\n if (\n [\n 'ArrowLeft',\n 'ArrowRight',\n 'ArrowUp',\n 'ArrowDown',\n 'Home',\n 'End',\n 'PageUp',\n 'PageDown',\n ].includes(event.key)\n ) {\n event.preventDefault();\n }\n };\n\n private handleFocus = (index: number) => {\n this.activeThumbIndex = index;\n this.focused = true;\n };\n\n private handleBlur = (event: FocusEvent) => {\n const next = event.relatedTarget;\n if (next instanceof Node && this.el.contains(next)) return;\n this.focused = false;\n this.touched = true;\n };\n\n private handleHostClick = (event: MouseEvent) => {\n if (event.target !== this.el || this.isDisabled) return;\n const inputs = this.el.querySelectorAll<HTMLInputElement>('.slider__input');\n inputs[Math.min(this.activeThumbIndex, inputs.length - 1)]?.focus();\n };\n\n private pointerPercent(event: PointerEvent): number {\n const control = this.controlEl;\n if (!control) return 0;\n const rect = control.getBoundingClientRect();\n const thumb = this.el.querySelector<HTMLElement>('.slider__thumb');\n const thumbSize = thumb\n ? this.orientation === 'horizontal'\n ? thumb.offsetWidth\n : thumb.offsetHeight\n : 0;\n // Both alignment modes keep the complete thumb inside the control. Edge\n // alignment lets the rail span the control while center alignment insets\n // the rail to the same thumb-center travel.\n const inset = thumbSize / 2;\n\n if (this.orientation === 'vertical') {\n const travel = Math.max(1, rect.height - inset * 2);\n return Math.min(1, Math.max(0, (rect.bottom - inset - event.clientY) / travel));\n }\n\n const travel = Math.max(1, rect.width - inset * 2);\n const percent = (event.clientX - rect.left - inset) / travel;\n return Math.min(1, Math.max(0, percent));\n }\n\n private valueFromPointer(event: PointerEvent): number {\n return this.snap(this.safeMin + this.pointerPercent(event) * (this.safeMax - this.safeMin));\n }\n\n private closestThumbIndex(value: number, target: EventTarget | null): number {\n const targetElement =\n target instanceof HTMLElement ? target.closest<HTMLElement>('.slider__thumb') : null;\n if (targetElement?.dataset['index']) return Number(targetElement.dataset['index']);\n if (!this.isRange) return 0;\n\n const values = this.resolvedValues;\n const lowerDistance = Math.abs(value - values[0]);\n const upperDistance = Math.abs(value - values[1]);\n if (lowerDistance === upperDistance) return value >= values[0] ? 1 : 0;\n return lowerDistance < upperDistance ? 0 : 1;\n }\n\n private handlePointerDown = (event: PointerEvent) => {\n if (event.button !== 0 || this.isDisabled || this.readOnly) return;\n event.preventDefault();\n const value = this.valueFromPointer(event);\n const index = this.closestThumbIndex(value, event.target);\n this.activeThumbIndex = index;\n this.pointerId = event.pointerId;\n this.pointerStartValue = this.cloneValue(this.publicValue);\n this.dragging = true;\n this.setValueAt(index, value);\n this.controlEl?.setPointerCapture(event.pointerId);\n requestAnimationFrame(() => {\n const input = this.el.querySelectorAll<HTMLInputElement>('.slider__input')[index];\n input?.focus({ preventScroll: true });\n });\n };\n\n private handlePointerMove = (event: PointerEvent) => {\n if (this.pointerId !== event.pointerId || !this.dragging) return;\n event.preventDefault();\n this.setValueAt(this.activeThumbIndex, this.valueFromPointer(event));\n };\n\n private endPointerInteraction(event: PointerEvent, canceled: boolean) {\n if (this.pointerId !== event.pointerId) return;\n if (this.controlEl?.hasPointerCapture(event.pointerId))\n this.controlEl.releasePointerCapture(event.pointerId);\n this.pointerId = null;\n this.dragging = false;\n this.touched = true;\n if (!canceled && !this.valuesEqual(this.pointerStartValue, this.publicValue))\n this.commitIfChanged();\n }\n\n private renderThumb(value: number, index: number) {\n const inputId =\n index === 0\n ? (this.inputId ?? `${this.generatedId}-input`)\n : `${this.inputId ?? `${this.generatedId}-input`}-end`;\n const rangeLabel = index === 0 ? this.startLabel : this.endLabel;\n const labelledby = this.isRange\n ? undefined\n : (this.ariaLabelledby ?? (this.label ? this.labelId : this.externalLabelledby));\n const directLabel = this.isRange ? rangeLabel : labelledby ? undefined : this.ariaLabel;\n\n return (\n <div\n class={{\n slider__thumb: true,\n 'slider__thumb--active': index === this.activeThumbIndex,\n }}\n data-index={String(index)}\n style={{ '--ds-slider-thumb-pct': String(this.percent(value)) } as Record<string, string>}\n >\n <input\n class=\"slider__input\"\n type=\"range\"\n id={inputId}\n min={this.allowedMin(index)}\n max={this.allowedMax(index)}\n step={this.resolvedTicks.length || this.step === 'any' ? 'any' : this.safeStep}\n value={value}\n disabled={this.isDisabled}\n aria-label={directLabel}\n aria-labelledby={labelledby}\n aria-describedby={this.ariaDescribedby}\n aria-valuetext={this.ariaValueText(value, index)}\n aria-orientation={this.orientation === 'vertical' ? 'vertical' : undefined}\n aria-readonly={this.readOnly ? 'true' : undefined}\n onInput={(event: Event) => this.handleNativeInput(event, index)}\n onChange={this.handleNativeChange}\n onKeyDown={event => this.handleKeyDown(event, index)}\n onFocus={() => this.handleFocus(index)}\n onBlur={this.handleBlur}\n />\n <span class=\"slider__thumb-visual\" aria-hidden=\"true\">\n <span class=\"slider__thumb-wash\" />\n </span>\n </div>\n );\n }\n\n render() {\n const values = this.resolvedValues;\n const first = values[0];\n const last = values[values.length - 1];\n const firstInputId = this.inputId ?? `${this.generatedId}-input`;\n const dirty = !this.valuesEqual(this.publicValue, this.initialValue);\n const valueDisplay = values\n .map((value, index) => this.formattedValue(value, index))\n .join(` ${this.rangeSeparator} `);\n\n return (\n <Host\n aria-disabled={this.isDisabled ? 'true' : undefined}\n class={{\n slider: true,\n 'ds-field-stack': true,\n [`slider--${this.size}`]: true,\n [`slider--${this.orientation}`]: true,\n [`slider--thumb-${this.thumbAlignment}`]: true,\n 'slider--range': this.isRange,\n 'slider--ticks': this.resolvedTicks.length > 0,\n 'slider--tick-labels': this.resolvedTicks.some(tick => Boolean(tick.label)),\n 'slider--readonly': this.readOnly,\n 'ds-control-inactive': this.isDisabled,\n }}\n data-orientation={this.orientation}\n data-disabled={this.isDisabled ? '' : undefined}\n data-readonly={this.readOnly ? '' : undefined}\n data-dragging={this.dragging ? '' : undefined}\n data-focused={this.focused ? '' : undefined}\n data-filled=\"\"\n data-dirty={dirty ? '' : undefined}\n data-touched={this.touched ? '' : undefined}\n data-valid={!this.isDisabled ? '' : undefined}\n onClick={this.handleHostClick}\n >\n {(this.label || this.showValue) && (\n <div class=\"slider__label-row\">\n {this.label && (\n <ds-text\n class=\"slider__label\"\n as=\"label\"\n variant=\"text-body-small\"\n color=\"primary\"\n emphasis\n for={firstInputId}\n textId={this.labelId}\n >\n {this.label}\n </ds-text>\n )}\n {this.showValue && (\n <ds-text\n class=\"slider__value\"\n as=\"span\"\n variant=\"text-body-small\"\n color=\"primary\"\n fontFeature=\"tabular-nums\"\n >\n {valueDisplay}\n </ds-text>\n )}\n </div>\n )}\n <div\n class=\"slider__control\"\n ref={element => {\n this.controlEl = element ?? null;\n }}\n style={\n {\n '--ds-slider-start-pct': String(this.isRange ? this.percent(first) : 0),\n '--ds-slider-end-pct': String(this.percent(last)),\n } as Record<string, string>\n }\n onPointerDown={this.handlePointerDown}\n onPointerMove={this.handlePointerMove}\n onPointerUp={(event: PointerEvent) => this.endPointerInteraction(event, false)}\n onPointerCancel={(event: PointerEvent) => this.endPointerInteraction(event, true)}\n >\n <div class=\"slider__rail\" aria-hidden=\"true\">\n <div class=\"slider__indicator\" />\n </div>\n {this.resolvedTicks.map(tick => (\n <span\n class=\"slider__tick\"\n data-edge={\n tick.value === this.safeMin\n ? 'start'\n : tick.value === this.safeMax\n ? 'end'\n : undefined\n }\n aria-hidden=\"true\"\n style={{ '--ds-slider-tick-pct': String(this.percent(tick.value)) }}\n >\n <span class=\"slider__tick-mark\" />\n {tick.label && (\n <ds-text\n class=\"slider__tick-label\"\n as=\"span\"\n variant=\"text-caption\"\n color=\"secondary\"\n >\n {tick.label}\n </ds-text>\n )}\n </span>\n ))}\n {values.map((value, index) => this.renderThumb(value, index))}\n </div>\n </Host>\n );\n }\n}\n",
|
|
701
721
|
"type": "registry:ui"
|
|
702
722
|
}
|
|
703
723
|
]
|
|
@@ -227,8 +227,8 @@
|
|
|
227
227
|
"complexPropertyNote": "Assign these non-primitive values as JavaScript properties: options, sections.",
|
|
228
228
|
"peerDependencies": {
|
|
229
229
|
"required": [
|
|
230
|
-
"@ds-mo/tokens ^6.5.
|
|
231
|
-
"@ds-mo/icons ^8.1.
|
|
230
|
+
"@ds-mo/tokens ^6.5.2",
|
|
231
|
+
"@ds-mo/icons ^8.1.1"
|
|
232
232
|
],
|
|
233
233
|
"frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
|
|
234
234
|
}
|
|
@@ -378,8 +378,8 @@
|
|
|
378
378
|
},
|
|
379
379
|
"peerDependencies": {
|
|
380
380
|
"required": [
|
|
381
|
-
"@ds-mo/tokens ^6.5.
|
|
382
|
-
"@ds-mo/icons ^8.1.
|
|
381
|
+
"@ds-mo/tokens ^6.5.2",
|
|
382
|
+
"@ds-mo/icons ^8.1.1"
|
|
383
383
|
],
|
|
384
384
|
"frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
|
|
385
385
|
}
|
|
@@ -346,8 +346,8 @@
|
|
|
346
346
|
"complexPropertyNote": "Assign these non-primitive values as JavaScript properties: tabs.",
|
|
347
347
|
"peerDependencies": {
|
|
348
348
|
"required": [
|
|
349
|
-
"@ds-mo/tokens ^6.5.
|
|
350
|
-
"@ds-mo/icons ^8.1.
|
|
349
|
+
"@ds-mo/tokens ^6.5.2",
|
|
350
|
+
"@ds-mo/icons ^8.1.1"
|
|
351
351
|
],
|
|
352
352
|
"frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
|
|
353
353
|
}
|