@ds-mo/ui 14.35.0 → 15.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.package-ready.json +1 -1
- package/dist/agent-patterns.json +1 -1
- package/dist/agent.json +5733 -4656
- package/dist/angular/ds-button-inverted.d.ts +17 -0
- package/dist/angular/ds-button-inverted.js +46 -0
- package/dist/angular/ds-calendar.d.ts +15 -0
- package/dist/angular/ds-calendar.js +43 -0
- package/dist/angular/ds-conversation-list.d.ts +1 -1
- package/dist/angular/ds-conversation-list.js +3 -4
- package/dist/angular/ds-data-customize.d.ts +18 -0
- package/dist/angular/ds-data-customize.js +46 -0
- package/dist/angular/ds-data-filter.d.ts +50 -0
- package/dist/angular/{ds-table-filter.js → ds-data-filter.js} +10 -10
- package/dist/angular/ds-data-group.d.ts +29 -0
- package/dist/angular/{ds-table-group.js → ds-data-group.js} +10 -10
- package/dist/angular/ds-data-preferences.d.ts +39 -0
- package/dist/angular/{ds-table-preferences.js → ds-data-preferences.js} +15 -15
- package/dist/angular/ds-data-saved-views.d.ts +49 -0
- package/dist/angular/{ds-table-saved-views.js → ds-data-saved-views.js} +10 -10
- package/dist/angular/ds-data-search.d.ts +20 -0
- package/dist/angular/{ds-table-search.js → ds-data-search.js} +12 -12
- package/dist/angular/ds-data-sort.d.ts +16 -0
- package/dist/angular/{ds-table-sort.js → ds-data-sort.js} +12 -12
- package/dist/angular/ds-data-toolbar.d.ts +12 -0
- package/dist/angular/{ds-table-toolbar.js → ds-data-toolbar.js} +10 -10
- package/dist/angular/ds-field.d.ts +1 -1
- package/dist/angular/ds-field.js +1 -1
- package/dist/angular/ds-input-date.d.ts +15 -0
- package/dist/angular/ds-input-date.js +43 -0
- package/dist/angular/ds-input-time.d.ts +15 -0
- package/dist/angular/ds-input-time.js +43 -0
- package/dist/angular/ds-input.d.ts +1 -1
- package/dist/angular/ds-input.js +3 -3
- package/dist/angular/ds-select.d.ts +1 -1
- package/dist/angular/ds-select.js +3 -3
- package/dist/angular/ds-table.d.ts +7 -7
- package/dist/angular/ds-table.js +6 -6
- package/dist/angular/ds-time-picker.d.ts +15 -0
- package/dist/angular/ds-time-picker.js +43 -0
- package/dist/angular/index.d.ts +1 -1
- package/dist/angular/index.js +13 -7
- package/dist/angular/proxies.d.ts +13 -7
- package/dist/angular/proxies.js +13 -7
- 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-avatar.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.d.ts +11 -0
- package/dist/components/ds-button-inverted.js +2 -0
- package/dist/components/ds-button-inverted.js.map +1 -0
- package/dist/components/ds-button-unfilled.js +1 -1
- package/dist/components/{ds-table-search.d.ts → ds-calendar.d.ts} +4 -4
- package/dist/components/ds-calendar.js +2 -0
- 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-navigation.js.map +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-settings-scope.js +1 -1
- package/dist/components/ds-card-settings-scope.js.map +1 -1
- package/dist/components/ds-chart-legend.js +1 -1
- package/dist/components/ds-chart.js +1 -1
- package/dist/components/ds-checkbox.js +1 -1
- package/dist/components/ds-chip.js +1 -1
- package/dist/components/ds-code-block.js +1 -1
- package/dist/components/ds-conversation-list-item.js +1 -1
- package/dist/components/ds-conversation-list-item.js.map +1 -1
- package/dist/components/ds-conversation-list-section.js +1 -1
- package/dist/components/ds-conversation-list.js +1 -1
- package/dist/components/ds-conversation-list.js.map +1 -1
- package/dist/components/ds-data-customize.d.ts +11 -0
- package/dist/components/ds-data-customize.js +2 -0
- package/dist/components/ds-data-customize.js.map +1 -0
- package/dist/components/{ds-table-group.d.ts → ds-data-filter.d.ts} +4 -4
- package/dist/components/ds-data-filter.js +2 -0
- package/dist/components/ds-data-filter.js.map +1 -0
- package/dist/components/{ds-table-sort.d.ts → ds-data-group.d.ts} +4 -4
- package/dist/components/ds-data-group.js +2 -0
- package/dist/components/ds-data-group.js.map +1 -0
- package/dist/components/{ds-table-saved-views.d.ts → ds-data-preferences.d.ts} +4 -4
- package/dist/components/ds-data-preferences.js +2 -0
- package/dist/components/ds-data-preferences.js.map +1 -0
- package/dist/components/ds-data-saved-views.d.ts +11 -0
- package/dist/components/ds-data-saved-views.js +2 -0
- package/dist/components/ds-data-saved-views.js.map +1 -0
- package/dist/components/ds-data-search.d.ts +11 -0
- package/dist/components/ds-data-search.js +2 -0
- package/dist/components/ds-data-search.js.map +1 -0
- package/dist/components/ds-data-sort.d.ts +11 -0
- package/dist/components/ds-data-sort.js +2 -0
- package/dist/components/ds-data-sort.js.map +1 -0
- package/dist/components/{ds-table-filter.d.ts → ds-data-toolbar.d.ts} +4 -4
- package/dist/components/ds-data-toolbar.js +2 -0
- package/dist/components/ds-data-toolbar.js.map +1 -0
- package/dist/components/ds-divider.js +1 -1
- package/dist/components/ds-empty-state.js +1 -1
- package/dist/components/ds-field.js +1 -1
- package/dist/components/ds-filter-menu.js +1 -1
- package/dist/components/ds-icon.js +1 -1
- package/dist/components/ds-input-date.d.ts +11 -0
- package/dist/components/ds-input-date.js +2 -0
- package/dist/components/ds-input-date.js.map +1 -0
- package/dist/components/ds-input-time.d.ts +11 -0
- package/dist/components/ds-input-time.js +2 -0
- package/dist/components/ds-input-time.js.map +1 -0
- package/dist/components/ds-input.js +1 -1
- package/dist/components/ds-markdown.js +1 -1
- package/dist/components/ds-menu.js +1 -1
- package/dist/components/ds-message-actions.js +1 -1
- package/dist/components/ds-message-bubble.js +1 -1
- package/dist/components/ds-message-bubble.js.map +1 -1
- package/dist/components/ds-message-composer.js +1 -1
- package/dist/components/ds-message-composer.js.map +1 -1
- package/dist/components/ds-message-scroller.js +1 -1
- package/dist/components/ds-message.js +1 -1
- package/dist/components/ds-mobile-bar-nav.js +1 -1
- package/dist/components/ds-mobile-header.js +1 -1
- package/dist/components/ds-mobile-section-switcher.js +1 -1
- package/dist/components/ds-mobile-sheet-nav.js +1 -1
- package/dist/components/ds-modal.js +1 -1
- package/dist/components/ds-pagination.js +1 -1
- package/dist/components/ds-panel-nav.js +1 -1
- package/dist/components/ds-panel-sub-nav.js +1 -1
- package/dist/components/ds-panel-tool-header.js +1 -1
- package/dist/components/ds-panel-tool-search.js +1 -1
- package/dist/components/ds-panel-tools.js +1 -1
- package/dist/components/ds-paper-texture.js +1 -1
- package/dist/components/ds-radio.js +1 -1
- package/dist/components/ds-score.js +1 -1
- package/dist/components/ds-scroll-overlay.js +1 -1
- package/dist/components/ds-select.js +1 -1
- 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.d.ts +11 -0
- package/dist/components/ds-time-picker.js +2 -0
- package/dist/components/ds-time-picker.js.map +1 -0
- 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/index.d.ts +5 -5
- package/dist/components/p-0FYD2bev.js +2 -0
- package/dist/components/p-0FYD2bev.js.map +1 -0
- package/dist/components/p-0qY_HDId.js +2 -0
- package/dist/components/{p-D_u8WhlU.js.map → p-0qY_HDId.js.map} +1 -1
- package/dist/components/{p-BQsVI_vO.js → p-5URekSny.js} +2 -2
- package/dist/components/{p-eo_pmPqp.js → p-7V1AhetH.js} +2 -2
- package/dist/components/{p-yZRXPHDe.js → p-8yBdCXCn.js} +2 -2
- package/dist/components/p-BKZdqJQB.js +2 -0
- package/dist/components/p-BKZdqJQB.js.map +1 -0
- package/dist/components/p-BYrBU_U9.js +2 -0
- package/dist/components/p-BYrBU_U9.js.map +1 -0
- package/dist/components/{p-D44g2Kw1.js → p-BciTtTwx.js} +2 -2
- package/dist/components/p-BciTtTwx.js.map +1 -0
- package/dist/components/{p-CZOiTaNa.js → p-BeNa6tw5.js} +2 -2
- package/dist/components/{p-CZOiTaNa.js.map → p-BeNa6tw5.js.map} +1 -1
- package/dist/components/p-BgQMEHRa.js +2 -0
- package/dist/components/{p-CwqFJMvP.js.map → p-BgQMEHRa.js.map} +1 -1
- package/dist/components/{p-BQaO7cg_.js → p-BhJXmuRA.js} +2 -2
- package/dist/components/{p-n68x-ZKp.js → p-Bm7rqs3C.js} +2 -2
- package/dist/components/{p-DdspY23v.js → p-Bn8I7iw6.js} +2 -2
- package/dist/components/{p-BnWxbhFP.js → p-Bpd6YCo4.js} +2 -2
- package/dist/components/{p-B-9fdIWv.js → p-C-3YqeTb.js} +2 -2
- package/dist/components/{p-umAf0fBn.js → p-CD4DZPy_.js} +2 -2
- package/dist/components/p-CElUM-xU.js +2 -0
- package/dist/components/p-CElUM-xU.js.map +1 -0
- package/dist/components/{p-CuwopElg.js → p-CGidq1iC.js} +2 -2
- package/dist/components/p-CNxvnQ6A.js +2 -0
- package/dist/components/p-CNxvnQ6A.js.map +1 -0
- package/dist/components/{p-CI7VfYC3.js → p-CUcUHwI3.js} +2 -2
- package/dist/components/p-CYzFfFcH.js +2 -0
- package/dist/components/{p-BINSI_KF.js.map → p-CYzFfFcH.js.map} +1 -1
- package/dist/components/{p-Dhw_W8nk.js → p-Cc3ZUQlJ.js} +2 -2
- package/dist/components/p-Cc3ZUQlJ.js.map +1 -0
- package/dist/components/p-CdgOLWX9.js +2 -0
- package/dist/components/p-CdgOLWX9.js.map +1 -0
- package/dist/components/{p-BcdHgPi5.js → p-CeXf9-X3.js} +2 -2
- package/dist/components/{p-CSnsz3Eb.js → p-CiH4GG6r.js} +2 -2
- package/dist/components/{p-y06IxxoN.js → p-CiJ1WR11.js} +2 -2
- package/dist/components/p-CmexIVnE.js +2 -0
- package/dist/components/{p-N5SHSVo2.js.map → p-CmexIVnE.js.map} +1 -1
- package/dist/components/{p-BmFeeR4q.js → p-CqW2eyiF.js} +2 -2
- package/dist/components/{p-CzbsTZt7.js → p-Cxr0IQjC.js} +2 -2
- package/dist/components/{p-CqlBlv55.js → p-CzIpquvw.js} +2 -2
- package/dist/components/{p-DC69DgAR.js → p-D0y7Sja6.js} +2 -2
- package/dist/components/{p-Cwz9TPVS.js → p-D1vQGJzc.js} +2 -2
- package/dist/components/{p-Cwz9TPVS.js.map → p-D1vQGJzc.js.map} +1 -1
- package/dist/components/{p-C7CZ9pnP.js → p-D6Wl3dRO.js} +2 -2
- package/dist/components/{p-BPhbwXOv.js → p-D922f6Tb.js} +2 -2
- package/dist/components/{p-beRFLHbB.js → p-DHICPS4n.js} +2 -2
- package/dist/components/{p-omPm8_vx.js → p-DOAybCp0.js} +2 -2
- package/dist/components/{p-DEGNrPLe.js → p-DVINzOoK.js} +2 -2
- package/dist/components/{p-DEGNrPLe.js.map → p-DVINzOoK.js.map} +1 -1
- package/dist/components/p-DVOjjuXc.js +2 -0
- package/dist/components/p-DVOjjuXc.js.map +1 -0
- package/dist/components/p-Di5FH7eh.js +2 -0
- package/dist/components/p-Di5FH7eh.js.map +1 -0
- package/dist/components/p-DjkUFlDW.js +2 -0
- package/dist/components/p-DjkUFlDW.js.map +1 -0
- package/dist/components/{p-BnzsBNUY.js → p-Dn9QHL4O.js} +2 -2
- package/dist/components/{p-DGzn4k4h.js → p-Do2FJd1y.js} +2 -2
- package/dist/components/{p-DTDLlinw.js → p-DpoTwJAR.js} +2 -2
- package/dist/components/{p-Dk-8Ju0Q.js → p-Dpr2y6_S.js} +2 -2
- package/dist/components/{p-Dk-8Ju0Q.js.map → p-Dpr2y6_S.js.map} +1 -1
- package/dist/components/p-Dw9sE6Iw.js +2 -0
- package/dist/components/p-Dw9sE6Iw.js.map +1 -0
- package/dist/components/{p-CLGtPE0K.js → p-DwbcNDJF.js} +2 -2
- package/dist/components/p-Dzndkdx5.js +2 -0
- package/dist/components/{p-xHGqrz_p.js.map → p-Dzndkdx5.js.map} +1 -1
- package/dist/components/{p-C8ek-1SP.js → p-E5W27Fu_.js} +2 -2
- package/dist/components/{p-mpk_Mm8_.js → p-FIBCluwV.js} +2 -2
- package/dist/components/{p-DQQFN2sw.js → p-IEq_06J0.js} +2 -2
- package/dist/components/{p-DQQFN2sw.js.map → p-IEq_06J0.js.map} +1 -1
- package/dist/components/{p-CE540WZ7.js → p-MG4lcN0D.js} +2 -2
- package/dist/components/p-Nc76seSq.js +2 -0
- package/dist/components/p-Nc76seSq.js.map +1 -0
- package/dist/components/{p-DtLQIMsa.js → p-ZhP2tVmM.js} +2 -2
- package/dist/components/p-aD5cw_m2.js +2 -0
- package/dist/components/p-aD5cw_m2.js.map +1 -0
- package/dist/components/p-etifxiDc.js +2 -0
- package/dist/components/{p-beCz9OnD.js.map → p-etifxiDc.js.map} +1 -1
- package/dist/components/p-kDZ0sEII.js +2 -0
- package/dist/components/p-kDZ0sEII.js.map +1 -0
- package/dist/components/{p-BPlWEidl.js → p-ljbw3UMZ.js} +2 -2
- package/dist/components/{p-DZ58Sg5a.js → p-vfCu7XSc.js} +2 -2
- package/dist/components/p-vfCu7XSc.js.map +1 -0
- package/dist/components/{p-DFjIBS5B.js → p-xdmJCPCg.js} +2 -2
- package/dist/components/{p-CAxDdYjh.js → p-xtGGIZmU.js} +2 -2
- package/dist/docs/components.json +18102 -14568
- package/dist/lib/components/Icon/flag-icon-catalog.d.ts +2 -0
- package/dist/lib/components/Icon/icon-cache.d.ts +36 -4
- package/dist/lib/components/Icon/map-icon-catalog.d.ts +2 -0
- package/dist/lib/shell/index.js +2 -2
- package/dist/lib/shell/index.js.map +1 -1
- package/dist/lib/utils/button-render.d.ts +1 -1
- package/dist/lib/utils/clock-time.d.ts +22 -0
- package/dist/lib/utils/date-filter-value.d.ts +4 -0
- package/dist/lib/utils/index.d.ts +3 -1
- package/dist/lib/utils/index.js +201 -5
- package/dist/lib/utils/index.js.map +4 -4
- 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 +1 -1
- package/dist/mcp-data/registry/agent-source-list.json +1 -1
- package/dist/mcp-data/registry/agent-tool-call.json +2 -2
- package/dist/mcp-data/registry/attachment-list.json +1 -1
- package/dist/mcp-data/registry/avatar.json +1 -1
- package/dist/mcp-data/registry/badge.json +1 -1
- package/dist/mcp-data/registry/banner.json +1 -1
- package/dist/mcp-data/registry/bar-action.json +1 -1
- package/dist/mcp-data/registry/bar-nav.json +1 -1
- package/dist/mcp-data/registry/bar-page-title.json +1 -1
- package/dist/mcp-data/registry/bar-title.json +3 -3
- package/dist/mcp-data/registry/bar-workflow.json +1 -1
- package/dist/mcp-data/registry/breadcrumb.json +1 -1
- package/dist/mcp-data/registry/button-filled.json +1 -1
- package/dist/mcp-data/registry/button-inverted.json +580 -0
- package/dist/mcp-data/registry/button-unfilled.json +1 -1
- package/dist/mcp-data/registry/calendar.json +273 -0
- package/dist/mcp-data/registry/card-action-center.json +1 -1
- package/dist/mcp-data/registry/card-chart.json +1 -1
- package/dist/mcp-data/registry/card-navigation.json +5 -3
- package/dist/mcp-data/registry/card-overview.json +1 -1
- package/dist/mcp-data/registry/card-setting.json +1 -1
- package/dist/mcp-data/registry/card-settings-scope.json +1 -1
- package/dist/mcp-data/registry/chart-legend.json +1 -1
- package/dist/mcp-data/registry/chart.json +1 -1
- package/dist/mcp-data/registry/checkbox.json +1 -1
- package/dist/mcp-data/registry/chip.json +1 -1
- package/dist/mcp-data/registry/code-block.json +1 -1
- package/dist/mcp-data/registry/conversation-list-item.json +1 -1
- package/dist/mcp-data/registry/conversation-list-section.json +1 -1
- package/dist/mcp-data/registry/conversation-list.json +10 -32
- package/dist/mcp-data/registry/data-customize.json +374 -0
- package/dist/mcp-data/registry/{table-filter.json → data-filter.json} +33 -33
- package/dist/mcp-data/registry/data-group.json +358 -0
- package/dist/mcp-data/registry/data-preferences.json +566 -0
- package/dist/mcp-data/registry/data-saved-views.json +433 -0
- package/dist/mcp-data/registry/data-search.json +367 -0
- package/dist/mcp-data/registry/data-sort.json +254 -0
- package/dist/mcp-data/registry/data-toolbar.json +181 -0
- package/dist/mcp-data/registry/divider.json +1 -1
- package/dist/mcp-data/registry/empty-state.json +1 -1
- package/dist/mcp-data/registry/field.json +20 -15
- package/dist/mcp-data/registry/filter-menu.json +7 -11
- package/dist/mcp-data/registry/icon.json +13 -7
- package/dist/mcp-data/registry/input-date.json +516 -0
- package/dist/mcp-data/registry/input-time.json +535 -0
- package/dist/mcp-data/registry/input.json +57 -9
- package/dist/mcp-data/registry/loader.json +1 -1
- package/dist/mcp-data/registry/markdown.json +1 -1
- package/dist/mcp-data/registry/menu.json +3 -3
- package/dist/mcp-data/registry/message-actions.json +1 -1
- package/dist/mcp-data/registry/message-bubble.json +1 -1
- package/dist/mcp-data/registry/message-composer.json +2 -2
- package/dist/mcp-data/registry/message-scroller.json +1 -1
- package/dist/mcp-data/registry/message.json +1 -1
- package/dist/mcp-data/registry/mobile-bar-nav.json +2 -2
- package/dist/mcp-data/registry/mobile-header.json +1 -1
- package/dist/mcp-data/registry/mobile-section-switcher.json +1 -1
- package/dist/mcp-data/registry/mobile-sheet-nav.json +2 -2
- package/dist/mcp-data/registry/modal.json +1 -1
- package/dist/mcp-data/registry/pagination.json +1 -1
- package/dist/mcp-data/registry/panel-nav.json +1 -1
- package/dist/mcp-data/registry/panel-sub-nav.json +1 -1
- package/dist/mcp-data/registry/panel-tool-header.json +1 -1
- package/dist/mcp-data/registry/panel-tool-search.json +1 -1
- package/dist/mcp-data/registry/panel-tools.json +3 -3
- package/dist/mcp-data/registry/paper-texture.json +1 -1
- package/dist/mcp-data/registry/radio.json +1 -1
- package/dist/mcp-data/registry/registry.json +5911 -4816
- package/dist/mcp-data/registry/score.json +1 -1
- package/dist/mcp-data/registry/scroll-overlay.json +1 -1
- package/dist/mcp-data/registry/select.json +64 -8
- package/dist/mcp-data/registry/shell-app.json +1 -1
- package/dist/mcp-data/registry/shell-page.json +1 -1
- package/dist/mcp-data/registry/shell-tools.json +1 -1
- package/dist/mcp-data/registry/skeleton.json +1 -1
- package/dist/mcp-data/registry/slider.json +1 -1
- package/dist/mcp-data/registry/swatch-picker.json +1 -1
- package/dist/mcp-data/registry/switch.json +1 -1
- package/dist/mcp-data/registry/tab-group.json +1 -1
- package/dist/mcp-data/registry/table.json +71 -71
- package/dist/mcp-data/registry/tag.json +1 -1
- package/dist/mcp-data/registry/text.json +1 -1
- package/dist/mcp-data/registry/textarea.json +3 -3
- package/dist/mcp-data/registry/time-picker.json +259 -0
- package/dist/mcp-data/registry/toast.json +1 -1
- package/dist/mcp-data/registry/tooltip-chart.json +1 -1
- package/dist/mcp-data/registry/tooltip.json +1 -1
- package/dist/mcp-data/registry/typing-indicator.json +1 -1
- package/dist/react/components.d.ts +13 -7
- package/dist/react/components.js +13 -7
- package/dist/react/ds-button-inverted.d.ts +13 -0
- package/dist/react/ds-button-inverted.js +15 -0
- package/dist/react/ds-calendar.d.ts +12 -0
- package/dist/react/ds-calendar.js +12 -0
- package/dist/react/ds-data-customize.d.ts +13 -0
- package/dist/react/ds-data-customize.js +15 -0
- package/dist/react/ds-data-filter.d.ts +18 -0
- package/dist/react/{ds-table-filter.js → ds-data-filter.js} +5 -5
- package/dist/react/ds-data-group.d.ts +14 -0
- package/dist/react/{ds-table-group.js → ds-data-group.js} +5 -5
- package/dist/react/ds-data-preferences.d.ts +21 -0
- package/dist/react/{ds-table-preferences.js → ds-data-preferences.js} +6 -6
- package/dist/react/ds-data-saved-views.d.ts +17 -0
- package/dist/react/{ds-table-saved-views.js → ds-data-saved-views.js} +5 -5
- package/dist/react/ds-data-search.d.ts +14 -0
- package/dist/react/{ds-table-search.js → ds-data-search.js} +5 -5
- package/dist/react/ds-data-sort.d.ts +12 -0
- package/dist/react/ds-data-sort.js +12 -0
- package/dist/react/{ds-table-toolbar.d.ts → ds-data-toolbar.d.ts} +3 -3
- package/dist/react/ds-data-toolbar.js +12 -0
- package/dist/react/ds-field.d.ts +1 -1
- package/dist/react/ds-input-date.d.ts +12 -0
- package/dist/react/ds-input-date.js +12 -0
- package/dist/react/ds-input-time.d.ts +12 -0
- package/dist/react/ds-input-time.js +12 -0
- package/dist/react/ds-table.d.ts +3 -3
- package/dist/react/ds-table.js +1 -1
- package/dist/react/ds-time-picker.d.ts +12 -0
- package/dist/react/ds-time-picker.js +12 -0
- package/dist/styles/table.css +11 -11
- package/dist/types/components/BarTitle/BarTitle.d.ts +1 -0
- package/dist/types/components/BarTitle/bar-title-action-chrome.d.ts +2 -0
- package/dist/types/components/ButtonInverted/ButtonInverted.d.ts +83 -0
- package/dist/types/components/ButtonInverted/index.d.ts +2 -0
- package/dist/types/components/Calendar/Calendar.d.ts +32 -0
- package/dist/types/components/Calendar/calendar-grid.d.ts +19 -0
- package/dist/types/components/ConversationList/ConversationList.d.ts +0 -7
- package/dist/types/components/DataCustomize/DataCustomize.d.ts +67 -0
- package/dist/types/components/{TableFilter/TableFilter.d.ts → DataFilter/DataFilter.d.ts} +2 -2
- package/dist/types/components/{TableGroup/TableGroup.d.ts → DataGroup/DataGroup.d.ts} +8 -8
- package/dist/types/components/{TablePreferences/TablePreferences.d.ts → DataPreferences/DataPreferences.d.ts} +29 -13
- package/dist/types/components/{TableSavedViews/TableSavedViews.d.ts → DataSavedViews/DataSavedViews.d.ts} +10 -10
- package/dist/types/components/DataSavedViews/data-saved-views-types.d.ts +24 -0
- package/dist/types/components/DataSavedViews/index.d.ts +2 -0
- package/dist/types/components/{TableSearch/TableSearch.d.ts → DataSearch/DataSearch.d.ts} +6 -6
- package/dist/types/components/{TableSearch/table-search-model.d.ts → DataSearch/data-search-model.d.ts} +6 -6
- package/dist/types/components/{TableSearch/table-search-types.d.ts → DataSearch/data-search-types.d.ts} +3 -3
- package/dist/types/components/{TableSort/TableSort.d.ts → DataSort/DataSort.d.ts} +7 -6
- package/dist/types/components/DataSort/data-sort-menu.d.ts +15 -0
- package/dist/types/components/{TableToolbar/TableToolbar.d.ts → DataToolbar/DataToolbar.d.ts} +3 -3
- package/dist/types/components/Field/Field.d.ts +7 -2
- package/dist/types/components/FilterMenu/FilterMenu.d.ts +0 -10
- package/dist/types/components/Icon/icon-cache.d.ts +36 -4
- package/dist/types/components/Icon/map-icon-catalog.d.ts +3 -0
- package/dist/types/components/Input/Input.d.ts +10 -0
- package/dist/types/components/InputDate/InputDate.d.ts +78 -0
- package/dist/types/components/InputTime/InputTime.d.ts +80 -0
- package/dist/types/components/PanelTools/PanelTools.d.ts +1 -1
- package/dist/types/components/Select/Select.d.ts +8 -1
- package/dist/types/components/Table/Table.d.ts +9 -9
- package/dist/types/components/Table/index.d.ts +1 -1
- package/dist/types/components/Table/table-action-menu.d.ts +1 -1
- package/dist/types/components/Table/table-body-renderer.d.ts +2 -2
- package/dist/types/components/Table/table-column-customizer.d.ts +9 -9
- package/dist/types/components/Table/table-group-load-controller.d.ts +2 -2
- package/dist/types/components/Table/table-model.d.ts +7 -7
- package/dist/types/components/Table/table-render-model.d.ts +3 -3
- package/dist/types/components/Table/table-types.d.ts +17 -36
- package/dist/types/components/Table/table-virtual-model.d.ts +2 -2
- package/dist/types/components/TimePicker/TimePicker.d.ts +33 -0
- package/dist/types/components.d.ts +5461 -4433
- package/dist/types/utils/button-render.d.ts +1 -1
- package/dist/types/utils/clock-time.d.ts +23 -0
- package/dist/types/utils/data-field.d.ts +38 -0
- package/dist/types/utils/date-filter-value.d.ts +4 -0
- package/dist/types/utils/index.d.ts +3 -1
- package/dist/types/utils/list-customizer.d.ts +38 -0
- package/dist/types/utils/table-caption-compact.d.ts +1 -1
- package/dist/vue/components.d.ts +13 -7
- package/dist/vue/components.js +13 -7
- package/dist/vue/ds-button-inverted.d.ts +3 -0
- package/dist/vue/ds-button-inverted.js +33 -0
- package/dist/vue/{ds-table-sort.d.ts → ds-calendar.d.ts} +1 -1
- package/dist/vue/ds-calendar.js +16 -0
- package/dist/vue/ds-conversation-list.js +1 -3
- package/dist/vue/ds-data-customize.d.ts +3 -0
- package/dist/vue/ds-data-customize.js +23 -0
- package/dist/vue/{ds-table-group.d.ts → ds-data-filter.d.ts} +1 -1
- package/dist/vue/{ds-table-filter.js → ds-data-filter.js} +2 -2
- package/dist/vue/{ds-table-filter.d.ts → ds-data-group.d.ts} +1 -1
- package/dist/vue/{ds-table-group.js → ds-data-group.js} +2 -2
- package/dist/vue/{ds-table-saved-views.d.ts → ds-data-preferences.d.ts} +1 -1
- package/dist/vue/{ds-table-preferences.js → ds-data-preferences.js} +10 -7
- package/dist/vue/ds-data-saved-views.d.ts +3 -0
- package/dist/vue/{ds-table-saved-views.js → ds-data-saved-views.js} +2 -2
- package/dist/vue/{ds-table-search.d.ts → ds-data-search.d.ts} +1 -1
- package/dist/vue/{ds-table-search.js → ds-data-search.js} +3 -3
- package/dist/vue/ds-data-sort.d.ts +3 -0
- package/dist/vue/{ds-table-sort.js → ds-data-sort.js} +3 -3
- package/dist/vue/ds-data-toolbar.d.ts +3 -0
- package/dist/vue/ds-data-toolbar.js +9 -0
- package/dist/vue/{ds-table-preferences.d.ts → ds-input-date.d.ts} +1 -1
- package/dist/vue/ds-input-date.js +31 -0
- package/dist/vue/ds-input-time.d.ts +3 -0
- package/dist/vue/ds-input-time.js +32 -0
- package/dist/vue/ds-input.js +2 -0
- package/dist/vue/ds-select.js +3 -0
- package/dist/vue/ds-table.js +4 -4
- package/dist/vue/ds-time-picker.d.ts +3 -0
- package/dist/vue/ds-time-picker.js +16 -0
- package/package.json +3 -3
- package/dist/angular/ds-table-filter.d.ts +0 -50
- package/dist/angular/ds-table-group.d.ts +0 -29
- package/dist/angular/ds-table-preferences.d.ts +0 -39
- package/dist/angular/ds-table-saved-views.d.ts +0 -49
- package/dist/angular/ds-table-search.d.ts +0 -20
- package/dist/angular/ds-table-sort.d.ts +0 -16
- package/dist/angular/ds-table-toolbar.d.ts +0 -12
- package/dist/components/ds-table-filter.js +0 -2
- package/dist/components/ds-table-filter.js.map +0 -1
- package/dist/components/ds-table-group.js +0 -2
- package/dist/components/ds-table-preferences.d.ts +0 -11
- package/dist/components/ds-table-preferences.js +0 -2
- package/dist/components/ds-table-preferences.js.map +0 -1
- package/dist/components/ds-table-saved-views.js +0 -2
- package/dist/components/ds-table-saved-views.js.map +0 -1
- package/dist/components/ds-table-search.js +0 -2
- package/dist/components/ds-table-search.js.map +0 -1
- package/dist/components/ds-table-sort.js +0 -2
- package/dist/components/ds-table-sort.js.map +0 -1
- package/dist/components/ds-table-toolbar.d.ts +0 -11
- package/dist/components/ds-table-toolbar.js +0 -2
- package/dist/components/ds-table-toolbar.js.map +0 -1
- package/dist/components/p-BINSI_KF.js +0 -2
- package/dist/components/p-BbfBvMRR.js +0 -2
- package/dist/components/p-BbfBvMRR.js.map +0 -1
- package/dist/components/p-C1_3CVma.js +0 -2
- package/dist/components/p-C1_3CVma.js.map +0 -1
- package/dist/components/p-CKarsuR2.js +0 -2
- package/dist/components/p-CKarsuR2.js.map +0 -1
- package/dist/components/p-Cea7rROU.js +0 -2
- package/dist/components/p-Cea7rROU.js.map +0 -1
- package/dist/components/p-Cmj04E5Q.js +0 -2
- package/dist/components/p-Cmj04E5Q.js.map +0 -1
- package/dist/components/p-Cq_Qpe_C.js +0 -2
- package/dist/components/p-Cq_Qpe_C.js.map +0 -1
- package/dist/components/p-CwqFJMvP.js +0 -2
- package/dist/components/p-D44g2Kw1.js.map +0 -1
- package/dist/components/p-DZ58Sg5a.js.map +0 -1
- package/dist/components/p-D_u8WhlU.js +0 -2
- package/dist/components/p-Dhw_W8nk.js.map +0 -1
- package/dist/components/p-FPZbS19l.js +0 -2
- package/dist/components/p-FPZbS19l.js.map +0 -1
- package/dist/components/p-KBrC9IG4.js +0 -2
- package/dist/components/p-KBrC9IG4.js.map +0 -1
- package/dist/components/p-N5SHSVo2.js +0 -2
- package/dist/components/p-QjkufCcn.js +0 -2
- package/dist/components/p-QjkufCcn.js.map +0 -1
- package/dist/components/p-UAIxh67Q.js +0 -2
- package/dist/components/p-UAIxh67Q.js.map +0 -1
- package/dist/components/p-beCz9OnD.js +0 -2
- package/dist/components/p-xHGqrz_p.js +0 -2
- package/dist/mcp-data/registry/table-group.json +0 -358
- package/dist/mcp-data/registry/table-preferences.json +0 -511
- package/dist/mcp-data/registry/table-saved-views.json +0 -431
- package/dist/mcp-data/registry/table-search.json +0 -366
- package/dist/mcp-data/registry/table-sort.json +0 -253
- package/dist/mcp-data/registry/table-toolbar.json +0 -180
- package/dist/react/ds-table-filter.d.ts +0 -18
- package/dist/react/ds-table-group.d.ts +0 -14
- package/dist/react/ds-table-preferences.d.ts +0 -21
- package/dist/react/ds-table-saved-views.d.ts +0 -17
- package/dist/react/ds-table-search.d.ts +0 -14
- package/dist/react/ds-table-sort.d.ts +0 -12
- package/dist/react/ds-table-sort.js +0 -12
- package/dist/react/ds-table-toolbar.js +0 -12
- package/dist/types/components/FilterMenu/filter-menu-calendar.d.ts +0 -13
- package/dist/types/components/TableSavedViews/index.d.ts +0 -2
- package/dist/types/components/TableSavedViews/table-saved-views-types.d.ts +0 -24
- package/dist/types/components/TableSort/table-sort-menu.d.ts +0 -15
- package/dist/vue/ds-table-toolbar.d.ts +0 -3
- package/dist/vue/ds-table-toolbar.js +0 -9
- /package/dist/components/{ds-table-group.js.map → ds-calendar.js.map} +0 -0
- /package/dist/components/{p-BQsVI_vO.js.map → p-5URekSny.js.map} +0 -0
- /package/dist/components/{p-eo_pmPqp.js.map → p-7V1AhetH.js.map} +0 -0
- /package/dist/components/{p-yZRXPHDe.js.map → p-8yBdCXCn.js.map} +0 -0
- /package/dist/components/{p-BQaO7cg_.js.map → p-BhJXmuRA.js.map} +0 -0
- /package/dist/components/{p-n68x-ZKp.js.map → p-Bm7rqs3C.js.map} +0 -0
- /package/dist/components/{p-DdspY23v.js.map → p-Bn8I7iw6.js.map} +0 -0
- /package/dist/components/{p-BnWxbhFP.js.map → p-Bpd6YCo4.js.map} +0 -0
- /package/dist/components/{p-B-9fdIWv.js.map → p-C-3YqeTb.js.map} +0 -0
- /package/dist/components/{p-umAf0fBn.js.map → p-CD4DZPy_.js.map} +0 -0
- /package/dist/components/{p-CuwopElg.js.map → p-CGidq1iC.js.map} +0 -0
- /package/dist/components/{p-CI7VfYC3.js.map → p-CUcUHwI3.js.map} +0 -0
- /package/dist/components/{p-BcdHgPi5.js.map → p-CeXf9-X3.js.map} +0 -0
- /package/dist/components/{p-CSnsz3Eb.js.map → p-CiH4GG6r.js.map} +0 -0
- /package/dist/components/{p-y06IxxoN.js.map → p-CiJ1WR11.js.map} +0 -0
- /package/dist/components/{p-BmFeeR4q.js.map → p-CqW2eyiF.js.map} +0 -0
- /package/dist/components/{p-CzbsTZt7.js.map → p-Cxr0IQjC.js.map} +0 -0
- /package/dist/components/{p-CqlBlv55.js.map → p-CzIpquvw.js.map} +0 -0
- /package/dist/components/{p-DC69DgAR.js.map → p-D0y7Sja6.js.map} +0 -0
- /package/dist/components/{p-C7CZ9pnP.js.map → p-D6Wl3dRO.js.map} +0 -0
- /package/dist/components/{p-BPhbwXOv.js.map → p-D922f6Tb.js.map} +0 -0
- /package/dist/components/{p-beRFLHbB.js.map → p-DHICPS4n.js.map} +0 -0
- /package/dist/components/{p-omPm8_vx.js.map → p-DOAybCp0.js.map} +0 -0
- /package/dist/components/{p-BnzsBNUY.js.map → p-Dn9QHL4O.js.map} +0 -0
- /package/dist/components/{p-DGzn4k4h.js.map → p-Do2FJd1y.js.map} +0 -0
- /package/dist/components/{p-DTDLlinw.js.map → p-DpoTwJAR.js.map} +0 -0
- /package/dist/components/{p-CLGtPE0K.js.map → p-DwbcNDJF.js.map} +0 -0
- /package/dist/components/{p-C8ek-1SP.js.map → p-E5W27Fu_.js.map} +0 -0
- /package/dist/components/{p-mpk_Mm8_.js.map → p-FIBCluwV.js.map} +0 -0
- /package/dist/components/{p-CE540WZ7.js.map → p-MG4lcN0D.js.map} +0 -0
- /package/dist/components/{p-DtLQIMsa.js.map → p-ZhP2tVmM.js.map} +0 -0
- /package/dist/components/{p-BPlWEidl.js.map → p-ljbw3UMZ.js.map} +0 -0
- /package/dist/components/{p-DFjIBS5B.js.map → p-xdmJCPCg.js.map} +0 -0
- /package/dist/components/{p-CAxDdYjh.js.map → p-xtGGIZmU.js.map} +0 -0
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
3
|
+
"name": "data-sort",
|
|
4
|
+
"title": "DataSort",
|
|
5
|
+
"description": "Toolbar control for one application-owned sort, with separate field and direction choices that can also mirror table-header sorting.",
|
|
6
|
+
"type": "registry:ui",
|
|
7
|
+
"meta": {
|
|
8
|
+
"library": "@ds-mo/ui",
|
|
9
|
+
"distribution": "npm",
|
|
10
|
+
"storybook": "https://zainadeel.github.io/compomo/?path=/story/data-sort",
|
|
11
|
+
"source": "src/wc/components/DataSort/DataSort.tsx",
|
|
12
|
+
"intentStatus": "complete",
|
|
13
|
+
"intent": {
|
|
14
|
+
"audience": "general",
|
|
15
|
+
"status": "stable",
|
|
16
|
+
"summary": "Toolbar control for one application-owned sort, with separate field and direction choices that can also mirror table-header sorting.",
|
|
17
|
+
"useWhen": [
|
|
18
|
+
"A data view needs an explicit Sort control alongside Filter and Group.",
|
|
19
|
+
"Sortable columns or compound header segments should be choosable without relying only on column-header clicks."
|
|
20
|
+
],
|
|
21
|
+
"avoidWhen": [
|
|
22
|
+
"The data view has no sortable fields.",
|
|
23
|
+
"The application expects the control to sort rows internally or persist preferences.",
|
|
24
|
+
"The popup should submit a form value; use Select."
|
|
25
|
+
],
|
|
26
|
+
"alternatives": [
|
|
27
|
+
{
|
|
28
|
+
"when": "The choice is one submitted form value.",
|
|
29
|
+
"component": "component:ds-select",
|
|
30
|
+
"reason": "Select owns form-value and listbox semantics, not table sort state."
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
"commonlyComposedWith": [
|
|
34
|
+
"component:ds-table",
|
|
35
|
+
"component:ds-data-toolbar",
|
|
36
|
+
"component:ds-data-filter",
|
|
37
|
+
"component:ds-select",
|
|
38
|
+
"component:ds-button-unfilled",
|
|
39
|
+
"component:ds-menu"
|
|
40
|
+
],
|
|
41
|
+
"patterns": [
|
|
42
|
+
"pattern:menu-trigger"
|
|
43
|
+
],
|
|
44
|
+
"accessibility": [
|
|
45
|
+
"The trigger is an icon-label menu button named Sort table unless a product aria-label is supplied. Compact caption widths keep that accessible name after the visible label is omitted.",
|
|
46
|
+
"The start-aligned menu has two sections, Data and Order. Each section presents one selected row through isSelected; the menu is not a single radio group because field and direction are independent.",
|
|
47
|
+
"Choosing a row applies immediately and keeps the menu open so the other section can be changed. Escape and outside activation close the menu and restore trigger focus."
|
|
48
|
+
],
|
|
49
|
+
"states": [
|
|
50
|
+
"fields and sort are controlled. dsSortChange reports the next DataSortState and never mutates those inputs. The same sort object is what column headers emit through the table.",
|
|
51
|
+
"Selecting a different data field keeps the current direction, or starts ascending when no sort exists. Selecting a direction applies it to the current field, or to the first sortable field when no sort exists. Selecting the already-active field or direction is a no-op and does not toggle the way a header click does.",
|
|
52
|
+
"The trigger stays Sort in regular-weight resting secondary chrome. Field and direction selection live in the menu and on column headers, so the trigger never uses active primary emphasis. It keeps pressed interaction paint without physically scaling inside the stable table caption row.",
|
|
53
|
+
"Compound sortable headers contribute one Data row per segment. Action columns never appear.",
|
|
54
|
+
"The trigger automatically holds the shared surface-open wash through menu exit while the selected sort remains independently controlled.",
|
|
55
|
+
"Borderless toolbar compositions omit resting control borders while retaining focus and interaction feedback.",
|
|
56
|
+
"Expanded toolbar triggers use an icon and regular-weight text without a trailing chevron.",
|
|
57
|
+
"fields accepts a DataField catalog for any data view: a card list or map overlay supplies id, label and sortable without describing itself as a table."
|
|
58
|
+
],
|
|
59
|
+
"responsiveBehavior": [
|
|
60
|
+
"Place the control in the trailing region of ds-data-toolbar with Filter and Group.",
|
|
61
|
+
"The owning table caption or standalone data toolbar determines when the trigger becomes icon-only. A hover and keyboard-focus tooltip preserves the label, and the icon keeps the resting secondary foreground.",
|
|
62
|
+
"Long sortable-field catalogs inherit Menu's collision-aware height cap and internal choice scrolling instead of extending beyond the available viewport space."
|
|
63
|
+
],
|
|
64
|
+
"frameworkCaveats": {
|
|
65
|
+
"customElements": [
|
|
66
|
+
"Assign fields and sort as JavaScript properties. Replace sort from both dsSortChange on this control and dsSortChange on the table."
|
|
67
|
+
],
|
|
68
|
+
"react": [
|
|
69
|
+
"Keep one sort state and pass it to both ds-table and ds-data-sort; update it from either event."
|
|
70
|
+
],
|
|
71
|
+
"angular": [
|
|
72
|
+
"Import the generated DsDataSort adapter, bind fields and sort, and handle dsSortChange with the same owner that handles table header sorting."
|
|
73
|
+
]
|
|
74
|
+
},
|
|
75
|
+
"references": [
|
|
76
|
+
{
|
|
77
|
+
"label": "Storybook review states",
|
|
78
|
+
"path": "src/wc/components/DataSort/DataSort.stories.ts"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"label": "Toolbar composition owner",
|
|
82
|
+
"path": "src/wc/components/DataToolbar/DataToolbar.agent.json"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"label": "Surface ownership and trigger state",
|
|
86
|
+
"path": "src/docs/SurfaceOwnership.mdx"
|
|
87
|
+
}
|
|
88
|
+
]
|
|
89
|
+
},
|
|
90
|
+
"api": {
|
|
91
|
+
"props": {
|
|
92
|
+
"ariaLabel": {
|
|
93
|
+
"type": "string | null",
|
|
94
|
+
"resolvedType": "null | string",
|
|
95
|
+
"attribute": "aria-label",
|
|
96
|
+
"default": "null",
|
|
97
|
+
"required": false,
|
|
98
|
+
"mutable": false,
|
|
99
|
+
"description": "Accessible name for the trigger and menu."
|
|
100
|
+
},
|
|
101
|
+
"fields": {
|
|
102
|
+
"type": "DataField[]",
|
|
103
|
+
"resolvedType": "DataField[]",
|
|
104
|
+
"default": "[]",
|
|
105
|
+
"required": false,
|
|
106
|
+
"mutable": false
|
|
107
|
+
},
|
|
108
|
+
"hasBorder": {
|
|
109
|
+
"type": "boolean",
|
|
110
|
+
"resolvedType": "boolean",
|
|
111
|
+
"attribute": "has-border",
|
|
112
|
+
"default": "true",
|
|
113
|
+
"required": false,
|
|
114
|
+
"mutable": false,
|
|
115
|
+
"description": "Show the trigger border."
|
|
116
|
+
},
|
|
117
|
+
"sort": {
|
|
118
|
+
"type": "DataSortState | null",
|
|
119
|
+
"resolvedType": "DataSortState | null",
|
|
120
|
+
"default": "null",
|
|
121
|
+
"required": false,
|
|
122
|
+
"mutable": false,
|
|
123
|
+
"description": "Controlled table sort. Header sorting and this menu share the same value."
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
"events": [
|
|
127
|
+
{
|
|
128
|
+
"name": "dsSortChange",
|
|
129
|
+
"detail": "DataSortChangeDetail",
|
|
130
|
+
"bubbles": false,
|
|
131
|
+
"cancelable": true,
|
|
132
|
+
"composed": true
|
|
133
|
+
}
|
|
134
|
+
],
|
|
135
|
+
"methods": [
|
|
136
|
+
{
|
|
137
|
+
"name": "setFocus",
|
|
138
|
+
"signature": "setFocus() => Promise<void>"
|
|
139
|
+
}
|
|
140
|
+
],
|
|
141
|
+
"slots": []
|
|
142
|
+
},
|
|
143
|
+
"props": {
|
|
144
|
+
"ariaLabel": {
|
|
145
|
+
"type": "string | null",
|
|
146
|
+
"resolvedType": "null | string",
|
|
147
|
+
"attribute": "aria-label",
|
|
148
|
+
"default": "null",
|
|
149
|
+
"required": false,
|
|
150
|
+
"mutable": false,
|
|
151
|
+
"description": "Accessible name for the trigger and menu."
|
|
152
|
+
},
|
|
153
|
+
"fields": {
|
|
154
|
+
"type": "DataField[]",
|
|
155
|
+
"resolvedType": "DataField[]",
|
|
156
|
+
"default": "[]",
|
|
157
|
+
"required": false,
|
|
158
|
+
"mutable": false
|
|
159
|
+
},
|
|
160
|
+
"hasBorder": {
|
|
161
|
+
"type": "boolean",
|
|
162
|
+
"resolvedType": "boolean",
|
|
163
|
+
"attribute": "has-border",
|
|
164
|
+
"default": "true",
|
|
165
|
+
"required": false,
|
|
166
|
+
"mutable": false,
|
|
167
|
+
"description": "Show the trigger border."
|
|
168
|
+
},
|
|
169
|
+
"sort": {
|
|
170
|
+
"type": "DataSortState | null",
|
|
171
|
+
"resolvedType": "DataSortState | null",
|
|
172
|
+
"default": "null",
|
|
173
|
+
"required": false,
|
|
174
|
+
"mutable": false,
|
|
175
|
+
"description": "Controlled table sort. Header sorting and this menu share the same value."
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
"events": [
|
|
179
|
+
{
|
|
180
|
+
"name": "dsSortChange",
|
|
181
|
+
"detail": "DataSortChangeDetail",
|
|
182
|
+
"bubbles": false,
|
|
183
|
+
"cancelable": true,
|
|
184
|
+
"composed": true
|
|
185
|
+
}
|
|
186
|
+
],
|
|
187
|
+
"methods": [
|
|
188
|
+
{
|
|
189
|
+
"name": "setFocus",
|
|
190
|
+
"signature": "setFocus() => Promise<void>"
|
|
191
|
+
}
|
|
192
|
+
],
|
|
193
|
+
"slots": [],
|
|
194
|
+
"exports": {
|
|
195
|
+
"customElement": "ds-data-sort",
|
|
196
|
+
"react": "DsDataSort",
|
|
197
|
+
"vue": "DsDataSort",
|
|
198
|
+
"angular": "DsDataSort"
|
|
199
|
+
},
|
|
200
|
+
"consumption": {
|
|
201
|
+
"install": "npm install @ds-mo/ui @ds-mo/tokens @ds-mo/icons",
|
|
202
|
+
"cssSetup": "import '@ds-mo/tokens';\nimport '@ds-mo/tokens/reset';\nimport '@ds-mo/tokens/globals';",
|
|
203
|
+
"customElements": {
|
|
204
|
+
"import": "import '@ds-mo/ui/dist/components/ds-data-sort.js';",
|
|
205
|
+
"example": "<ds-data-sort></ds-data-sort>"
|
|
206
|
+
},
|
|
207
|
+
"react": {
|
|
208
|
+
"import": "import { DsDataSort } from '@ds-mo/ui/react';",
|
|
209
|
+
"example": "<DsDataSort />"
|
|
210
|
+
},
|
|
211
|
+
"vue": {
|
|
212
|
+
"import": "import { DsDataSort } from '@ds-mo/ui/vue';",
|
|
213
|
+
"example": "<DsDataSort />"
|
|
214
|
+
},
|
|
215
|
+
"angular": {
|
|
216
|
+
"import": "import { DsDataSort } from '@ds-mo/ui/angular/ds-data-sort';",
|
|
217
|
+
"example": "<ds-data-sort></ds-data-sort>"
|
|
218
|
+
},
|
|
219
|
+
"complexPropertyNote": "Assign these non-primitive values as JavaScript properties: fields, sort.",
|
|
220
|
+
"peerDependencies": {
|
|
221
|
+
"required": [
|
|
222
|
+
"@ds-mo/tokens ^6.5.1",
|
|
223
|
+
"@ds-mo/icons ^8.1.0"
|
|
224
|
+
],
|
|
225
|
+
"frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
"dependencies": [
|
|
230
|
+
"@ds-mo/ui",
|
|
231
|
+
"@ds-mo/tokens"
|
|
232
|
+
],
|
|
233
|
+
"registryDependencies": [
|
|
234
|
+
"button-unfilled",
|
|
235
|
+
"menu"
|
|
236
|
+
],
|
|
237
|
+
"files": [
|
|
238
|
+
{
|
|
239
|
+
"path": "src/wc/components/DataSort/DataSort.css",
|
|
240
|
+
"content": ":host {\n display: inline-flex;\n min-inline-size: 0;\n max-inline-size: var(--dimension-menu-width-xs);\n}\n\n:host([hidden]) {\n display: none;\n}\n",
|
|
241
|
+
"type": "registry:ui"
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
"path": "src/wc/components/DataSort/DataSort.tsx",
|
|
245
|
+
"content": "import {\n Component,\n Element,\n Event,\n EventEmitter,\n h,\n Host,\n Method,\n Prop,\n State,\n} from '@stencil/core';\nimport type { DataField } from '../../utils/data-field';\nimport type { MenuItemData } from '../Menu/menu-types';\nimport type { DataSortChangeDetail, DataSortState } from '../Table/table-types';\nimport {\n nextDataSortStateFromMenuItem,\n dataSortFields,\n dataSortMenuSections,\n dataSortStatesEqual,\n} from './data-sort-menu';\n\nlet tableSortSeq = 0;\n\n@Component({\n tag: 'ds-data-sort',\n styleUrl: 'DataSort.css',\n scoped: true,\n})\nexport class DataSort {\n @Element() private el!: HTMLElement;\n\n /** Catalog used to derive sortable fields, including compound header segments. */\n /** Show the trigger border. */\n @Prop() hasBorder: boolean = true;\n @Prop() fields: DataField[] = [];\n /** Controlled table sort. Header sorting and this menu share the same value. */\n @Prop() sort: DataSortState | null = null;\n /** Accessible name for the trigger and menu. */\n @Prop({ attribute: 'aria-label' }) ariaLabel: string | null = null;\n\n @Event({ bubbles: false }) dsSortChange!: EventEmitter<DataSortChangeDetail>;\n\n @State() private menuOpen = false;\n @State() private menuSurfaceOpen = false;\n @State() private initialFocusVisible = false;\n\n private readonly componentId = `ds-data-sort-${++tableSortSeq}`;\n private readonly triggerId = `${this.componentId}-trigger`;\n private readonly menuId = `${this.componentId}-menu`;\n\n @Method()\n async setFocus() {\n const trigger = this.el.querySelector<HTMLElement & { setFocus?: () => Promise<void> }>(\n `#${CSS.escape(this.triggerId)}`\n );\n await trigger?.setFocus?.();\n }\n\n render() {\n const fields = dataSortFields(this.fields);\n const name = this.ariaLabel?.trim() || 'Sort table';\n\n return (\n <Host hidden={fields.length === 0 ? true : undefined}>\n {fields.length === 0 ? null : (\n <ds-button-unfilled\n hasBorder={this.hasBorder}\n id={this.triggerId}\n variant=\"icon-label\"\n size=\"md\"\n icon=\"ArrowsVertical\"\n label=\"Sort\"\n labelEmphasis={false}\n pressScale={false}\n aria-label={name}\n haspopup=\"menu\"\n collapseLabel={true}\n expanded={this.menuOpen}\n surfaceOpen={this.menuSurfaceOpen}\n controls={this.menuId}\n onDsClick={(event: CustomEvent<MouseEvent>) => {\n this.toggle(event.detail.detail === 0);\n }}\n />\n )}\n {fields.length === 0 ? null : (\n <ds-menu\n id={this.menuId}\n open={this.menuOpen}\n anchorId={this.triggerId}\n align=\"start\"\n side=\"bottom\"\n menuLabel={name}\n selectionMode=\"none\"\n initialFocusVisible={this.initialFocusVisible}\n sections={dataSortMenuSections(this.fields, this.sort)}\n onDsClose={() => this.close()}\n onDsAfterClose={() => {\n if (!this.menuOpen) this.menuSurfaceOpen = false;\n }}\n onDsSelect={event => this.handleSelect(event.detail)}\n />\n )}\n </Host>\n );\n }\n\n private toggle(fromKeyboard = false): void {\n if (this.menuOpen) this.close();\n else this.open(fromKeyboard);\n }\n\n private open(fromKeyboard = false): void {\n if (this.menuOpen) return;\n this.initialFocusVisible = fromKeyboard;\n this.menuOpen = true;\n this.menuSurfaceOpen = true;\n }\n\n private close(): void {\n this.menuOpen = false;\n }\n\n private handleSelect(item: MenuItemData): void {\n const next = nextDataSortStateFromMenuItem(this.fields, this.sort, item);\n if (dataSortStatesEqual(this.sort, next)) return;\n this.dsSortChange.emit({ sort: next });\n }\n}\n",
|
|
246
|
+
"type": "registry:ui"
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
"path": "src/wc/components/DataSort/data-sort-menu.ts",
|
|
250
|
+
"content": "import type { MenuItemData, MenuSection } from '../Menu/menu-types';\nimport { isTableActionColumn } from '../Table/table-column-customizer';\nimport type { TableColumn, DataSortState } from '../Table/table-types';\n\nexport const TABLE_SORT_DIRECTION_ASC = 'direction:asc';\nexport const TABLE_SORT_DIRECTION_DESC = 'direction:desc';\nconst TABLE_SORT_FIELD_PREFIX = 'field:';\n\nexport interface TableSortField {\n id: string;\n label: string;\n}\n\n/** Sortable data fields from the catalog, including compound header segments. */\nexport function dataSortFields(columns: readonly TableColumn[]): TableSortField[] {\n const fields: TableSortField[] = [];\n const seen = new Set<string>();\n\n for (const column of columns) {\n if (isTableActionColumn(column) || !column.sortable) continue;\n const segments = column.segments?.filter(segment => segment.sortKey.trim()) ?? [];\n if (segments.length > 0) {\n for (const segment of segments) {\n if (seen.has(segment.sortKey)) continue;\n seen.add(segment.sortKey);\n fields.push({\n id: segment.sortKey,\n label: segment.dataLabel?.trim() || segment.label.trim() || segment.sortKey,\n });\n }\n continue;\n }\n if (seen.has(column.id)) continue;\n seen.add(column.id);\n fields.push({\n id: column.id,\n label:\n column.dataLabel?.trim() ||\n column.label.trim() ||\n column.accessibleLabel?.trim() ||\n column.id,\n });\n }\n\n return fields;\n}\n\nexport function dataSortMenuSections(\n columns: readonly TableColumn[],\n sort: DataSortState | null | undefined\n): MenuSection[] {\n const fields = dataSortFields(columns);\n return [\n {\n header: 'Data',\n items: fields.map(field => ({\n label: field.label,\n value: `${TABLE_SORT_FIELD_PREFIX}${encodeURIComponent(field.id)}`,\n isSelected: sort?.fieldId === field.id,\n })),\n },\n {\n header: 'Order',\n items: [\n {\n label: 'Ascending',\n value: TABLE_SORT_DIRECTION_ASC,\n icon: 'ArrowUp',\n isSelected: sort?.direction === 'asc',\n },\n {\n label: 'Descending',\n value: TABLE_SORT_DIRECTION_DESC,\n icon: 'ArrowDown',\n isSelected: sort?.direction === 'desc',\n },\n ],\n },\n ];\n}\n\nexport function dataSortStatesEqual(\n left: DataSortState | null | undefined,\n right: DataSortState | null | undefined\n): boolean {\n if (left === right) return true;\n if (!left || !right) return false;\n return left.fieldId === right.fieldId && left.direction === right.direction;\n}\n\n/** Next controlled sort from a Sort menu selection. Does not toggle like a header click. */\nexport function nextDataSortStateFromMenuItem(\n columns: readonly TableColumn[],\n current: DataSortState | null | undefined,\n item: MenuItemData\n): DataSortState | null {\n const fields = dataSortFields(columns);\n if (fields.length === 0) return current ?? null;\n\n if (item.value === TABLE_SORT_DIRECTION_ASC || item.value === TABLE_SORT_DIRECTION_DESC) {\n const direction = item.value === TABLE_SORT_DIRECTION_ASC ? 'asc' : 'desc';\n const fieldId = fields.some(field => field.id === current?.fieldId)\n ? current!.fieldId\n : fields[0]!.id;\n return { fieldId, direction };\n }\n\n if (!item.value?.startsWith(TABLE_SORT_FIELD_PREFIX)) return current ?? null;\n let fieldId: string;\n try {\n fieldId = decodeURIComponent(item.value.slice(TABLE_SORT_FIELD_PREFIX.length));\n } catch {\n return current ?? null;\n }\n if (!fields.some(field => field.id === fieldId)) return current ?? null;\n if (current?.fieldId === fieldId) return current ?? null;\n return { fieldId, direction: current?.direction ?? 'asc' };\n}\n",
|
|
251
|
+
"type": "registry:ui"
|
|
252
|
+
}
|
|
253
|
+
]
|
|
254
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
3
|
+
"name": "data-toolbar",
|
|
4
|
+
"title": "DataToolbar",
|
|
5
|
+
"description": "Shared layout for application-owned data-view controls, with a start cluster, optional search, trailing Filter/Sort/Group, and narrow-width horizontal overflow.",
|
|
6
|
+
"type": "registry:ui",
|
|
7
|
+
"meta": {
|
|
8
|
+
"library": "@ds-mo/ui",
|
|
9
|
+
"distribution": "npm",
|
|
10
|
+
"storybook": "https://zainadeel.github.io/compomo/?path=/story/data-toolbar",
|
|
11
|
+
"source": "src/wc/components/DataToolbar/DataToolbar.tsx",
|
|
12
|
+
"intentStatus": "complete",
|
|
13
|
+
"intent": {
|
|
14
|
+
"audience": "general",
|
|
15
|
+
"status": "stable",
|
|
16
|
+
"summary": "Shared layout for application-owned data-view controls, with a start cluster, optional search, trailing Filter/Sort/Group, and narrow-width horizontal overflow.",
|
|
17
|
+
"useWhen": [
|
|
18
|
+
"Several data views repeat the same saved-view cluster, middle discovery and result-shaping controls, and table-owned caption actions.",
|
|
19
|
+
"A ds-table header slot needs consistent control spacing, alignment, grouping, and narrow-width overflow without moving product behavior into the table."
|
|
20
|
+
],
|
|
21
|
+
"avoidWhen": [
|
|
22
|
+
"The controls do not operate on a table or structured result set.",
|
|
23
|
+
"The application expects the toolbar to define filters, saved views, grouping choices, persistence, or data transformations.",
|
|
24
|
+
"Only one standalone control is present and needs no grouped toolbar semantics."
|
|
25
|
+
],
|
|
26
|
+
"commonlyComposedWith": [
|
|
27
|
+
"component:ds-table",
|
|
28
|
+
"component:ds-data-saved-views",
|
|
29
|
+
"component:ds-divider",
|
|
30
|
+
"component:ds-input",
|
|
31
|
+
"component:ds-data-filter",
|
|
32
|
+
"component:ds-data-group",
|
|
33
|
+
"component:ds-select",
|
|
34
|
+
"component:ds-data-sort",
|
|
35
|
+
"component:ds-data-customize",
|
|
36
|
+
"component:ds-button-unfilled",
|
|
37
|
+
"component:ds-data-preferences"
|
|
38
|
+
],
|
|
39
|
+
"patterns": [],
|
|
40
|
+
"accessibility": [
|
|
41
|
+
"The component exposes a named toolbar while each slotted control retains its own accessible name and native keyboard behavior.",
|
|
42
|
+
"Use the start slot for saved views. Use search for the optional discovery field, leading for any additional left-side middle controls, and trailing for Filter, Sort, and Group. Table-owned column customizer and data-mode actions remain in the table caption trailing cluster and participate in the same caption overflow row.",
|
|
43
|
+
"Tab order follows authored DOM order. The toolbar does not add roving focus because it may contain heterogeneous form and popup controls."
|
|
44
|
+
],
|
|
45
|
+
"states": [
|
|
46
|
+
"The component owns layout only. It never mutates slotted control props, values, menus, loading, persistence, or consequences. Use ds-data-saved-views and ds-data-filter when those interactions need the shared CompoMo behavior while application data and persistence remain external.",
|
|
47
|
+
"Buttons in the toolbar keep their hover and pressed interaction paint without physically scaling, so pointer feedback does not disturb the stable caption geometry.",
|
|
48
|
+
"The start cluster is followed by Search, optional leading controls, and one trailing action cluster. The start cluster hides when nothing is projected. Search is a dedicated slot that hides when nothing is projected and grows to consume available row space. Empty leading or trailing clusters add no placeholder chrome. Search is the only toolbar region that grows and shrinks; all action controls retain their control geometry and align directly before the table-owned actions.",
|
|
49
|
+
"Data-mode switching remains a table-owned caption action. Column customization normally uses the table caption trigger; compact compositions use the shared ds-data-preferences control and hide that trigger. When slotted into a table header, the table caption owns overflow for the complete toolbar and table-owned action row.",
|
|
50
|
+
"Standard toolbars omit region dividers. Borderless compositions show dividers after populated start and search regions when another region follows; the application supplies borderless controls."
|
|
51
|
+
],
|
|
52
|
+
"responsiveBehavior": [
|
|
53
|
+
"The start cluster, search, trailing Filter/Sort/Group, and table caption trailing actions stay on one line. Saved views hug their current trigger content up to the compact menu-width token rather than reserving that full width; long names truncate while the dirty dot stays visible. Filter, Sort, and Group triggers cap at the same token, and Sort and Group popups keep that compact menu-width floor. A standalone toolbar owns its horizontal scrolling; inside a table, the complete caption row is the single overflow owner so table-owned actions never remain pinned over scrolling toolbar controls.",
|
|
54
|
+
"Search consumes the row space left between fixed control groups and flexes smaller when the complete row needs space. The owning table caption or standalone toolbar determines when data controls omit their labels and chevrons; each exposes its label through a hover and keyboard-focus tooltip. Empty leading and trailing slot groups do not add spacing. Active filtering retains neutral trigger colors. Group and Sort keep resting secondary chrome. Standalone Customize follows the same compact treatment; table-owned Customize remains part of the caption.",
|
|
55
|
+
"The scrollbar is visually suppressed without removing touch, trackpad, mouse-wheel, or keyboard scrolling from the overflow container.",
|
|
56
|
+
"For compact toolbars, the application can replace Filter, Sort, Group and the table Customize trigger with ds-data-preferences in the trailing slot. Share the same controlled values and events; the toolbar remains a data-agnostic layout."
|
|
57
|
+
],
|
|
58
|
+
"frameworkCaveats": {
|
|
59
|
+
"customElements": [
|
|
60
|
+
"Project saved views through slot=start, search through slot=search, additional left-side middle controls through slot=leading, and ds-data-filter, ds-data-group, and ds-data-sort through slot=trailing. Provide a contextual accessible name for the data view."
|
|
61
|
+
],
|
|
62
|
+
"react": [
|
|
63
|
+
"Set slot=start, slot=search, slot=leading, or slot=trailing on each child control. Use ds-data-filter and ds-data-group for the standard Filter and Group recipes, and keep values and event handlers in the application."
|
|
64
|
+
],
|
|
65
|
+
"angular": [
|
|
66
|
+
"Set slot=start, slot=search, slot=leading, or slot=trailing on each child control, use DsDataFilter and DsDataGroup for the standard Filter and Group recipes, and import the generated adapters."
|
|
67
|
+
]
|
|
68
|
+
},
|
|
69
|
+
"references": [
|
|
70
|
+
{
|
|
71
|
+
"label": "Storybook review states",
|
|
72
|
+
"path": "src/wc/components/DataToolbar/DataToolbar.stories.ts"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"label": "Table composition owner",
|
|
76
|
+
"path": "src/wc/components/Table/Table.agent.json"
|
|
77
|
+
}
|
|
78
|
+
]
|
|
79
|
+
},
|
|
80
|
+
"api": {
|
|
81
|
+
"props": {
|
|
82
|
+
"borderless": {
|
|
83
|
+
"type": "boolean",
|
|
84
|
+
"resolvedType": "boolean",
|
|
85
|
+
"attribute": "borderless",
|
|
86
|
+
"default": "false",
|
|
87
|
+
"required": false,
|
|
88
|
+
"mutable": false,
|
|
89
|
+
"description": "Use separators between regions when composing borderless controls."
|
|
90
|
+
},
|
|
91
|
+
"label": {
|
|
92
|
+
"type": "string",
|
|
93
|
+
"resolvedType": "string",
|
|
94
|
+
"attribute": "label",
|
|
95
|
+
"default": "'Controls'",
|
|
96
|
+
"required": false,
|
|
97
|
+
"mutable": false,
|
|
98
|
+
"description": "Accessible name for the grouped controls. Pass a contextual name such as Table controls or Map controls."
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
"events": [],
|
|
102
|
+
"methods": [],
|
|
103
|
+
"slots": []
|
|
104
|
+
},
|
|
105
|
+
"props": {
|
|
106
|
+
"borderless": {
|
|
107
|
+
"type": "boolean",
|
|
108
|
+
"resolvedType": "boolean",
|
|
109
|
+
"attribute": "borderless",
|
|
110
|
+
"default": "false",
|
|
111
|
+
"required": false,
|
|
112
|
+
"mutable": false,
|
|
113
|
+
"description": "Use separators between regions when composing borderless controls."
|
|
114
|
+
},
|
|
115
|
+
"label": {
|
|
116
|
+
"type": "string",
|
|
117
|
+
"resolvedType": "string",
|
|
118
|
+
"attribute": "label",
|
|
119
|
+
"default": "'Controls'",
|
|
120
|
+
"required": false,
|
|
121
|
+
"mutable": false,
|
|
122
|
+
"description": "Accessible name for the grouped controls. Pass a contextual name such as Table controls or Map controls."
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
"events": [],
|
|
126
|
+
"methods": [],
|
|
127
|
+
"slots": [],
|
|
128
|
+
"exports": {
|
|
129
|
+
"customElement": "ds-data-toolbar",
|
|
130
|
+
"react": "DsDataToolbar",
|
|
131
|
+
"vue": "DsDataToolbar",
|
|
132
|
+
"angular": "DsDataToolbar"
|
|
133
|
+
},
|
|
134
|
+
"consumption": {
|
|
135
|
+
"install": "npm install @ds-mo/ui @ds-mo/tokens @ds-mo/icons",
|
|
136
|
+
"cssSetup": "import '@ds-mo/tokens';\nimport '@ds-mo/tokens/reset';\nimport '@ds-mo/tokens/globals';",
|
|
137
|
+
"customElements": {
|
|
138
|
+
"import": "import '@ds-mo/ui/dist/components/ds-data-toolbar.js';",
|
|
139
|
+
"example": "<ds-data-toolbar></ds-data-toolbar>"
|
|
140
|
+
},
|
|
141
|
+
"react": {
|
|
142
|
+
"import": "import { DsDataToolbar } from '@ds-mo/ui/react';",
|
|
143
|
+
"example": "<DsDataToolbar />"
|
|
144
|
+
},
|
|
145
|
+
"vue": {
|
|
146
|
+
"import": "import { DsDataToolbar } from '@ds-mo/ui/vue';",
|
|
147
|
+
"example": "<DsDataToolbar />"
|
|
148
|
+
},
|
|
149
|
+
"angular": {
|
|
150
|
+
"import": "import { DsDataToolbar } from '@ds-mo/ui/angular/ds-data-toolbar';",
|
|
151
|
+
"example": "<ds-data-toolbar></ds-data-toolbar>"
|
|
152
|
+
},
|
|
153
|
+
"peerDependencies": {
|
|
154
|
+
"required": [
|
|
155
|
+
"@ds-mo/tokens ^6.5.1",
|
|
156
|
+
"@ds-mo/icons ^8.1.0"
|
|
157
|
+
],
|
|
158
|
+
"frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
"dependencies": [
|
|
163
|
+
"@ds-mo/ui",
|
|
164
|
+
"@ds-mo/tokens"
|
|
165
|
+
],
|
|
166
|
+
"registryDependencies": [
|
|
167
|
+
"divider"
|
|
168
|
+
],
|
|
169
|
+
"files": [
|
|
170
|
+
{
|
|
171
|
+
"path": "src/wc/components/DataToolbar/DataToolbar.css",
|
|
172
|
+
"content": ":host {\n --ds-control-press-active-scale: var(--dimension-scale-default);\n\n display: block;\n min-inline-size: 0;\n max-inline-size: 100%;\n}\n\n/* A table caption owns overflow for the complete application + table control row. */\n:host([slot='header']) {\n display: contents;\n max-inline-size: none;\n}\n\n.data-toolbar {\n box-sizing: border-box;\n display: flex;\n align-items: center;\n inline-size: 100%;\n min-inline-size: 0;\n gap: var(--dimension-space-100);\n overflow-x: auto;\n overflow-y: hidden;\n scrollbar-width: none;\n}\n\n:host([slot='header']) .data-toolbar {\n display: contents;\n}\n\n.data-toolbar::-webkit-scrollbar {\n display: none;\n}\n\n.data-toolbar__start,\n.data-toolbar__search,\n.data-toolbar__leading,\n.data-toolbar__trailing {\n display: flex;\n align-items: center;\n min-inline-size: 0;\n gap: var(--dimension-space-100);\n}\n\n.data-toolbar__start {\n flex: 0 0 auto;\n min-inline-size: 0;\n max-inline-size: var(--dimension-menu-width-xs);\n overflow: hidden;\n}\n\n.data-toolbar__rule {\n flex: 0 0 auto;\n}\n\n.data-toolbar__search {\n flex: 1 1 0;\n max-inline-size: none;\n contain: inline-size;\n}\n\n.data-toolbar__slot--empty {\n display: none;\n}\n\n.data-toolbar__leading {\n flex: 0 0 auto;\n}\n\n.data-toolbar__trailing {\n flex: 0 0 auto;\n margin-inline-start: auto;\n}\n\n.data-toolbar__trailing > *,\n.data-toolbar [slot='start'],\n.data-toolbar ds-data-filter,\n.data-toolbar ds-filter-menu,\n.data-toolbar ds-select,\n.data-toolbar ds-data-group,\n.data-toolbar ds-data-sort {\n min-inline-size: 0;\n max-inline-size: var(--dimension-menu-width-xs);\n --ds-choice-popup-min-inline-size: var(--dimension-menu-width-xs);\n}\n\n.data-toolbar__trailing > * {\n flex: 0 0 auto;\n}\n\n.data-toolbar__start slot,\n.data-toolbar__search slot,\n.data-toolbar__leading slot,\n.data-toolbar__trailing slot {\n display: contents;\n}\n",
|
|
173
|
+
"type": "registry:ui"
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
"path": "src/wc/components/DataToolbar/DataToolbar.tsx",
|
|
177
|
+
"content": "import { Component, Element, h, Host, Prop, State } from '@stencil/core';\n\nconst TOOLBAR_SLOT_START = 1 << 0;\nconst TOOLBAR_SLOT_SEARCH = 1 << 1;\nconst TOOLBAR_SLOT_LEADING = 1 << 2;\nconst TOOLBAR_SLOT_TRAILING = 1 << 3;\n\n@Component({\n tag: 'ds-data-toolbar',\n styleUrl: 'DataToolbar.css',\n scoped: true,\n})\nexport class DataToolbar {\n @Element() el!: HTMLElement;\n\n /** Accessible name for the grouped controls. Pass a contextual name such as Table controls or Map controls. */\n @Prop() label: string = 'Controls';\n\n /** Use separators between regions when composing borderless controls. */\n @Prop() borderless: boolean = false;\n\n @State() private slotPresence = 0;\n\n componentWillLoad(): void {\n this.syncSlotPresence();\n }\n\n private hasOwnedSlot(name: string): boolean {\n return Array.from(this.el.querySelectorAll<HTMLElement>(`[slot=\"${name}\"]`)).some(\n element => element.closest('ds-data-toolbar') === this.el\n );\n }\n\n private syncSlotPresence = () => {\n let presence = 0;\n if (this.hasOwnedSlot('start')) presence |= TOOLBAR_SLOT_START;\n if (this.hasOwnedSlot('search')) presence |= TOOLBAR_SLOT_SEARCH;\n if (this.hasOwnedSlot('leading')) presence |= TOOLBAR_SLOT_LEADING;\n if (this.hasOwnedSlot('trailing')) presence |= TOOLBAR_SLOT_TRAILING;\n if (presence !== this.slotPresence) this.slotPresence = presence;\n };\n\n render() {\n const hasStart = (this.slotPresence & TOOLBAR_SLOT_START) !== 0;\n const hasSearch = (this.slotPresence & TOOLBAR_SLOT_SEARCH) !== 0;\n const hasLeading = (this.slotPresence & TOOLBAR_SLOT_LEADING) !== 0;\n const hasTrailing = (this.slotPresence & TOOLBAR_SLOT_TRAILING) !== 0;\n\n return (\n <Host>\n <div class=\"data-toolbar\" role=\"toolbar\" aria-label={this.label}>\n <div\n class={{\n 'data-toolbar__start': true,\n 'data-toolbar__slot--empty': !hasStart,\n }}\n >\n <slot name=\"start\" onSlotchange={this.syncSlotPresence} />\n </div>\n <ds-divider\n class={{\n 'data-toolbar__rule': true,\n 'data-toolbar__slot--empty':\n !this.borderless || !hasStart || !(hasSearch || hasLeading || hasTrailing),\n }}\n orientation=\"vertical\"\n length=\"var(--dimension-space-250)\"\n />\n <div\n class={{\n 'data-toolbar__search': true,\n 'data-toolbar__slot--empty': !hasSearch,\n }}\n >\n <slot name=\"search\" onSlotchange={this.syncSlotPresence} />\n </div>\n <ds-divider\n class={{\n 'data-toolbar__rule': true,\n 'data-toolbar__slot--empty':\n !this.borderless || !hasSearch || !(hasLeading || hasTrailing),\n }}\n orientation=\"vertical\"\n length=\"var(--dimension-space-250)\"\n />\n <div\n class={{\n 'data-toolbar__leading': true,\n 'data-toolbar__slot--empty': !hasLeading,\n }}\n >\n <slot name=\"leading\" onSlotchange={this.syncSlotPresence} />\n </div>\n <div\n class={{\n 'data-toolbar__trailing': true,\n 'data-toolbar__slot--empty': !hasTrailing,\n }}\n >\n <slot name=\"trailing\" onSlotchange={this.syncSlotPresence} />\n </div>\n </div>\n </Host>\n );\n }\n}\n",
|
|
178
|
+
"type": "registry:ui"
|
|
179
|
+
}
|
|
180
|
+
]
|
|
181
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
3
3
|
"name": "field",
|
|
4
4
|
"title": "Field",
|
|
5
|
-
"description": "Accessible form-field composition that gives one Input, Textarea, or Select
|
|
5
|
+
"description": "Accessible form-field composition that gives one Input, InputDate, InputTime, Textarea, or Select an optional visible label, optional guidance, shared error presentation, stable IDs, and observable interaction state.",
|
|
6
6
|
"type": "registry:ui",
|
|
7
7
|
"meta": {
|
|
8
8
|
"library": "@ds-mo/ui",
|
|
@@ -13,9 +13,10 @@
|
|
|
13
13
|
"intent": {
|
|
14
14
|
"audience": "general",
|
|
15
15
|
"status": "stable",
|
|
16
|
-
"summary": "Accessible form-field composition that gives one Input, Textarea, or Select
|
|
16
|
+
"summary": "Accessible form-field composition that gives one Input, InputDate, InputTime, Textarea, or Select an optional visible label, optional guidance, shared error presentation, stable IDs, and observable interaction state.",
|
|
17
17
|
"useWhen": [
|
|
18
|
-
"An Input, Textarea, or Select needs a persistent visible label in a form.",
|
|
18
|
+
"An Input, InputDate, InputTime, Textarea, or Select needs a persistent visible label in a form.",
|
|
19
|
+
"A nearby heading already names the field, and the control still needs Field's error association and message rhythm.",
|
|
19
20
|
"Help text or an error message must be programmatically associated with one control.",
|
|
20
21
|
"A form layout needs one consistent label-control-message rhythm."
|
|
21
22
|
],
|
|
@@ -33,19 +34,23 @@
|
|
|
33
34
|
],
|
|
34
35
|
"commonlyComposedWith": [
|
|
35
36
|
"component:ds-input",
|
|
37
|
+
"component:ds-input-date",
|
|
38
|
+
"component:ds-input-time",
|
|
36
39
|
"component:ds-textarea",
|
|
37
40
|
"component:ds-select",
|
|
38
41
|
"component:ds-text"
|
|
39
42
|
],
|
|
40
43
|
"accessibility": [
|
|
41
|
-
"Slot exactly one form control. Field assigns its stable control ID and connects
|
|
44
|
+
"Slot exactly one form control. When a visible label is provided, Field assigns its stable control ID and connects that label automatically.",
|
|
45
|
+
"Omit the visible label when a nearby heading already names the field. Keep a programmatic name on the slotted control, such as aria-label, and do not set aria-labelledby to an empty value.",
|
|
42
46
|
"The visible description or error ID is merged with any authored aria-describedby references; a rendered error replaces the description.",
|
|
43
47
|
"The error prop forwards aria-invalid and supported design-system control error styling; put visible error text on Field, not again on the child control.",
|
|
44
48
|
"Clicking the label focuses the slotted design-system control without opening a Select popup.",
|
|
45
49
|
"Do not use placeholder text as the only label. Keep label text concise and put format or consequence guidance in description."
|
|
46
50
|
],
|
|
47
51
|
"states": [
|
|
48
|
-
"
|
|
52
|
+
"The visible label is optional. Omit it when a nearby heading already names the field; Field still associates description and error text with the slotted control.",
|
|
53
|
+
"Label, control, description, and error content follow the shared 4px vertical field flow without changing the slotted control's width or semantics. When the slotted control is borderless, description and error copy inset to that control's text origin instead of the resting bordered edge.",
|
|
49
54
|
"Field exposes data-focused, data-filled, data-dirty, data-touched, data-invalid, data-disabled, and data-required hooks while the slotted control remains the source of value and interaction behavior.",
|
|
50
55
|
"A rendered error replaces the description; preserve essential guidance in the error message so users retain what they need to correct the field.",
|
|
51
56
|
"Field owns validation presentation but not validation timing; the form decides when to set error and errorMessage.",
|
|
@@ -61,7 +66,7 @@
|
|
|
61
66
|
"Assign child component values and option arrays through their normal JavaScript properties."
|
|
62
67
|
],
|
|
63
68
|
"react": [
|
|
64
|
-
"Compose one DsInput, DsTextarea, or DsSelect child and control validation timing in the form owner."
|
|
69
|
+
"Compose one DsInput, DsInputDate, DsInputTime, DsTextarea, or DsSelect child and control validation timing in the form owner."
|
|
65
70
|
],
|
|
66
71
|
"angular": [
|
|
67
72
|
"Compose the generated Field adapter around the control adapter and its matching Angular value accessor."
|
|
@@ -115,11 +120,11 @@
|
|
|
115
120
|
},
|
|
116
121
|
"label": {
|
|
117
122
|
"type": "string",
|
|
118
|
-
"resolvedType": "string",
|
|
123
|
+
"resolvedType": "string | undefined",
|
|
119
124
|
"attribute": "label",
|
|
120
|
-
"required":
|
|
125
|
+
"required": false,
|
|
121
126
|
"mutable": false,
|
|
122
|
-
"description": "
|
|
127
|
+
"description": "Visible label for the slotted control. Omit when a nearby heading already names the field."
|
|
123
128
|
}
|
|
124
129
|
},
|
|
125
130
|
"events": [],
|
|
@@ -162,11 +167,11 @@
|
|
|
162
167
|
},
|
|
163
168
|
"label": {
|
|
164
169
|
"type": "string",
|
|
165
|
-
"resolvedType": "string",
|
|
170
|
+
"resolvedType": "string | undefined",
|
|
166
171
|
"attribute": "label",
|
|
167
|
-
"required":
|
|
172
|
+
"required": false,
|
|
168
173
|
"mutable": false,
|
|
169
|
-
"description": "
|
|
174
|
+
"description": "Visible label for the slotted control. Omit when a nearby heading already names the field."
|
|
170
175
|
}
|
|
171
176
|
},
|
|
172
177
|
"events": [],
|
|
@@ -200,7 +205,7 @@
|
|
|
200
205
|
"peerDependencies": {
|
|
201
206
|
"required": [
|
|
202
207
|
"@ds-mo/tokens ^6.5.1",
|
|
203
|
-
"@ds-mo/icons ^
|
|
208
|
+
"@ds-mo/icons ^8.1.0"
|
|
204
209
|
],
|
|
205
210
|
"frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
|
|
206
211
|
}
|
|
@@ -216,12 +221,12 @@
|
|
|
216
221
|
"files": [
|
|
217
222
|
{
|
|
218
223
|
"path": "src/wc/components/Field/Field.css",
|
|
219
|
-
"content": "@import '../../utils/field-stack.css';\n\n:host {\n display: block;\n}\n\n.field__control {\n display: flex;\n min-width: 0;\n}\n\n.field__control > * {\n width: 100%;\n}\n",
|
|
224
|
+
"content": "@import '../../utils/control-density.css';\n@import '../../utils/field-stack.css';\n\n:host {\n display: block;\n}\n\n.field__control {\n display: flex;\n min-width: 0;\n}\n\n.field__control > * {\n width: 100%;\n}\n",
|
|
220
225
|
"type": "registry:ui"
|
|
221
226
|
},
|
|
222
227
|
{
|
|
223
228
|
"path": "src/wc/components/Field/Field.tsx",
|
|
224
|
-
"content": "import { Component, Element, Prop, State, Watch, h, Host } from '@stencil/core';\n\ninterface FieldControl extends HTMLElement {\n value?: string | string[];\n inputId?: string;\n error?: boolean;\n disabled?: boolean;\n isInactive?: boolean;\n required?: boolean;\n setFocus?: () => Promise<void> | void;\n}\n\ninterface AuthoredAria {\n labelledby: string[];\n describedby: string[];\n}\n\nlet fieldCounter = 0;\n\nconst tokens = (value: string | null | undefined): string[] =>\n value?.split(/\\s+/).filter(Boolean) ?? [];\n\nconst uniqueTokens = (...groups: string[][]): string[] => [...new Set(groups.flat())];\n\n@Component({\n tag: 'ds-field',\n styleUrl: 'Field.css',\n scoped: true,\n})\nexport class Field {\n @Element() el!: HTMLElement;\n\n /** Persistent visible label for the single slotted control. */\n @Prop() label!: string;\n /** Explicit ID for the slotted control; generated when omitted. */\n @Prop() fieldId: string | undefined;\n /** Optional guidance associated with the slotted control while no visible error is shown. */\n @Prop() description: string | undefined;\n /** Invalid visual and accessible state forwarded to supported ds controls. */\n @Prop() error: boolean = false;\n /** Visible error associated with the slotted control while error is true. */\n @Prop() errorMessage: string | undefined;\n\n @State() private focused = false;\n @State() private filled = false;\n @State() private dirty = false;\n @State() private touched = false;\n @State() private controlDisabled = false;\n @State() private controlRequired = false;\n /** Bumped to let Stencil relocate a control added after the initial render. */\n @State() private slotRevision = 0;\n\n private readonly generatedId = `ds-field-${++fieldCounter}`;\n private controlContainer?: HTMLDivElement;\n private control?: FieldControl;\n private initialValue = '';\n private authoredAria = new WeakMap<FieldControl, AuthoredAria>();\n private childObserver?: MutationObserver;\n private didLoad = false;\n\n connectedCallback() {\n if (this.didLoad) this.observeLateControls();\n }\n\n disconnectedCallback() {\n this.childObserver?.disconnect();\n this.childObserver = undefined;\n }\n\n componentDidLoad() {\n this.syncControl();\n this.didLoad = true;\n this.observeLateControls();\n requestAnimationFrame(() => this.syncControl());\n }\n\n componentDidRender() {\n this.syncControl();\n }\n\n @Watch('fieldId')\n @Watch('description')\n @Watch('error')\n @Watch('errorMessage')\n onFieldContractChange() {\n this.syncControl();\n }\n\n private get controlId(): string {\n return this.fieldId || this.generatedId;\n }\n\n private get labelId(): string {\n return `${this.controlId}-label`;\n }\n\n private get descriptionId(): string {\n return `${this.controlId}-description`;\n }\n\n private get errorId(): string {\n return `${this.controlId}-error`;\n }\n\n private get renderedDescription(): boolean {\n return Boolean(this.description) && !this.renderedError;\n }\n\n private get renderedError(): boolean {\n return this.error && Boolean(this.errorMessage);\n }\n\n private readValue(control: FieldControl): string {\n const value = control.value;\n return Array.isArray(value) ? value.join('\\u001f') : String(value ?? '');\n }\n\n private updateControlAttribute(control: FieldControl, name: string, value: string | undefined) {\n if (value === undefined) {\n if (control.hasAttribute(name)) control.removeAttribute(name);\n return;\n }\n if (control.getAttribute(name) !== value) control.setAttribute(name, value);\n }\n\n private findControl(): FieldControl | undefined {\n return this.controlContainer?.querySelector<FieldControl>(':scope > :not(slot)') ?? undefined;\n }\n\n private observeLateControls() {\n if (this.childObserver || typeof MutationObserver === 'undefined') return;\n this.childObserver = new MutationObserver(records => {\n const addedControl = records.some(record =>\n Array.from(record.addedNodes).some(node => node.nodeType === 1)\n );\n if (addedControl) this.slotRevision++;\n });\n this.childObserver.observe(this.el, { childList: true });\n }\n\n private syncControl = () => {\n const control = this.findControl();\n if (!control) return;\n\n if (control !== this.control) {\n this.control = control;\n this.initialValue = this.readValue(control);\n this.authoredAria.set(control, {\n labelledby: tokens(control.getAttribute('aria-labelledby')),\n describedby: tokens(control.getAttribute('aria-describedby')),\n });\n }\n\n const isDsControl = control.tagName.startsWith('DS-');\n if (isDsControl && 'inputId' in control) control.inputId = this.controlId;\n else this.updateControlAttribute(control, 'id', this.controlId);\n\n const authored = this.authoredAria.get(control) ?? { labelledby: [], describedby: [] };\n const labelledby = uniqueTokens(authored.labelledby, [this.labelId]).join(' ');\n const describedby = uniqueTokens(\n authored.describedby,\n this.renderedDescription ? [this.descriptionId] : [],\n this.renderedError ? [this.errorId] : []\n ).join(' ');\n\n this.updateControlAttribute(control, 'aria-labelledby', labelledby);\n this.updateControlAttribute(control, 'aria-describedby', describedby || undefined);\n this.updateControlAttribute(control, 'aria-invalid', this.error ? 'true' : undefined);\n\n if (isDsControl && 'error' in control && control.error !== this.error)\n control.error = this.error;\n\n const value = this.readValue(control);\n this.filled = value.length > 0;\n this.dirty = value !== this.initialValue;\n this.controlDisabled = Boolean(\n control.disabled || control.isInactive || control.hasAttribute('disabled')\n );\n this.controlRequired = Boolean(control.required || control.hasAttribute('required'));\n };\n\n private handleLabelClick = (event: MouseEvent) => {\n if (!this.control?.tagName.startsWith('DS-')) return;\n event.preventDefault();\n this.control.setFocus?.();\n };\n\n private handleFocusIn = () => {\n this.focused = true;\n };\n\n private handleFocusOut = (event: FocusEvent) => {\n if (event.relatedTarget instanceof Node && this.el.contains(event.relatedTarget)) return;\n this.focused = false;\n this.touched = true;\n };\n\n private handleValueChange = () => {\n this.syncControl();\n };\n\n render() {\n return (\n <Host\n data-focused={this.focused ? '' : undefined}\n data-filled={this.filled ? '' : undefined}\n data-dirty={this.dirty ? '' : undefined}\n data-touched={this.touched ? '' : undefined}\n data-invalid={this.error ? '' : undefined}\n data-disabled={this.controlDisabled ? '' : undefined}\n data-required={this.controlRequired ? '' : undefined}\n onFocusin={this.handleFocusIn}\n onFocusout={this.handleFocusOut}\n onInput={this.handleValueChange}\n onChange={this.handleValueChange}\n onDsChange={this.handleValueChange}\n >\n <div class=\"field ds-field-stack\">\n <ds-text\n class=\"field__label\"\n as=\"label\"\n variant=\"text-body-small\"\n color=\"primary\"\n emphasis\n for={this.controlId}\n textId={this.labelId}\n onClick={this.handleLabelClick}\n >\n {this.label}\n </ds-text>\n <div class=\"field__control\" ref={el => (this.controlContainer = el)}>\n <slot onSlotchange={this.syncControl} />\n </div>\n {this.renderedDescription && (\n <ds-text\n class=\"field__description\"\n as=\"div\"\n variant=\"text-body-small\"\n color=\"secondary\"\n textId={this.descriptionId}\n >\n {this.description}\n </ds-text>\n )}\n {this.renderedError && (\n <ds-text\n class=\"field__error\"\n as=\"div\"\n variant=\"text-body-small\"\n color=\"negative\"\n textId={this.errorId}\n role=\"alert\"\n >\n {this.errorMessage}\n </ds-text>\n )}\n </div>\n </Host>\n );\n }\n}\n",
|
|
229
|
+
"content": "import { Component, Element, Prop, State, Watch, h, Host } from '@stencil/core';\n\ninterface FieldControl extends HTMLElement {\n value?: string | string[];\n inputId?: string;\n error?: boolean;\n disabled?: boolean;\n isInactive?: boolean;\n required?: boolean;\n hasBorder?: boolean;\n size?: string;\n setFocus?: () => Promise<void> | void;\n}\n\ninterface AuthoredAria {\n labelledby: string[];\n describedby: string[];\n}\n\nlet fieldCounter = 0;\n\nconst tokens = (value: string | null | undefined): string[] =>\n value?.split(/\\s+/).filter(Boolean) ?? [];\n\nconst uniqueTokens = (...groups: string[][]): string[] => [...new Set(groups.flat())];\n\nconst CONTROL_SIZES = ['lg', 'md', 'sm', 'xs'] as const;\ntype FieldControlSize = (typeof CONTROL_SIZES)[number];\n\nconst readControlSize = (control: FieldControl): FieldControlSize =>\n CONTROL_SIZES.includes(control.size as FieldControlSize)\n ? (control.size as FieldControlSize)\n : 'md';\n\n@Component({\n tag: 'ds-field',\n styleUrl: 'Field.css',\n scoped: true,\n})\nexport class Field {\n @Element() el!: HTMLElement;\n\n /** Visible label for the slotted control. Omit when a nearby heading already names the field. */\n @Prop() label?: string;\n /** Explicit ID for the slotted control; generated when omitted. */\n @Prop() fieldId: string | undefined;\n /** Optional guidance associated with the slotted control while no visible error is shown. */\n @Prop() description: string | undefined;\n /** Invalid visual and accessible state forwarded to supported ds controls. */\n @Prop() error: boolean = false;\n /** Visible error associated with the slotted control while error is true. */\n @Prop() errorMessage: string | undefined;\n\n @State() private focused = false;\n @State() private filled = false;\n @State() private dirty = false;\n @State() private touched = false;\n @State() private controlDisabled = false;\n @State() private controlRequired = false;\n @State() private controlBorderless = false;\n @State() private controlSize: 'lg' | 'md' | 'sm' | 'xs' = 'md';\n /** Bumped to let Stencil relocate a control added after the initial render. */\n @State() private slotRevision = 0;\n\n private readonly generatedId = `ds-field-${++fieldCounter}`;\n private controlContainer?: HTMLDivElement;\n private control?: FieldControl;\n private initialValue = '';\n private authoredAria = new WeakMap<FieldControl, AuthoredAria>();\n private childObserver?: MutationObserver;\n private controlAttrObserver?: MutationObserver;\n private didLoad = false;\n\n connectedCallback() {\n if (this.didLoad) this.observeLateControls();\n }\n\n disconnectedCallback() {\n this.childObserver?.disconnect();\n this.childObserver = undefined;\n this.controlAttrObserver?.disconnect();\n this.controlAttrObserver = undefined;\n }\n\n componentDidLoad() {\n this.syncControl();\n this.didLoad = true;\n this.observeLateControls();\n requestAnimationFrame(() => this.syncControl());\n }\n\n componentDidRender() {\n this.syncControl();\n }\n\n @Watch('fieldId')\n @Watch('label')\n @Watch('description')\n @Watch('error')\n @Watch('errorMessage')\n onFieldContractChange() {\n this.syncControl();\n }\n\n private get hasLabel(): boolean {\n return Boolean(this.label?.trim());\n }\n\n private get controlId(): string {\n return this.fieldId || this.generatedId;\n }\n\n private get labelId(): string {\n return `${this.controlId}-label`;\n }\n\n private get descriptionId(): string {\n return `${this.controlId}-description`;\n }\n\n private get errorId(): string {\n return `${this.controlId}-error`;\n }\n\n private get renderedDescription(): boolean {\n return Boolean(this.description) && !this.renderedError;\n }\n\n private get renderedError(): boolean {\n return this.error && Boolean(this.errorMessage);\n }\n\n private readValue(control: FieldControl): string {\n const value = control.value;\n return Array.isArray(value) ? value.join('\\u001f') : String(value ?? '');\n }\n\n private updateControlAttribute(control: FieldControl, name: string, value: string | undefined) {\n if (value === undefined) {\n if (control.hasAttribute(name)) control.removeAttribute(name);\n return;\n }\n if (control.getAttribute(name) !== value) control.setAttribute(name, value);\n }\n\n private findControl(): FieldControl | undefined {\n return this.controlContainer?.querySelector<FieldControl>(':scope > :not(slot)') ?? undefined;\n }\n\n private observeLateControls() {\n if (this.childObserver || typeof MutationObserver === 'undefined') return;\n this.childObserver = new MutationObserver(records => {\n const addedControl = records.some(record =>\n Array.from(record.addedNodes).some(node => node.nodeType === 1)\n );\n if (addedControl) this.slotRevision++;\n });\n this.childObserver.observe(this.el, { childList: true });\n }\n\n private syncControl = () => {\n const control = this.findControl();\n if (!control) return;\n\n if (control !== this.control) {\n this.control = control;\n this.initialValue = this.readValue(control);\n this.authoredAria.set(control, {\n labelledby: tokens(control.getAttribute('aria-labelledby')),\n describedby: tokens(control.getAttribute('aria-describedby')),\n });\n this.observeControlAttributes(control);\n }\n\n const isDsControl = control.tagName.startsWith('DS-');\n if (isDsControl && 'inputId' in control) control.inputId = this.controlId;\n else this.updateControlAttribute(control, 'id', this.controlId);\n\n const authored = this.authoredAria.get(control) ?? { labelledby: [], describedby: [] };\n const labelledby = uniqueTokens(authored.labelledby, this.hasLabel ? [this.labelId] : []).join(\n ' '\n );\n const describedby = uniqueTokens(\n authored.describedby,\n this.renderedDescription ? [this.descriptionId] : [],\n this.renderedError ? [this.errorId] : []\n ).join(' ');\n\n this.updateControlAttribute(control, 'aria-labelledby', labelledby || undefined);\n this.updateControlAttribute(control, 'aria-describedby', describedby || undefined);\n this.updateControlAttribute(control, 'aria-invalid', this.error ? 'true' : undefined);\n\n if (isDsControl && 'error' in control && control.error !== this.error)\n control.error = this.error;\n\n const value = this.readValue(control);\n this.filled = value.length > 0;\n this.dirty = value !== this.initialValue;\n this.controlDisabled = Boolean(\n control.disabled || control.isInactive || control.hasAttribute('disabled')\n );\n this.controlRequired = Boolean(control.required || control.hasAttribute('required'));\n this.controlBorderless = control.hasBorder === false;\n this.controlSize = readControlSize(control);\n };\n\n private observeControlAttributes(control: FieldControl) {\n this.controlAttrObserver?.disconnect();\n this.controlAttrObserver = new MutationObserver(() => this.syncControl());\n this.controlAttrObserver.observe(control, {\n attributes: true,\n attributeFilter: ['has-border', 'size', 'class'],\n });\n }\n\n private handleLabelClick = (event: MouseEvent) => {\n if (!this.control?.tagName.startsWith('DS-')) return;\n event.preventDefault();\n this.control.setFocus?.();\n };\n\n private handleFocusIn = () => {\n this.focused = true;\n };\n\n private handleFocusOut = (event: FocusEvent) => {\n if (event.relatedTarget instanceof Node && this.el.contains(event.relatedTarget)) return;\n this.focused = false;\n this.touched = true;\n };\n\n private handleValueChange = () => {\n this.syncControl();\n };\n\n render() {\n return (\n <Host\n data-focused={this.focused ? '' : undefined}\n data-filled={this.filled ? '' : undefined}\n data-dirty={this.dirty ? '' : undefined}\n data-touched={this.touched ? '' : undefined}\n data-invalid={this.error ? '' : undefined}\n data-disabled={this.controlDisabled ? '' : undefined}\n data-required={this.controlRequired ? '' : undefined}\n onFocusin={this.handleFocusIn}\n onFocusout={this.handleFocusOut}\n onInput={this.handleValueChange}\n onChange={this.handleValueChange}\n onDsChange={this.handleValueChange}\n >\n <div\n class={{\n field: true,\n 'ds-field-stack': true,\n 'ds-field-stack--supporting-inset': this.controlBorderless,\n [`ds-control--${this.controlSize}`]: true,\n }}\n >\n {this.hasLabel ? (\n <ds-text\n class=\"field__label\"\n as=\"label\"\n variant=\"text-body-small\"\n color=\"primary\"\n emphasis\n for={this.controlId}\n textId={this.labelId}\n onClick={this.handleLabelClick}\n >\n {this.label}\n </ds-text>\n ) : null}\n <div class=\"field__control\" ref={el => (this.controlContainer = el)}>\n <slot onSlotchange={this.syncControl} />\n </div>\n {this.renderedDescription && (\n <ds-text\n class=\"field__description\"\n as=\"div\"\n variant=\"text-body-small\"\n color=\"secondary\"\n textId={this.descriptionId}\n >\n {this.description}\n </ds-text>\n )}\n {this.renderedError && (\n <ds-text\n class=\"field__error\"\n as=\"div\"\n variant=\"text-body-small\"\n color=\"negative\"\n textId={this.errorId}\n role=\"alert\"\n >\n {this.errorMessage}\n </ds-text>\n )}\n </div>\n </Host>\n );\n }\n}\n",
|
|
225
230
|
"type": "registry:ui"
|
|
226
231
|
}
|
|
227
232
|
]
|