@mono-lit/helper 0.0.0-stage → 0.0.1
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/LICENSE.md +55 -0
- package/README.md +34 -2
- package/dist/breakpoints-CAbhDUht.js +84 -0
- package/dist/checkbox-Cqpie9Ap.js +4 -0
- package/dist/chip-DBUUa2eB.js +4 -0
- package/dist/chip-limits-BMoO31JM.js +213 -0
- package/dist/chip-strip-Cw3gyz0q.js +213 -0
- package/dist/color-DHYrfXsX.js +253 -0
- package/dist/css-class-BRKRzHx-.js +60 -0
- package/dist/css-size-DhHSVZJK.js +37 -0
- package/dist/data/theme/presets.json.d.ts +140 -0
- package/dist/data-search-Bwo5bg8K.js +573 -0
- package/dist/data-source-controller-C50Qyfzh.js +178 -0
- package/dist/data-source-options-BTpfrOZ_.js +535 -0
- package/dist/data-source-options-CQSTZHPE.js +537 -0
- package/dist/data-source-read-CUX-lgrQ.js +216 -0
- package/dist/data-source-read-DL88aH8t.js +217 -0
- package/dist/decorate-DEXtNagw.js +141 -0
- package/dist/element-props-CLB6yvbm.js +114 -0
- package/dist/esm-Ptok4SQZ.js +2026 -0
- package/dist/excel-CY6zGkcx.js +608 -0
- package/dist/excel-DopRbEMK.js +608 -0
- package/dist/export-BvlBx_GZ.js +2302 -0
- package/dist/export.d.ts +1 -0
- package/dist/export.js +2302 -0
- package/dist/field-icons-BoOG6KrL.js +51 -0
- package/dist/field-path-C92eGLg3.js +251 -0
- package/dist/filter-builder-Bke3qOgJ.js +205 -0
- package/dist/filter-builder-CE4zE0V5.js +205 -0
- package/dist/filter-eval-DIfU2EAn.js +173 -0
- package/dist/filter-odata-C1vSGZaY.js +591 -0
- package/dist/form-control-core-B8d7k6vk.js +223 -0
- package/dist/form-control-core-eeRr0zLU.js +223 -0
- package/dist/hydration-flush-RB5Tz5nl.js +1001 -0
- package/dist/icon-CJkTlmTb.js +55 -0
- package/dist/icon-dVhYJUIH.js +17 -0
- package/dist/import-BgJdkwBI.js +606 -0
- package/dist/import.d.ts +1 -0
- package/dist/import.js +606 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +16 -0
- package/dist/index.node-DjvYOL-J.js +395 -0
- package/dist/index.node.d.ts +1 -0
- package/dist/index.node.js +16 -0
- package/dist/input-zGOULADt.js +4 -0
- package/dist/layout-var-CZnzMC0s.js +73 -0
- package/dist/light-slots-BVJwyg_2.js +244 -0
- package/dist/light-slots-DW1WgfgT.js +254 -0
- package/dist/markdown-DfqrfOJN.js +20146 -0
- package/dist/mono-button-CoVnBLav.js +873 -0
- package/dist/mono-button.shadow-FfP_hMH4.js +784 -0
- package/dist/mono-data-chart-ChU4Ii3p.js +738 -0
- package/dist/mono-data-dropdown-BAUl58kW.js +357 -0
- package/dist/mono-data-grid-CLBK8clE.js +4140 -0
- package/dist/mono-data-grid-Db80FzdZ.js +4142 -0
- package/dist/mono-element-B0kP_96P.js +232 -0
- package/dist/mono-event-Bi1qP9uN.js +129 -0
- package/dist/mono-form-controller-5PfsU4qa.js +409 -0
- package/dist/mono-modal-controller-BMO3n3rP.js +223 -0
- package/dist/mono-ui-CPV7rrdo.js +358 -0
- package/dist/notifier-CE4yxMUQ.js +88 -0
- package/dist/nuxt.d.ts +1 -0
- package/dist/nuxt.js +130 -0
- package/dist/popup-portal-BziRX1yG.js +465 -0
- package/dist/popup-stack-CEEMib__.js +189 -0
- package/dist/rate-limit-BBa2PO79.js +521 -0
- package/dist/reactive-BHsqVjRh.js +789 -0
- package/dist/reactive-D3EERqgO.js +47 -0
- package/dist/search.d.ts +1 -0
- package/dist/search.js +97 -0
- package/dist/src/components/accordion/accordion-core.d.ts +62 -0
- package/dist/src/components/accordion/accordion-types.d.ts +62 -0
- package/dist/src/components/accordion/index.d.ts +3 -0
- package/dist/src/components/accordion/index.shadow.d.ts +5 -0
- package/dist/src/components/accordion/mono-accordion.d.ts +55 -0
- package/dist/src/components/accordion/mono-accordion.shadow.d.ts +56 -0
- package/dist/src/components/alert/alert-core.d.ts +46 -0
- package/dist/src/components/alert/alert-types.d.ts +44 -0
- package/dist/src/components/alert/index.d.ts +3 -0
- package/dist/src/components/alert/index.shadow.d.ts +5 -0
- package/dist/src/components/alert/mono-alert.d.ts +44 -0
- package/dist/src/components/alert/mono-alert.shadow.d.ts +34 -0
- package/dist/src/components/breadcrumb/breadcrumb-core.d.ts +61 -0
- package/dist/src/components/breadcrumb/breadcrumb-list-core.d.ts +49 -0
- package/dist/src/components/breadcrumb/breadcrumb-render.d.ts +31 -0
- package/dist/src/components/breadcrumb/breadcrumb-types.d.ts +117 -0
- package/dist/src/components/breadcrumb/breadcrumb-utils.d.ts +43 -0
- package/dist/src/components/breadcrumb/index.d.ts +6 -0
- package/dist/src/components/breadcrumb/index.shadow.d.ts +8 -0
- package/dist/src/components/breadcrumb/mono-breadcrumb-list.d.ts +29 -0
- package/dist/src/components/breadcrumb/mono-breadcrumb-list.shadow.d.ts +48 -0
- package/dist/src/components/breadcrumb/mono-breadcrumb.d.ts +38 -0
- package/dist/src/components/breadcrumb/mono-breadcrumb.shadow.d.ts +73 -0
- package/dist/src/components/button/button-core.d.ts +90 -0
- package/dist/src/components/button/button-dropdown-core.d.ts +57 -0
- package/dist/src/components/button/button-dropdown-types.d.ts +129 -0
- package/dist/src/components/button/button-types.d.ts +219 -0
- package/dist/src/components/button/button-utils.d.ts +18 -0
- package/dist/src/components/button/index.button-dropdown.d.ts +4 -0
- package/dist/src/components/button/index.button-dropdown.shadow.d.ts +4 -0
- package/dist/src/components/button/index.d.ts +8 -0
- package/dist/src/components/button/index.shadow.d.ts +5 -0
- package/dist/src/components/button/mono-button-dropdown.d.ts +35 -0
- package/dist/src/components/button/mono-button-dropdown.shadow.d.ts +45 -0
- package/dist/src/components/button/mono-button.d.ts +123 -0
- package/dist/src/components/button/mono-button.shadow.d.ts +56 -0
- package/dist/src/components/card/card-core.d.ts +74 -0
- package/dist/src/components/card/card-types.d.ts +137 -0
- package/dist/src/components/card/card-utils.d.ts +23 -0
- package/dist/src/components/card/index.d.ts +4 -0
- package/dist/src/components/card/index.shadow.d.ts +6 -0
- package/dist/src/components/card/mono-card.d.ts +56 -0
- package/dist/src/components/card/mono-card.shadow.d.ts +52 -0
- package/dist/src/components/chart/chart-core.d.ts +43 -0
- package/dist/src/components/chart/chart-odata.d.ts +52 -0
- package/dist/src/components/chart/chart-types.d.ts +337 -0
- package/dist/src/components/chart/index.d.ts +8 -0
- package/dist/src/components/chart/index.shadow.d.ts +7 -0
- package/dist/src/components/chart/mono-chart-presets.d.ts +43 -0
- package/dist/src/components/chart/mono-chart-presets.shadow.d.ts +43 -0
- package/dist/src/components/chart/mono-chart.d.ts +30 -0
- package/dist/src/components/chart/mono-chart.shadow.d.ts +22 -0
- package/dist/src/components/chart/mono-data-chart.d.ts +27 -0
- package/dist/src/components/checkbox/checkbox-core.d.ts +53 -0
- package/dist/src/components/checkbox/checkbox-types.d.ts +69 -0
- package/dist/src/components/checkbox/checkbox-utils.d.ts +35 -0
- package/dist/src/components/checkbox/index.d.ts +4 -0
- package/dist/src/components/checkbox/index.shadow.d.ts +5 -0
- package/dist/src/components/checkbox/mono-checkbox.d.ts +34 -0
- package/dist/src/components/checkbox/mono-checkbox.shadow.d.ts +45 -0
- package/dist/src/components/chip/chip-core.d.ts +58 -0
- package/dist/src/components/chip/chip-types.d.ts +142 -0
- package/dist/src/components/chip/chip-utils.d.ts +24 -0
- package/dist/src/components/chip/index.d.ts +8 -0
- package/dist/src/components/chip/index.shadow.d.ts +6 -0
- package/dist/src/components/chip/mono-chip.d.ts +48 -0
- package/dist/src/components/chip/mono-chip.shadow.d.ts +33 -0
- package/dist/src/components/chip/mono-status-dot.d.ts +34 -0
- package/dist/src/components/date/date-core.d.ts +80 -0
- package/dist/src/components/date/date-types.d.ts +163 -0
- package/dist/src/components/date/index.d.ts +3 -0
- package/dist/src/components/date/index.shadow.d.ts +4 -0
- package/dist/src/components/date/mono-date.d.ts +22 -0
- package/dist/src/components/date/mono-date.shadow.d.ts +31 -0
- package/dist/src/components/drawer/drawer-core.d.ts +99 -0
- package/dist/src/components/drawer/drawer-types.d.ts +153 -0
- package/dist/src/components/drawer/index.d.ts +3 -0
- package/dist/src/components/drawer/index.shadow.d.ts +4 -0
- package/dist/src/components/drawer/mono-drawer.d.ts +45 -0
- package/dist/src/components/drawer/mono-drawer.shadow.d.ts +46 -0
- package/dist/src/components/dropdown/dropdown-core.d.ts +33 -0
- package/dist/src/components/dropdown/dropdown-types.d.ts +88 -0
- package/dist/src/components/dropdown/index.d.ts +3 -0
- package/dist/src/components/dropdown/index.shadow.d.ts +4 -0
- package/dist/src/components/dropdown/mono-dropdown.d.ts +34 -0
- package/dist/src/components/dropdown/mono-dropdown.shadow.d.ts +28 -0
- package/dist/src/components/dropdown-table/dropdown-table-core.d.ts +65 -0
- package/dist/src/components/dropdown-table/dropdown-table-types.d.ts +278 -0
- package/dist/src/components/dropdown-table/index.d.ts +5 -0
- package/dist/src/components/dropdown-table/index.shadow.d.ts +6 -0
- package/dist/src/components/dropdown-table/mono-data-dropdown.d.ts +152 -0
- package/dist/src/components/dropdown-table/mono-dropdown-table.d.ts +46 -0
- package/dist/src/components/dropdown-table/mono-dropdown-table.shadow.d.ts +22 -0
- package/dist/src/components/file-upload/file-upload-core.d.ts +60 -0
- package/dist/src/components/file-upload/file-upload-types.d.ts +145 -0
- package/dist/src/components/file-upload/file-upload-utils.d.ts +16 -0
- package/dist/src/components/file-upload/index.d.ts +4 -0
- package/dist/src/components/file-upload/index.shadow.d.ts +5 -0
- package/dist/src/components/file-upload/mono-file-upload.d.ts +33 -0
- package/dist/src/components/file-upload/mono-file-upload.shadow.d.ts +50 -0
- package/dist/src/components/filter/filter-builder-core.d.ts +36 -0
- package/dist/src/components/filter/filter-builder.d.ts +23 -0
- package/dist/src/components/filter/filter-odata.d.ts +27 -0
- package/dist/src/components/filter/filter-operators.d.ts +13 -0
- package/dist/src/components/filter/filter-types.d.ts +253 -0
- package/dist/src/components/filter/index.d.ts +6 -0
- package/dist/src/components/filter/index.shadow.d.ts +7 -0
- package/dist/src/components/filter/mono-filter-builder.d.ts +21 -0
- package/dist/src/components/filter/mono-filter-builder.shadow.d.ts +17 -0
- package/dist/src/components/form/form-control-core.d.ts +37 -0
- package/dist/src/components/form/form-rules.d.ts +25 -0
- package/dist/src/components/form/form-types.d.ts +307 -0
- package/dist/src/components/form/index.d.ts +6 -0
- package/dist/src/components/form/mono-form-controller.d.ts +16 -0
- package/dist/src/components/input/index.d.ts +6 -0
- package/dist/src/components/input/index.shadow.d.ts +8 -0
- package/dist/src/components/input/input-core.d.ts +91 -0
- package/dist/src/components/input/input-format.d.ts +118 -0
- package/dist/src/components/input/input-types.d.ts +179 -0
- package/dist/src/components/input/input-utils.d.ts +10 -0
- package/dist/src/components/input/mono-input.d.ts +46 -0
- package/dist/src/components/input/mono-input.shadow.d.ts +34 -0
- package/dist/src/components/menu/index.d.ts +6 -0
- package/dist/src/components/menu/index.shadow.d.ts +7 -0
- package/dist/src/components/menu/menu-core.d.ts +65 -0
- package/dist/src/components/menu/menu-render.d.ts +55 -0
- package/dist/src/components/menu/menu-types.d.ts +195 -0
- package/dist/src/components/menu/menu-utils.d.ts +53 -0
- package/dist/src/components/menu/mono-menu-list.d.ts +118 -0
- package/dist/src/components/menu/mono-menu.d.ts +39 -0
- package/dist/src/components/menu/mono-menu.shadow.d.ts +40 -0
- package/dist/src/components/modal/index.d.ts +4 -0
- package/dist/src/components/modal/index.shadow.d.ts +5 -0
- package/dist/src/components/modal/modal-core.d.ts +110 -0
- package/dist/src/components/modal/modal-types.d.ts +304 -0
- package/dist/src/components/modal/mono-modal-controller.d.ts +4 -0
- package/dist/src/components/modal/mono-modal.d.ts +45 -0
- package/dist/src/components/modal/mono-modal.shadow.d.ts +50 -0
- package/dist/src/components/nav/index.d.ts +4 -0
- package/dist/src/components/nav/index.shadow.d.ts +6 -0
- package/dist/src/components/nav/mono-nav.d.ts +41 -0
- package/dist/src/components/nav/mono-nav.shadow.d.ts +21 -0
- package/dist/src/components/nav/nav-core.d.ts +34 -0
- package/dist/src/components/nav/nav-types.d.ts +48 -0
- package/dist/src/components/nav/nav-utils.d.ts +12 -0
- package/dist/src/components/radio/index.d.ts +4 -0
- package/dist/src/components/radio/index.shadow.d.ts +5 -0
- package/dist/src/components/radio/mono-radio.d.ts +31 -0
- package/dist/src/components/radio/mono-radio.shadow.d.ts +35 -0
- package/dist/src/components/radio/radio-core.d.ts +45 -0
- package/dist/src/components/radio/radio-types.d.ts +58 -0
- package/dist/src/components/radio/radio-utils.d.ts +12 -0
- package/dist/src/components/rich-text-editor/index.d.ts +5 -0
- package/dist/src/components/rich-text-editor/index.shadow.d.ts +6 -0
- package/dist/src/components/rich-text-editor/mono-rich-text-editor.d.ts +31 -0
- package/dist/src/components/rich-text-editor/mono-rich-text-editor.shadow.d.ts +34 -0
- package/dist/src/components/rich-text-editor/rich-text-editor-core.d.ts +100 -0
- package/dist/src/components/rich-text-editor/rich-text-editor-loader.d.ts +17 -0
- package/dist/src/components/rich-text-editor/rich-text-editor-toolbar.d.ts +65 -0
- package/dist/src/components/rich-text-editor/rich-text-editor-types.d.ts +231 -0
- package/dist/src/components/select/index.d.ts +4 -0
- package/dist/src/components/select/index.shadow.d.ts +5 -0
- package/dist/src/components/select/mono-select.d.ts +69 -0
- package/dist/src/components/select/mono-select.shadow.d.ts +48 -0
- package/dist/src/components/select/select-core.d.ts +98 -0
- package/dist/src/components/select/select-types.d.ts +258 -0
- package/dist/src/components/select/select-utils.d.ts +7 -0
- package/dist/src/components/sidebar/index.d.ts +4 -0
- package/dist/src/components/sidebar/index.shadow.d.ts +6 -0
- package/dist/src/components/sidebar/mono-sidebar.d.ts +34 -0
- package/dist/src/components/sidebar/mono-sidebar.shadow.d.ts +27 -0
- package/dist/src/components/sidebar/sidebar-core.d.ts +51 -0
- package/dist/src/components/sidebar/sidebar-types.d.ts +119 -0
- package/dist/src/components/sidebar/sidebar-utils.d.ts +55 -0
- package/dist/src/components/switch/index.d.ts +4 -0
- package/dist/src/components/switch/index.shadow.d.ts +5 -0
- package/dist/src/components/switch/mono-switch.d.ts +31 -0
- package/dist/src/components/switch/mono-switch.shadow.d.ts +36 -0
- package/dist/src/components/switch/switch-core.d.ts +49 -0
- package/dist/src/components/switch/switch-types.d.ts +64 -0
- package/dist/src/components/switch/switch-utils.d.ts +12 -0
- package/dist/src/components/table/array-source.d.ts +44 -0
- package/dist/src/components/table/date-filter-tree.d.ts +93 -0
- package/dist/src/components/table/grouping.d.ts +55 -0
- package/dist/src/components/table/index.d.ts +33 -0
- package/dist/src/components/table/index.shadow.d.ts +47 -0
- package/dist/src/components/table/mono-data-grid.d.ts +1756 -0
- package/dist/src/components/table/mono-table-checkbox-core.d.ts +76 -0
- package/dist/src/components/table/mono-table-checkbox.d.ts +34 -0
- package/dist/src/components/table/mono-table-checkbox.shadow.d.ts +26 -0
- package/dist/src/components/table/mono-table-detail-core.d.ts +87 -0
- package/dist/src/components/table/mono-table-detail.d.ts +32 -0
- package/dist/src/components/table/mono-table-detail.shadow.d.ts +31 -0
- package/dist/src/components/table/mono-table-empty-core.d.ts +60 -0
- package/dist/src/components/table/mono-table-empty.d.ts +35 -0
- package/dist/src/components/table/mono-table-empty.shadow.d.ts +40 -0
- package/dist/src/components/table/mono-table-error-core.d.ts +84 -0
- package/dist/src/components/table/mono-table-error.d.ts +28 -0
- package/dist/src/components/table/mono-table-error.shadow.d.ts +21 -0
- package/dist/src/components/table/mono-table-info-core.d.ts +13 -0
- package/dist/src/components/table/mono-table-info.d.ts +19 -0
- package/dist/src/components/table/mono-table-info.shadow.d.ts +14 -0
- package/dist/src/components/table/mono-table-loading-core.d.ts +41 -0
- package/dist/src/components/table/mono-table-loading.d.ts +50 -0
- package/dist/src/components/table/mono-table-loading.shadow.d.ts +14 -0
- package/dist/src/components/table/mono-table-page-size-core.d.ts +14 -0
- package/dist/src/components/table/mono-table-page-size.d.ts +16 -0
- package/dist/src/components/table/mono-table-page-size.shadow.d.ts +11 -0
- package/dist/src/components/table/mono-table-paging-core.d.ts +22 -0
- package/dist/src/components/table/mono-table-paging-group-core.d.ts +18 -0
- package/dist/src/components/table/mono-table-paging-group.d.ts +20 -0
- package/dist/src/components/table/mono-table-paging-group.shadow.d.ts +13 -0
- package/dist/src/components/table/mono-table-paging.d.ts +16 -0
- package/dist/src/components/table/mono-table-paging.shadow.d.ts +11 -0
- package/dist/src/components/table/mono-table-search-core.d.ts +74 -0
- package/dist/src/components/table/mono-table-search.d.ts +34 -0
- package/dist/src/components/table/mono-table-search.shadow.d.ts +21 -0
- package/dist/src/components/table/mono-table-sort-core.d.ts +35 -0
- package/dist/src/components/table/mono-table-sort.d.ts +38 -0
- package/dist/src/components/table/mono-table-sort.shadow.d.ts +20 -0
- package/dist/src/components/table/mono-table-summary-core.d.ts +26 -0
- package/dist/src/components/table/mono-table-summary.d.ts +24 -0
- package/dist/src/components/table/mono-table-summary.shadow.d.ts +14 -0
- package/dist/src/components/table/mono-table-th-core.d.ts +56 -0
- package/dist/src/components/table/mono-table-th.d.ts +41 -0
- package/dist/src/components/table/mono-table-th.shadow.d.ts +19 -0
- package/dist/src/components/table/store-group-source.d.ts +24 -0
- package/dist/src/components/table/table-controller-core.d.ts +40 -0
- package/dist/src/components/table/table-filter-icons.d.ts +3 -0
- package/dist/src/components/table/table-menu-core.d.ts +65 -0
- package/dist/src/components/table/table-overlay.d.ts +165 -0
- package/dist/src/components/table/table-sort-icons.d.ts +4 -0
- package/dist/src/components/table/table-sort-utils.d.ts +20 -0
- package/dist/src/components/table/table-types.d.ts +475 -0
- package/dist/src/components/tabs/index.d.ts +3 -0
- package/dist/src/components/tabs/index.shadow.d.ts +4 -0
- package/dist/src/components/tabs/mono-tabs.d.ts +33 -0
- package/dist/src/components/tabs/mono-tabs.shadow.d.ts +37 -0
- package/dist/src/components/tabs/tabs-core.d.ts +57 -0
- package/dist/src/components/tabs/tabs-types.d.ts +65 -0
- package/dist/src/components/tag-input/index.d.ts +4 -0
- package/dist/src/components/tag-input/index.shadow.d.ts +5 -0
- package/dist/src/components/tag-input/mono-tag-input.d.ts +66 -0
- package/dist/src/components/tag-input/mono-tag-input.shadow.d.ts +40 -0
- package/dist/src/components/tag-input/tag-input-core.d.ts +108 -0
- package/dist/src/components/tag-input/tag-input-types.d.ts +394 -0
- package/dist/src/components/tag-input/tag-input-utils.d.ts +8 -0
- package/dist/src/components/textarea/index.d.ts +4 -0
- package/dist/src/components/textarea/index.shadow.d.ts +5 -0
- package/dist/src/components/textarea/mono-textarea.d.ts +29 -0
- package/dist/src/components/textarea/mono-textarea.shadow.d.ts +31 -0
- package/dist/src/components/textarea/textarea-core.d.ts +60 -0
- package/dist/src/components/textarea/textarea-types.d.ts +131 -0
- package/dist/src/components/textarea/textarea-utils.d.ts +7 -0
- package/dist/src/components/tooltip/control-tooltip.d.ts +36 -0
- package/dist/src/components/tooltip/index.d.ts +6 -0
- package/dist/src/components/tooltip/tooltip-config.d.ts +27 -0
- package/dist/src/components/tooltip/tooltip-declarative.d.ts +41 -0
- package/dist/src/components/tooltip/tooltip-loader.d.ts +1 -0
- package/dist/src/components/tooltip/tooltip-types.d.ts +110 -0
- package/dist/src/composables/breakpoints.d.ts +59 -0
- package/dist/src/composables/chip-limits.d.ts +48 -0
- package/dist/src/composables/chip-strip.d.ts +93 -0
- package/dist/src/composables/color.d.ts +103 -0
- package/dist/src/composables/css-class.d.ts +27 -0
- package/dist/src/composables/css-size.d.ts +40 -0
- package/dist/src/composables/data-source-controller.d.ts +84 -0
- package/dist/src/composables/element-props.d.ts +46 -0
- package/dist/src/composables/field-icons.d.ts +7 -0
- package/dist/src/composables/hybird-prop.d.ts +79 -0
- package/dist/src/composables/hydration-flush.d.ts +34 -0
- package/dist/src/composables/icon.d.ts +17 -0
- package/dist/src/composables/layout-var.d.ts +34 -0
- package/dist/src/composables/light-slots.d.ts +133 -0
- package/dist/src/composables/mdi-glyphs.d.ts +4 -0
- package/dist/src/composables/mono-element.d.ts +9 -0
- package/dist/src/composables/mono-event.d.ts +55 -0
- package/dist/src/composables/mono-pending.d.ts +8 -0
- package/dist/src/composables/mono-skeleton.d.ts +193 -0
- package/dist/src/composables/mono-ui.d.ts +58 -0
- package/dist/src/composables/notifier.d.ts +46 -0
- package/dist/src/composables/popup-portal.d.ts +226 -0
- package/dist/src/composables/popup-stack.d.ts +70 -0
- package/dist/src/composables/rate-limit.d.ts +108 -0
- package/dist/src/composables/reactive.d.ts +53 -0
- package/dist/src/composables/shadow-css.d.ts +42 -0
- package/dist/src/composables/visibility.d.ts +36 -0
- package/dist/src/data/theme/index.d.ts +30 -0
- package/dist/src/data/theme/presets.d.ts +94 -0
- package/dist/src/entries/index.d.ts +2 -0
- package/dist/src/entries/index.node.d.ts +42 -0
- package/dist/src/entries/search.d.ts +3 -0
- package/dist/src/export/detail.d.ts +29 -0
- package/dist/src/export/download.d.ts +9 -0
- package/dist/src/export/excel/index.d.ts +27 -0
- package/dist/src/export/excel/nodes.d.ts +123 -0
- package/dist/src/export/expression.d.ts +36 -0
- package/dist/src/export/helpers.d.ts +6 -0
- package/dist/src/export/index.d.ts +13 -0
- package/dist/src/export/markdown.d.ts +52 -0
- package/dist/src/export/resolve-data.d.ts +31 -0
- package/dist/src/export/sentinel.d.ts +97 -0
- package/dist/src/export/sheet-name.d.ts +45 -0
- package/dist/src/export/styles.d.ts +33 -0
- package/dist/src/export/template.d.ts +10 -0
- package/dist/src/export/types.d.ts +259 -0
- package/dist/src/import/coerce.d.ts +38 -0
- package/dist/src/import/index.d.ts +16 -0
- package/dist/src/import/match.d.ts +54 -0
- package/dist/src/import/parse.d.ts +15 -0
- package/dist/src/import/types.d.ts +153 -0
- package/dist/src/nuxt/index.d.ts +94 -0
- package/dist/src/search/data-search.d.ts +207 -0
- package/dist/src/search/field-path.d.ts +107 -0
- package/dist/src/search/filter-eval.d.ts +30 -0
- package/dist/src/search/index.d.ts +22 -0
- package/dist/src/search/odata-search.d.ts +18 -0
- package/dist/src/search/search-expr.d.ts +160 -0
- package/dist/src/utils/data-source-apply.d.ts +97 -0
- package/dist/src/utils/data-source-options.d.ts +116 -0
- package/dist/src/utils/data-source-read.d.ts +85 -0
- package/dist/src/utils/data-source-summary.d.ts +55 -0
- package/dist/src/utils/normalize-error.d.ts +60 -0
- package/dist/src/vite/index.d.ts +48 -0
- package/dist/src/vite/mono-client-only.d.ts +35 -0
- package/dist/src/vite/mono-ssr-stub.d.ts +20 -0
- package/dist/src/vite/shadow-manifest.d.ts +8 -0
- package/dist/styles-BIJ31TM4.js +20146 -0
- package/dist/tooltip-CysgRgBi.js +760 -0
- package/dist/tooltip.d.ts +1 -0
- package/dist/tooltip.js +2 -0
- package/dist/ui/accordion.d.ts +1 -0
- package/dist/ui/accordion.js +466 -0
- package/dist/ui/alert.d.ts +1 -0
- package/dist/ui/alert.js +221 -0
- package/dist/ui/breadcrumb.d.ts +1 -0
- package/dist/ui/breadcrumb.js +902 -0
- package/dist/ui/button-dropdown.d.ts +1 -0
- package/dist/ui/button-dropdown.js +679 -0
- package/dist/ui/button.d.ts +1 -0
- package/dist/ui/button.js +63 -0
- package/dist/ui/card.d.ts +1 -0
- package/dist/ui/card.js +511 -0
- package/dist/ui/chart.d.ts +1 -0
- package/dist/ui/chart.js +808 -0
- package/dist/ui/checkbox.d.ts +1 -0
- package/dist/ui/checkbox.js +413 -0
- package/dist/ui/chip.d.ts +1 -0
- package/dist/ui/chip.js +558 -0
- package/dist/ui/date.d.ts +1 -0
- package/dist/ui/date.js +686 -0
- package/dist/ui/drawer.d.ts +1 -0
- package/dist/ui/drawer.js +901 -0
- package/dist/ui/dropdown-table.d.ts +1 -0
- package/dist/ui/dropdown-table.js +1291 -0
- package/dist/ui/dropdown.d.ts +1 -0
- package/dist/ui/dropdown.js +586 -0
- package/dist/ui/file-upload.d.ts +1 -0
- package/dist/ui/file-upload.js +688 -0
- package/dist/ui/filter.d.ts +1 -0
- package/dist/ui/filter.js +400 -0
- package/dist/ui/font/files/geist-47c091c9.woff2 +0 -0
- package/dist/ui/font/files/geist-8dd77544.woff2 +0 -0
- package/dist/ui/font/files/geist-b9248b1e.woff2 +0 -0
- package/dist/ui/font/files/geist-d40d74b4.woff2 +0 -0
- package/dist/ui/font/files/geist-f493429a.woff2 +0 -0
- package/dist/ui/font/files/geistmono-03737868.woff2 +0 -0
- package/dist/ui/font/files/geistmono-421a7e38.woff2 +0 -0
- package/dist/ui/font/files/geistmono-48ef518d.woff2 +0 -0
- package/dist/ui/font/files/geistmono-5df35d39.woff2 +0 -0
- package/dist/ui/font/files/geistmono-7de289a4.woff2 +0 -0
- package/dist/ui/font/files/geistmono-e976128f.woff2 +0 -0
- package/dist/ui/font/files/inter-05cf802c.woff2 +0 -0
- package/dist/ui/font/files/inter-2b2f25a4.woff2 +0 -0
- package/dist/ui/font/files/inter-467acc7a.woff2 +0 -0
- package/dist/ui/font/files/inter-6e85163c.woff2 +0 -0
- package/dist/ui/font/files/inter-7048add3.woff2 +0 -0
- package/dist/ui/font/files/inter-9be0371e.woff2 +0 -0
- package/dist/ui/font/files/inter-a28b7e31.woff2 +0 -0
- package/dist/ui/font/files/poppins-054df55a.woff2 +0 -0
- package/dist/ui/font/files/poppins-0ee5dc9a.woff2 +0 -0
- package/dist/ui/font/files/poppins-0f44cb18.woff2 +0 -0
- package/dist/ui/font/files/poppins-0ff0d30c.woff2 +0 -0
- package/dist/ui/font/files/poppins-13045147.woff2 +0 -0
- package/dist/ui/font/files/poppins-1db57cd9.woff2 +0 -0
- package/dist/ui/font/files/poppins-2cf2a902.woff2 +0 -0
- package/dist/ui/font/files/poppins-39e7f079.woff2 +0 -0
- package/dist/ui/font/files/poppins-9607042d.woff2 +0 -0
- package/dist/ui/font/files/poppins-9a88fc1f.woff2 +0 -0
- package/dist/ui/font/files/poppins-b8f4f752.woff2 +0 -0
- package/dist/ui/font/files/poppins-f5e57db4.woff2 +0 -0
- package/dist/ui/font/geist-mono.css +104 -0
- package/dist/ui/font/geist.css +168 -0
- package/dist/ui/font/inter.css +232 -0
- package/dist/ui/font/poppins.css +104 -0
- package/dist/ui/form.d.ts +1 -0
- package/dist/ui/form.js +3 -0
- package/dist/ui/index.css +21826 -0
- package/dist/ui/input.d.ts +1 -0
- package/dist/ui/input.js +1176 -0
- package/dist/ui/menu.d.ts +1 -0
- package/dist/ui/menu.js +1289 -0
- package/dist/ui/modal.d.ts +1 -0
- package/dist/ui/modal.js +995 -0
- package/dist/ui/nav.d.ts +1 -0
- package/dist/ui/nav.js +295 -0
- package/dist/ui/radio.d.ts +1 -0
- package/dist/ui/radio.js +379 -0
- package/dist/ui/rich-text-editor.d.ts +1 -0
- package/dist/ui/rich-text-editor.js +1338 -0
- package/dist/ui/select.d.ts +1 -0
- package/dist/ui/select.js +2066 -0
- package/dist/ui/shadow/accordion.js +442 -0
- package/dist/ui/shadow/alert.js +218 -0
- package/dist/ui/shadow/breadcrumb.js +919 -0
- package/dist/ui/shadow/button-dropdown.js +696 -0
- package/dist/ui/shadow/button.js +63 -0
- package/dist/ui/shadow/card.js +524 -0
- package/dist/ui/shadow/chart.js +1569 -0
- package/dist/ui/shadow/checkbox.js +457 -0
- package/dist/ui/shadow/chip.js +559 -0
- package/dist/ui/shadow/date.js +712 -0
- package/dist/ui/shadow/drawer.js +869 -0
- package/dist/ui/shadow/dropdown-table.js +1620 -0
- package/dist/ui/shadow/dropdown.js +547 -0
- package/dist/ui/shadow/file-upload.js +731 -0
- package/dist/ui/shadow/filter.js +402 -0
- package/dist/ui/shadow/input.js +1150 -0
- package/dist/ui/shadow/menu.js +899 -0
- package/dist/ui/shadow/modal.js +1193 -0
- package/dist/ui/shadow/nav.js +240 -0
- package/dist/ui/shadow/radio.js +408 -0
- package/dist/ui/shadow/rich-text-editor.js +1344 -0
- package/dist/ui/shadow/select.js +2033 -0
- package/dist/ui/shadow/sidebar.js +606 -0
- package/dist/ui/shadow/switch.js +428 -0
- package/dist/ui/shadow/table.js +4755 -0
- package/dist/ui/shadow/tabs.js +372 -0
- package/dist/ui/shadow/tag-input.js +2846 -0
- package/dist/ui/shadow/textarea.js +816 -0
- package/dist/ui/sidebar.d.ts +1 -0
- package/dist/ui/sidebar.js +659 -0
- package/dist/ui/switch.d.ts +1 -0
- package/dist/ui/switch.js +398 -0
- package/dist/ui/table.d.ts +1 -0
- package/dist/ui/table.js +4654 -0
- package/dist/ui/tabs.d.ts +1 -0
- package/dist/ui/tabs.js +379 -0
- package/dist/ui/tag-input.d.ts +1 -0
- package/dist/ui/tag-input.js +2819 -0
- package/dist/ui/textarea.d.ts +1 -0
- package/dist/ui/textarea.js +819 -0
- package/dist/ui/theme/legacy.css +293 -0
- package/dist/ui/theme/luma.css +743 -0
- package/dist/ui/theme/lyra.css +754 -0
- package/dist/ui/theme/maia.css +673 -0
- package/dist/ui/theme/mira.css +802 -0
- package/dist/ui/theme/nova.css +662 -0
- package/dist/ui/theme/one.css +699 -0
- package/dist/ui/theme/rhea.css +742 -0
- package/dist/ui/theme/sera.css +845 -0
- package/dist/ui/theme/tokens.css +261 -0
- package/dist/ui/theme/vega.css +467 -0
- package/dist/vite-C5iUK7so.js +329 -0
- package/dist/vite.d.ts +1 -0
- package/dist/vite.js +2 -0
- package/dist/vue.d.ts +282 -0
- package/package.json +411 -3
|
@@ -0,0 +1,2033 @@
|
|
|
1
|
+
import { a as __decorate, f as customElement, i as withShadowUtilityStyles, l as defineHybridPropAliases, o as arrayHasChanged, r as toShadowCss, s as booleanStringConverter, t as flushSsrHydration } from "../../hydration-flush-RB5Tz5nl.js";
|
|
2
|
+
import { t as dispatchMonoEvent } from "../../mono-event-Bi1qP9uN.js";
|
|
3
|
+
import { n as toCssSize, t as buildSizeStyle } from "../../css-size-DhHSVZJK.js";
|
|
4
|
+
import { t as MonoFormControlCore } from "../../form-control-core-B8d7k6vk.js";
|
|
5
|
+
import { t as PopupPortalController } from "../../popup-portal-BziRX1yG.js";
|
|
6
|
+
import { a as rateLimitHasChanged } from "../../rate-limit-BBa2PO79.js";
|
|
7
|
+
import { t as getFieldValue } from "../../field-path-C92eGLg3.js";
|
|
8
|
+
import { a as MonoSourceSearch, c as searchRowPredicate, n as unwrapReactive, s as resolveSearchFields } from "../../reactive-BHsqVjRh.js";
|
|
9
|
+
import { t as LateSlotWatcher } from "../../light-slots-BVJwyg_2.js";
|
|
10
|
+
import { t as DataSourceController } from "../../data-source-controller-C50Qyfzh.js";
|
|
11
|
+
import { LitElement, html, isServer, nothing, unsafeCSS } from "lit";
|
|
12
|
+
import { property, query, state } from "lit/decorators.js";
|
|
13
|
+
import { ifDefined } from "lit/directives/if-defined.js";
|
|
14
|
+
import { styleMap } from "lit/directives/style-map.js";
|
|
15
|
+
//#region src/components/select/select-core.ts
|
|
16
|
+
/**
|
|
17
|
+
* `MonoSelectCore` — render-mode-agnostic logic for `mono-select` (props, hybrid
|
|
18
|
+
* aliases, value/model sync, DataSource paging, search, grouping, keyboard nav,
|
|
19
|
+
* the popup controller, and the full `render()`). SSR-safe: every `document` /
|
|
20
|
+
* `window` / focus access is `isServer`-guarded.
|
|
21
|
+
*
|
|
22
|
+
* Each build supplies `createRenderRoot()` + `static styles`, the slot strategy
|
|
23
|
+
* (light captures children into `data-mono-slot` placeholders; shadow uses native
|
|
24
|
+
* `<slot>` + a `firstUpdated` scan), and the `_slotOutlet` / `renderIcon` hooks.
|
|
25
|
+
* The shared `_has*SlotState` `@state` fields back both strategies.
|
|
26
|
+
*/
|
|
27
|
+
var MonoSelectCore = (superClass) => {
|
|
28
|
+
class MonoSelectCoreClass extends MonoFormControlCore(superClass) {
|
|
29
|
+
constructor(...args) {
|
|
30
|
+
super(...args);
|
|
31
|
+
this.size = "md";
|
|
32
|
+
this.color = "primary";
|
|
33
|
+
this.variant = "outlined";
|
|
34
|
+
this.modelValue = null;
|
|
35
|
+
this.value = null;
|
|
36
|
+
this.name = "";
|
|
37
|
+
this.label = "";
|
|
38
|
+
this.placeholder = "Select option";
|
|
39
|
+
this.helperText = "";
|
|
40
|
+
this.validationState = "default";
|
|
41
|
+
this.validationMessage = "";
|
|
42
|
+
this.errorMessage = "";
|
|
43
|
+
this.successMessage = "";
|
|
44
|
+
this.disabled = false;
|
|
45
|
+
this.readonly = false;
|
|
46
|
+
this.required = false;
|
|
47
|
+
this.clearable = false;
|
|
48
|
+
this.items = [];
|
|
49
|
+
this.dataSource = null;
|
|
50
|
+
this.immediate = true;
|
|
51
|
+
this.pageSize = 10;
|
|
52
|
+
this.dropdownHeight = "";
|
|
53
|
+
this.dropdownMaxHeight = "";
|
|
54
|
+
this.flip = true;
|
|
55
|
+
this.shift = true;
|
|
56
|
+
this.keyValue = "";
|
|
57
|
+
this.displayValue = "";
|
|
58
|
+
this.displayGroup = [];
|
|
59
|
+
this.groupKey = "key";
|
|
60
|
+
this.groupItems = "items";
|
|
61
|
+
this.group = false;
|
|
62
|
+
this.groupSticky = false;
|
|
63
|
+
this.searchable = false;
|
|
64
|
+
this.stayOpen = false;
|
|
65
|
+
this.searchValue = "";
|
|
66
|
+
this.searchOperation = "contains";
|
|
67
|
+
this.searchDebounce = 300;
|
|
68
|
+
this.searchPlaceholder = "";
|
|
69
|
+
this.cssClass = {};
|
|
70
|
+
this.cssClassName = "";
|
|
71
|
+
this._open = false;
|
|
72
|
+
this._query = "";
|
|
73
|
+
this._searchActive = false;
|
|
74
|
+
this._activeIndex = -1;
|
|
75
|
+
this._cursorPending = false;
|
|
76
|
+
this._sourceSearch = new MonoSourceSearch();
|
|
77
|
+
this._searchVersion = 0;
|
|
78
|
+
this._scrollAutoMaxHeight = "";
|
|
79
|
+
this._hasLabelSlotState = false;
|
|
80
|
+
this._hasHelperSlotState = false;
|
|
81
|
+
this._hasPrefixSlotState = false;
|
|
82
|
+
this._hasSuffixSlotState = false;
|
|
83
|
+
this._hasListSlotState = false;
|
|
84
|
+
this._popup = new PopupPortalController(this, {
|
|
85
|
+
getPanel: () => this.renderRoot.querySelector(".mono-select-dropdown"),
|
|
86
|
+
getAnchor: () => this.renderRoot.querySelector(".mono-select-trigger"),
|
|
87
|
+
getStyleScope: () => this.renderRoot.querySelector(".mono-select"),
|
|
88
|
+
isOpen: () => this._open,
|
|
89
|
+
matchWidth: () => !toCssSize(this.dropdown?.width),
|
|
90
|
+
offset: () => 6,
|
|
91
|
+
flip: () => this.flip,
|
|
92
|
+
shift: () => this.shift,
|
|
93
|
+
constrainSize: () => true
|
|
94
|
+
});
|
|
95
|
+
this._selectId = `mono-select-${Math.random().toString(36).slice(2)}`;
|
|
96
|
+
this._messageId = `${this._selectId}-message`;
|
|
97
|
+
this._listboxId = `${this._selectId}-listbox`;
|
|
98
|
+
this._lateListSlot = new LateSlotWatcher(this, "list", () => this._onLateListSlot());
|
|
99
|
+
this._docListenersBound = false;
|
|
100
|
+
this._itemsEpoch = 0;
|
|
101
|
+
this._handleDropdownScroll = (event) => {
|
|
102
|
+
if (this._loadMoreMode !== "scroll") return;
|
|
103
|
+
if (this._ds.loadingMore || this._ds.atLastPage) return;
|
|
104
|
+
const el = event.currentTarget;
|
|
105
|
+
if (!el) return;
|
|
106
|
+
if (el.scrollHeight - el.scrollTop - el.clientHeight <= 24) this._ds.loadMore();
|
|
107
|
+
};
|
|
108
|
+
this._handleDocumentClick = (event) => {
|
|
109
|
+
if (!this._open || this.stayOpen) return;
|
|
110
|
+
const path = event.composedPath();
|
|
111
|
+
if (path.includes(this) || this._popup.containsInPath(path)) return;
|
|
112
|
+
this._close();
|
|
113
|
+
};
|
|
114
|
+
this._handleDocumentFocusIn = (event) => {
|
|
115
|
+
if (!this._open || this.stayOpen) return;
|
|
116
|
+
const path = event.composedPath();
|
|
117
|
+
if (path.includes(this) || this._popup.containsInPath(path)) return;
|
|
118
|
+
this._close();
|
|
119
|
+
};
|
|
120
|
+
this._handleDocumentKeydown = (event) => {
|
|
121
|
+
if (!this._open) return;
|
|
122
|
+
if (event.key === "Escape") {
|
|
123
|
+
event.preventDefault();
|
|
124
|
+
this._close();
|
|
125
|
+
this._triggerEl?.focus();
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
this._publishedEntries = [];
|
|
129
|
+
this._onListSlotClick = (event) => {
|
|
130
|
+
if (this.disabled || this.readonly) return;
|
|
131
|
+
const target = event.target;
|
|
132
|
+
const item = target ? this._entryFromNode(target)?.item : void 0;
|
|
133
|
+
if (!item || item.disabled) return;
|
|
134
|
+
this._selectItem(item, event);
|
|
135
|
+
};
|
|
136
|
+
defineHybridPropAliases(this, [
|
|
137
|
+
"modelValue",
|
|
138
|
+
"helperText",
|
|
139
|
+
"validationState",
|
|
140
|
+
"validationMessage",
|
|
141
|
+
"errorMessage",
|
|
142
|
+
"successMessage",
|
|
143
|
+
"ariaLabelText",
|
|
144
|
+
"cssClass",
|
|
145
|
+
"keyValue",
|
|
146
|
+
"displayValue",
|
|
147
|
+
"displayGroup",
|
|
148
|
+
"groupKey",
|
|
149
|
+
"groupItems",
|
|
150
|
+
"groupSticky",
|
|
151
|
+
"searchValue",
|
|
152
|
+
"searchOperation",
|
|
153
|
+
"searchDebounce",
|
|
154
|
+
"searchPlaceholder",
|
|
155
|
+
"dataSource",
|
|
156
|
+
"loadMore",
|
|
157
|
+
"pageSize",
|
|
158
|
+
"dropdownHeight",
|
|
159
|
+
"dropdownMaxHeight",
|
|
160
|
+
"minWidth",
|
|
161
|
+
"maxWidth",
|
|
162
|
+
"minHeight",
|
|
163
|
+
"maxHeight",
|
|
164
|
+
"stayOpen"
|
|
165
|
+
]);
|
|
166
|
+
/**
|
|
167
|
+
* Makes these Vue usages work:
|
|
168
|
+
*
|
|
169
|
+
* <mono-select :cssClass="{}" />
|
|
170
|
+
* <mono-select :css-class="{}" />
|
|
171
|
+
* <mono-select :cssclass="{}" />
|
|
172
|
+
*/
|
|
173
|
+
Object.defineProperty(this, "css-class", {
|
|
174
|
+
get: () => this.cssClass,
|
|
175
|
+
set: (value) => {
|
|
176
|
+
this._setCssClass(value);
|
|
177
|
+
},
|
|
178
|
+
configurable: true,
|
|
179
|
+
enumerable: false
|
|
180
|
+
});
|
|
181
|
+
Object.defineProperty(this, "cssclass", {
|
|
182
|
+
get: () => this.cssClass,
|
|
183
|
+
set: (value) => {
|
|
184
|
+
this._setCssClass(value);
|
|
185
|
+
},
|
|
186
|
+
configurable: true,
|
|
187
|
+
enumerable: false
|
|
188
|
+
});
|
|
189
|
+
Object.defineProperty(this, "ariaLabel", {
|
|
190
|
+
get: () => this.ariaLabelText,
|
|
191
|
+
set: (value) => {
|
|
192
|
+
this.ariaLabelText = value == null ? void 0 : String(value);
|
|
193
|
+
},
|
|
194
|
+
configurable: true,
|
|
195
|
+
enumerable: false
|
|
196
|
+
});
|
|
197
|
+
Object.defineProperty(this, "aria-label", {
|
|
198
|
+
get: () => this.ariaLabelText,
|
|
199
|
+
set: (value) => {
|
|
200
|
+
this.ariaLabelText = value == null ? void 0 : String(value);
|
|
201
|
+
},
|
|
202
|
+
configurable: true,
|
|
203
|
+
enumerable: false
|
|
204
|
+
});
|
|
205
|
+
Object.defineProperty(this, "arialabel", {
|
|
206
|
+
get: () => this.ariaLabelText,
|
|
207
|
+
set: (value) => {
|
|
208
|
+
this.ariaLabelText = value == null ? void 0 : String(value);
|
|
209
|
+
},
|
|
210
|
+
configurable: true,
|
|
211
|
+
enumerable: false
|
|
212
|
+
});
|
|
213
|
+
this._ds = new DataSourceController(this, {
|
|
214
|
+
getDataSource: () => this.dataSource,
|
|
215
|
+
getItems: () => this.items,
|
|
216
|
+
getImmediate: () => this.immediate,
|
|
217
|
+
getLoadMoreMode: () => this._loadMoreMode,
|
|
218
|
+
getPageSize: () => this._pageSize
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
static {
|
|
222
|
+
this.monoPendingAuto = "data";
|
|
223
|
+
}
|
|
224
|
+
_monoPendingReady() {
|
|
225
|
+
return !this.dataSource || !this._ds.loading;
|
|
226
|
+
}
|
|
227
|
+
static get observedAttributes() {
|
|
228
|
+
return [
|
|
229
|
+
...super.observedAttributes ?? [],
|
|
230
|
+
"modelvalue",
|
|
231
|
+
"model-value",
|
|
232
|
+
"helpertext",
|
|
233
|
+
"validationstate",
|
|
234
|
+
"validationmessage",
|
|
235
|
+
"errormessage",
|
|
236
|
+
"successmessage",
|
|
237
|
+
"arialabeltext",
|
|
238
|
+
"arialabel",
|
|
239
|
+
"css-class",
|
|
240
|
+
"cssclass",
|
|
241
|
+
"keyvalue",
|
|
242
|
+
"displayvalue",
|
|
243
|
+
"display-value",
|
|
244
|
+
"stayopen"
|
|
245
|
+
];
|
|
246
|
+
}
|
|
247
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
248
|
+
super.attributeChangedCallback(name, oldValue, newValue);
|
|
249
|
+
if (oldValue === newValue) return;
|
|
250
|
+
if (name === "modelvalue" || name === "model-value") {
|
|
251
|
+
this.modelValue = this._toSelectValue(newValue);
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
if (name === "helpertext") {
|
|
255
|
+
this.helperText = newValue ?? "";
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
if (name === "validationstate") {
|
|
259
|
+
this.validationState = newValue ?? "default";
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
if (name === "validationmessage") {
|
|
263
|
+
this.validationMessage = newValue ?? "";
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
if (name === "errormessage") {
|
|
267
|
+
this.errorMessage = newValue ?? "";
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
if (name === "successmessage") {
|
|
271
|
+
this.successMessage = newValue ?? "";
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
if (name === "arialabeltext" || name === "arialabel") {
|
|
275
|
+
this.ariaLabelText = newValue ?? void 0;
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
if (name === "keyvalue") {
|
|
279
|
+
this.keyValue = newValue ?? "";
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
if (name === "displayvalue" || name === "display-value") {
|
|
283
|
+
if (typeof this.displayValue === "function") return;
|
|
284
|
+
const next = newValue ?? "";
|
|
285
|
+
if (this._looksLikeSerializedFunction(next)) return;
|
|
286
|
+
this.displayValue = next;
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
if (name === "stayopen") {
|
|
290
|
+
this.stayOpen = this._toBoolean(newValue);
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
if (name === "css-class" || name === "cssclass") this._setCssClass(newValue);
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* The scroll body lives inside the dropdown panel, which the portal
|
|
297
|
+
* controller relocates into a `<body>` portal while open — query it through
|
|
298
|
+
* `panelRoot` (the portal when adopted, else the host render root).
|
|
299
|
+
*/
|
|
300
|
+
get _dropdownBodyEl() {
|
|
301
|
+
return this._popup.panelRoot.querySelector(".mono-select-dropdown-body");
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Where the consumer's list wrapper is parked — through the SAME portal-aware root as the panel,
|
|
305
|
+
* since while the dropdown is open it lives in a body portal a host query would miss.
|
|
306
|
+
*/
|
|
307
|
+
get _listSlotTarget() {
|
|
308
|
+
return this._popup.panelRoot.querySelector("[data-mono-slot=\"list\"]");
|
|
309
|
+
}
|
|
310
|
+
/** A late wrapper arrived. Overridden per build — one adopts it, the other rescans. */
|
|
311
|
+
_onLateListSlot() {}
|
|
312
|
+
connectedCallback() {
|
|
313
|
+
super.connectedCallback();
|
|
314
|
+
this._lateListSlot.start();
|
|
315
|
+
if (isServer) return;
|
|
316
|
+
if (this._open) this._bindDocumentListeners();
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Outside-dismiss listeners, bound on OPEN rather than on connect.
|
|
320
|
+
*
|
|
321
|
+
* All three handlers begin with `if (!this._open) return`, so binding them only
|
|
322
|
+
* while open is behaviour-preserving — the cost they carried was pure event
|
|
323
|
+
* DISPATCH. Every mounted select used to hold three `document` listeners, two of
|
|
324
|
+
* them capture-phase, so a grid with one select per row put 600 handlers (400 in
|
|
325
|
+
* capture) in the path of every click, focus move and keystroke on the page.
|
|
326
|
+
* Measured on the 200-row fixture: 600 listeners before, 0 at rest after.
|
|
327
|
+
*
|
|
328
|
+
* Same change, and the same reasoning, as the popup viewport listeners in
|
|
329
|
+
* `popup-portal.ts` — which this file was explicitly the remaining example of.
|
|
330
|
+
*/
|
|
331
|
+
_bindDocumentListeners() {
|
|
332
|
+
if (this._docListenersBound) return;
|
|
333
|
+
this._docListenersBound = true;
|
|
334
|
+
document.addEventListener("click", this._handleDocumentClick, true);
|
|
335
|
+
document.addEventListener("focusin", this._handleDocumentFocusIn, true);
|
|
336
|
+
document.addEventListener("keydown", this._handleDocumentKeydown);
|
|
337
|
+
}
|
|
338
|
+
_unbindDocumentListeners() {
|
|
339
|
+
if (!this._docListenersBound) return;
|
|
340
|
+
this._docListenersBound = false;
|
|
341
|
+
document.removeEventListener("click", this._handleDocumentClick, true);
|
|
342
|
+
document.removeEventListener("focusin", this._handleDocumentFocusIn, true);
|
|
343
|
+
document.removeEventListener("keydown", this._handleDocumentKeydown);
|
|
344
|
+
}
|
|
345
|
+
disconnectedCallback() {
|
|
346
|
+
if (this._searchTimer) {
|
|
347
|
+
clearTimeout(this._searchTimer);
|
|
348
|
+
this._searchTimer = void 0;
|
|
349
|
+
}
|
|
350
|
+
this._sourceSearch.clear(this.dataSource);
|
|
351
|
+
this._lateListSlot.stop();
|
|
352
|
+
this._stopWatchingListChrome();
|
|
353
|
+
if (!isServer) this._unbindDocumentListeners();
|
|
354
|
+
super.disconnectedCallback();
|
|
355
|
+
}
|
|
356
|
+
willUpdate(changed) {
|
|
357
|
+
this._itemsEpoch++;
|
|
358
|
+
for (const key of [
|
|
359
|
+
"disabled",
|
|
360
|
+
"readonly",
|
|
361
|
+
"required",
|
|
362
|
+
"clearable",
|
|
363
|
+
"immediate",
|
|
364
|
+
"group",
|
|
365
|
+
"groupSticky",
|
|
366
|
+
"searchable",
|
|
367
|
+
"stayOpen"
|
|
368
|
+
]) {
|
|
369
|
+
const v = this[key];
|
|
370
|
+
if (typeof v !== "boolean") this[key] = this._toBoolean(v);
|
|
371
|
+
}
|
|
372
|
+
if (changed.has("modelValue") && !this._isSameValue(this.value, this.modelValue)) this.value = unwrapReactive(this.modelValue);
|
|
373
|
+
if (changed.has("value") && !this._isSameValue(this.modelValue, this.value)) this.modelValue = unwrapReactive(this.value);
|
|
374
|
+
if (this.group && (changed.has("dataSource") || changed.has("displayGroup") || changed.has("group"))) {
|
|
375
|
+
const fields = this._groupSortFields();
|
|
376
|
+
if (fields.length) this.dataSource?.sort?.(fields);
|
|
377
|
+
}
|
|
378
|
+
if (changed.has("dataSource")) {
|
|
379
|
+
this._ds.bind(this.dataSource);
|
|
380
|
+
this._sourceSearch.bind(this.dataSource);
|
|
381
|
+
}
|
|
382
|
+
if (changed.has("searchValue") || changed.has("searchOperation") || changed.has("displayValue") || changed.has("keyValue") || changed.has("dataSource") || changed.has("items")) this._searchVersion++;
|
|
383
|
+
if (changed.has("immediate")) this._ds.maybeImmediateLoad();
|
|
384
|
+
if (changed.has("loadMore")) this._ds.onLoadMoreModeChange();
|
|
385
|
+
if (changed.has("items") || changed.has("loadMore") || changed.has("pageSize")) this._ds.resetVisible();
|
|
386
|
+
if (changed.has("_open")) {
|
|
387
|
+
this._cursorPending = this._open;
|
|
388
|
+
if (!this._open) this._activeIndex = -1;
|
|
389
|
+
}
|
|
390
|
+
if (this._cursorPending && this._open && this._filteredItems.length) {
|
|
391
|
+
this._activeIndex = this._initialActiveIndex();
|
|
392
|
+
this._cursorPending = false;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
updated(changed) {
|
|
396
|
+
super.updated(changed);
|
|
397
|
+
this._syncListEntries();
|
|
398
|
+
if (isServer) return;
|
|
399
|
+
if (changed.has("_open") && this._open && this.searchable) this._searchFieldEl?.focus();
|
|
400
|
+
if (changed.has("_activeIndex") && this._open && this._activeIndex >= 0) (this._popup.panelRoot?.querySelectorAll?.(".mono-select-item")?.[this._activeIndex])?.scrollIntoView?.({ block: "nearest" });
|
|
401
|
+
this._updateScrollAutoHeight();
|
|
402
|
+
if (this._open) this._bindDocumentListeners();
|
|
403
|
+
else this._unbindDocumentListeners();
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Scroll-mode ergonomics: a short page (e.g. 5 items) won't overflow the
|
|
407
|
+
* default dropdown height, so there's nothing to scroll and the next page
|
|
408
|
+
* could never be triggered. Rather than eagerly fetching another page on
|
|
409
|
+
* open, cap the list height to the loaded rows minus a sliver — enough to
|
|
410
|
+
* show a scrollbar so the user scrolls to load more. No height is forced
|
|
411
|
+
* when the consumer set `dropdown-height`/`dropdown-max-height`, when the
|
|
412
|
+
* last page is reached, or when the rows already overflow.
|
|
413
|
+
*/
|
|
414
|
+
_updateScrollAutoHeight() {
|
|
415
|
+
const userSetHeight = this._toCssLength(this.dropdownHeight) != null || this._toCssLength(this.dropdownMaxHeight) != null || toCssSize(this.dropdown?.height) != null || toCssSize(this.dropdown?.maxHeight) != null;
|
|
416
|
+
if (!(this._loadMoreMode === "scroll" && this._open && !this._ds.atLastPage && !userSetHeight && this._visibleItems.length > 0)) {
|
|
417
|
+
this._setScrollAutoMaxHeight("");
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
const el = this._dropdownBodyEl;
|
|
421
|
+
const rowH = (el?.querySelector(".mono-select-item"))?.offsetHeight ?? 0;
|
|
422
|
+
if (!el || !rowH) return;
|
|
423
|
+
const CAP_ROWS = 7;
|
|
424
|
+
const rows = this._visibleItems.length;
|
|
425
|
+
let visible = Math.min(rows, CAP_ROWS);
|
|
426
|
+
if (rows <= CAP_ROWS) visible -= .5;
|
|
427
|
+
this._setScrollAutoMaxHeight(`${Math.round(visible * rowH)}px`);
|
|
428
|
+
}
|
|
429
|
+
_setScrollAutoMaxHeight(value) {
|
|
430
|
+
if (value === this._scrollAutoMaxHeight) return;
|
|
431
|
+
queueMicrotask(() => {
|
|
432
|
+
this._scrollAutoMaxHeight = value;
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
_setCssClass(value) {
|
|
436
|
+
if (value == null) {
|
|
437
|
+
this.cssClass = {};
|
|
438
|
+
this.cssClassName = "";
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
if (typeof value === "object") {
|
|
442
|
+
this.cssClass = value;
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
if (typeof value === "string") {
|
|
446
|
+
const trimmed = value.trim();
|
|
447
|
+
if (!trimmed) {
|
|
448
|
+
this.cssClass = {};
|
|
449
|
+
this.cssClassName = "";
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Optional HTML object support:
|
|
454
|
+
* <mono-select css-class='{"root":"...", "trigger":"..."}'>
|
|
455
|
+
*/
|
|
456
|
+
if (trimmed.startsWith("{") && trimmed.endsWith("}")) try {
|
|
457
|
+
this.cssClass = JSON.parse(trimmed);
|
|
458
|
+
return;
|
|
459
|
+
} catch {}
|
|
460
|
+
this.cssClassName = trimmed;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
_toSelectValue(value) {
|
|
464
|
+
if (value === void 0 || value === null) return null;
|
|
465
|
+
if (typeof value !== "string") return value;
|
|
466
|
+
const trimmed = value.trim();
|
|
467
|
+
if (!trimmed) return null;
|
|
468
|
+
if (/^-?\d+(?:\.\d+)?$/.test(trimmed) || trimmed === "true" || trimmed === "false" || trimmed === "null" || trimmed[0] === "{" && trimmed[trimmed.length - 1] === "}" || trimmed[0] === "[" && trimmed[trimmed.length - 1] === "]" || trimmed[0] === "\"" && trimmed[trimmed.length - 1] === "\"") try {
|
|
469
|
+
return JSON.parse(trimmed);
|
|
470
|
+
} catch {}
|
|
471
|
+
return trimmed;
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Wrap bare primitives so every row is an object, and pass objects through.
|
|
475
|
+
*
|
|
476
|
+
* The `.map()` used to be unconditional, which made this an ALLOCATION on the
|
|
477
|
+
* overwhelmingly common path (an array of objects, where the map is an identity
|
|
478
|
+
* function). It is read through `_normalizedItems` / `_visibleItems` / `_leafItems`
|
|
479
|
+
* several times per render, so at one select per table row it was the single
|
|
480
|
+
* hottest allocation in the component. The scan below is O(n) reads with no
|
|
481
|
+
* allocation, and returns the SAME array when nothing needs wrapping.
|
|
482
|
+
*
|
|
483
|
+
* Returning the input array is safe: every caller only reads
|
|
484
|
+
* (`find`/`filter`/`map`/`findIndex`/`length`), and `resolveSearchFields` takes its
|
|
485
|
+
* rows as `readonly unknown[]`. It also makes item identity STABLE across calls for
|
|
486
|
+
* primitive lists, which is the safe direction — see the note on
|
|
487
|
+
* `_initialActiveIndex`, which explains why it deliberately does not rely on that
|
|
488
|
+
* identity holding.
|
|
489
|
+
*/
|
|
490
|
+
_normalizeItems(items) {
|
|
491
|
+
if (Array.isArray(items)) {
|
|
492
|
+
let needsWrap = false;
|
|
493
|
+
for (const item of items) if (typeof item !== "object" || item === null) {
|
|
494
|
+
needsWrap = true;
|
|
495
|
+
break;
|
|
496
|
+
}
|
|
497
|
+
if (!needsWrap) return items;
|
|
498
|
+
return items.map((item) => {
|
|
499
|
+
if (typeof item === "object" && item !== null) return item;
|
|
500
|
+
return { value: item };
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
if (typeof items === "string") try {
|
|
504
|
+
const parsed = JSON.parse(items);
|
|
505
|
+
return this._normalizeItems(parsed);
|
|
506
|
+
} catch {
|
|
507
|
+
return [];
|
|
508
|
+
}
|
|
509
|
+
return [];
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Read `field` off an option row — PATH-AWARE, like every other field name in
|
|
513
|
+
* the library.
|
|
514
|
+
*
|
|
515
|
+
* A plain `field in item` was the old test, and it silently produced
|
|
516
|
+
* `undefined` for any nested accessor: an option list grouped by a navigation
|
|
517
|
+
* property (`$apply=groupby((PostBudget/Nama))` returns
|
|
518
|
+
* `{ PostBudget: { Nama: … } }`) has no top-level `"PostBudget.Nama"` key, so
|
|
519
|
+
* every option resolved to no value at all — selectable in appearance, inert in
|
|
520
|
+
* practice. `searchExpr`, table columns and summaries have always accepted
|
|
521
|
+
* these paths; a select's `key-value` / `display-value` now do too.
|
|
522
|
+
*
|
|
523
|
+
* The LITERAL key is still tried first, so a row that genuinely carries a
|
|
524
|
+
* dotted PROPERTY NAME keeps resolving exactly as it did — only a key that is
|
|
525
|
+
* absent falls through to being read as a path, which previously could only
|
|
526
|
+
* have yielded `undefined` anyway. Nothing that worked before changes.
|
|
527
|
+
*/
|
|
528
|
+
_readField(item, field) {
|
|
529
|
+
if (field in item) return item[field];
|
|
530
|
+
return getFieldValue(item, field);
|
|
531
|
+
}
|
|
532
|
+
_resolveItemValue(item) {
|
|
533
|
+
if (item == null) return item;
|
|
534
|
+
if (typeof item !== "object") return item;
|
|
535
|
+
if (this.keyValue) return this._readField(item, this.keyValue);
|
|
536
|
+
return item;
|
|
537
|
+
}
|
|
538
|
+
_resolveItemDisplay(item) {
|
|
539
|
+
if (item == null) return "";
|
|
540
|
+
if (typeof this.displayValue === "function") return String(this.displayValue(item));
|
|
541
|
+
if (typeof this.displayValue === "string" && this.displayValue) {
|
|
542
|
+
if (typeof item !== "object") return "";
|
|
543
|
+
const value = this._readField(item, this.displayValue);
|
|
544
|
+
return value == null ? "" : String(value);
|
|
545
|
+
}
|
|
546
|
+
if (typeof item === "object" && "label" in item) {
|
|
547
|
+
const label = item.label;
|
|
548
|
+
return label == null ? "" : String(label);
|
|
549
|
+
}
|
|
550
|
+
if (typeof item === "object" && "value" in item) {
|
|
551
|
+
const value = item.value;
|
|
552
|
+
return value == null ? "" : String(value);
|
|
553
|
+
}
|
|
554
|
+
return String(item);
|
|
555
|
+
}
|
|
556
|
+
_looksLikeSerializedFunction(value) {
|
|
557
|
+
const trimmed = value.trim();
|
|
558
|
+
if (!trimmed) return false;
|
|
559
|
+
return /^(?:async\s+)?(?:function\b|\([^)]*\)\s*=>|[A-Za-z_$][\w$]*\s*=>)/.test(trimmed);
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* Value equality. With no `key-value` the whole item IS the value, so this is
|
|
563
|
+
* identity — with one correction that is load-bearing under Vue.
|
|
564
|
+
*
|
|
565
|
+
* The model round-trips through the consumer's `ref`, which hands the item back
|
|
566
|
+
* wrapped in a **reactive Proxy**; `items` normally stays raw, so `proxy === row`
|
|
567
|
+
* is false and the selected row stops resolving (blank field, no highlight).
|
|
568
|
+
* Comparing the raw targets restores it. Still identity, not deep equality:
|
|
569
|
+
* two distinct rows with equal contents remain different values.
|
|
570
|
+
*/
|
|
571
|
+
_isSameValue(a, b) {
|
|
572
|
+
if (a === b) return true;
|
|
573
|
+
if (a == null || b == null) return false;
|
|
574
|
+
const rawA = unwrapReactive(a);
|
|
575
|
+
const rawB = unwrapReactive(b);
|
|
576
|
+
if (rawA === rawB) return true;
|
|
577
|
+
if (typeof rawA !== "object" || typeof rawB !== "object") return false;
|
|
578
|
+
return false;
|
|
579
|
+
}
|
|
580
|
+
_cls(base, key) {
|
|
581
|
+
const extra = this.cssClass?.[key];
|
|
582
|
+
return extra ? `${base} ${extra}` : base;
|
|
583
|
+
}
|
|
584
|
+
_toCssLength(value) {
|
|
585
|
+
if (value == null || value === "") return void 0;
|
|
586
|
+
if (typeof value === "number") return `${value}px`;
|
|
587
|
+
const trimmed = String(value).trim();
|
|
588
|
+
if (!trimmed) return void 0;
|
|
589
|
+
return /^-?\d+(?:\.\d+)?$/.test(trimmed) ? `${trimmed}px` : trimmed;
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* The WIDTH half of `dropdown`, on the panel.
|
|
593
|
+
*
|
|
594
|
+
* Split from the heights below because this component's popup is two elements: the panel owns
|
|
595
|
+
* the box and the border, its body does the scrolling. That split is also why select needs no
|
|
596
|
+
* `--_…-panel-max-h` custom property the way tag-input does — the popup controller's own cap
|
|
597
|
+
* (`--mono-popup-avail-h`) lives on the panel and the author's on the body, so the two writers
|
|
598
|
+
* never meet on one declaration.
|
|
599
|
+
*
|
|
600
|
+
* The panel is positioned `left: 0; right: 0` against the field, and a width on top of that is
|
|
601
|
+
* the over-constrained case, which CSS resolves by dropping `right` — so the panel keeps its
|
|
602
|
+
* left edge and takes this size.
|
|
603
|
+
*/
|
|
604
|
+
get _dropdownPanelStyle() {
|
|
605
|
+
const style = {};
|
|
606
|
+
const panel = this.dropdown;
|
|
607
|
+
const width = toCssSize(panel?.width);
|
|
608
|
+
if (width) style.width = width;
|
|
609
|
+
const minWidth = toCssSize(panel?.minWidth);
|
|
610
|
+
if (minWidth) style["min-width"] = minWidth;
|
|
611
|
+
const maxWidth = toCssSize(panel?.maxWidth);
|
|
612
|
+
if (maxWidth) style["max-width"] = maxWidth;
|
|
613
|
+
return style;
|
|
614
|
+
}
|
|
615
|
+
/** The HEIGHT half of `dropdown`, on the scrolling body — see `_dropdownPanelStyle`. */
|
|
616
|
+
get _dropdownBodyStyle() {
|
|
617
|
+
const style = {};
|
|
618
|
+
const panel = this.dropdown;
|
|
619
|
+
const minHeight = toCssSize(panel?.minHeight);
|
|
620
|
+
if (minHeight) style.minHeight = minHeight;
|
|
621
|
+
const height = toCssSize(panel?.height) ?? this._toCssLength(this.dropdownHeight);
|
|
622
|
+
if (height) style.height = height;
|
|
623
|
+
const maxHeight = toCssSize(panel?.maxHeight) ?? this._toCssLength(this.dropdownMaxHeight);
|
|
624
|
+
if (maxHeight) style.maxHeight = maxHeight;
|
|
625
|
+
else if (height) style.maxHeight = height;
|
|
626
|
+
else if (this._scrollAutoMaxHeight) style.maxHeight = this._scrollAutoMaxHeight;
|
|
627
|
+
return style;
|
|
628
|
+
}
|
|
629
|
+
get _normalizedItems() {
|
|
630
|
+
if (this._normalizedMemo?.epoch !== this._itemsEpoch) this._normalizedMemo = {
|
|
631
|
+
epoch: this._itemsEpoch,
|
|
632
|
+
items: this._normalizeItems(this._ds.sourceItems)
|
|
633
|
+
};
|
|
634
|
+
return this._normalizedMemo.items;
|
|
635
|
+
}
|
|
636
|
+
/** Sanitised chunk size for array-mode paging (>= 1). */
|
|
637
|
+
get _pageSize() {
|
|
638
|
+
const n = Math.floor(Number(this.pageSize));
|
|
639
|
+
return Number.isFinite(n) && n > 0 ? n : 10;
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* The effective load-more mode. Off when unset/false; otherwise 'button' only
|
|
643
|
+
* for the explicit `load-more="button"`, and 'scroll' for everything else that
|
|
644
|
+
* enables it (bare attribute, empty string, `true`, or `"scroll"`). Scroll is
|
|
645
|
+
* the default so enabling load-more "just works" without picking a mode.
|
|
646
|
+
*/
|
|
647
|
+
get _loadMoreMode() {
|
|
648
|
+
const v = this.loadMore;
|
|
649
|
+
if (v === void 0 || v === null || v === false) return void 0;
|
|
650
|
+
return v === "button" ? "button" : "scroll";
|
|
651
|
+
}
|
|
652
|
+
/**
|
|
653
|
+
* The rows to actually render — the controller's visible slice, normalized.
|
|
654
|
+
* (Array load-more reveals a chunk; DataSource mode accumulates pages.)
|
|
655
|
+
*/
|
|
656
|
+
get _visibleItems() {
|
|
657
|
+
if (this._visibleMemo?.epoch !== this._itemsEpoch) this._visibleMemo = {
|
|
658
|
+
epoch: this._itemsEpoch,
|
|
659
|
+
items: this._normalizeItems(this._ds.visibleItems)
|
|
660
|
+
};
|
|
661
|
+
return this._visibleMemo.items;
|
|
662
|
+
}
|
|
663
|
+
get _selectedItem() {
|
|
664
|
+
return this._leafItems.find((item) => this._isSameValue(this._resolveItemValue(item), this.value));
|
|
665
|
+
}
|
|
666
|
+
/** Grouping is active when at least one display-group accessor is given. */
|
|
667
|
+
get _grouped() {
|
|
668
|
+
return Array.isArray(this.displayGroup) && this.displayGroup.length > 0;
|
|
669
|
+
}
|
|
670
|
+
/** A node is a group when its `groupItems` field holds an array. */
|
|
671
|
+
_isGroupNode(x) {
|
|
672
|
+
return !!x && typeof x === "object" && Array.isArray(x[this.groupItems]);
|
|
673
|
+
}
|
|
674
|
+
/** Descend `groupItems[0]` to the first leaf row — the group's representative. */
|
|
675
|
+
_firstLeaf(node) {
|
|
676
|
+
let cur = node;
|
|
677
|
+
let guard = 0;
|
|
678
|
+
while (this._isGroupNode(cur) && guard++ < 50) cur = cur[this.groupItems]?.[0];
|
|
679
|
+
return cur ?? void 0;
|
|
680
|
+
}
|
|
681
|
+
/** Resolve a group header's label from `displayGroup[level]` over a leaf row. */
|
|
682
|
+
_resolveGroupLabel(node, level) {
|
|
683
|
+
const accessor = this.displayGroup[level];
|
|
684
|
+
const leaf = this._firstLeaf(node);
|
|
685
|
+
if (typeof accessor === "function") return String(accessor(leaf ?? {}) ?? "");
|
|
686
|
+
if (typeof accessor === "string" && leaf && accessor in leaf) return String(leaf[accessor] ?? "");
|
|
687
|
+
const key = node[this.groupKey];
|
|
688
|
+
return key == null ? "" : String(key);
|
|
689
|
+
}
|
|
690
|
+
/** The string `display-group` entries — usable as server group/sort fields. */
|
|
691
|
+
_groupSortFields() {
|
|
692
|
+
return (this.displayGroup ?? []).filter((a) => typeof a === "string");
|
|
693
|
+
}
|
|
694
|
+
/** A `display-group` level's key for a row (string → field, function → call). */
|
|
695
|
+
_groupKeyOf(row, level) {
|
|
696
|
+
const accessor = this.displayGroup[level];
|
|
697
|
+
if (typeof accessor === "function") return accessor(row);
|
|
698
|
+
if (typeof accessor === "string") return row[accessor];
|
|
699
|
+
}
|
|
700
|
+
/**
|
|
701
|
+
* `group` mode: bucket flat rows into the nested `{ [groupKey], [groupItems] }`
|
|
702
|
+
* shape client-side, by `display-group` level. Buckets keep first-appearance
|
|
703
|
+
* order, so each group is contiguous and grows in place as more pages load.
|
|
704
|
+
*/
|
|
705
|
+
_buildClientTree(rows) {
|
|
706
|
+
const build = (items, level) => {
|
|
707
|
+
if (level >= this.displayGroup.length) return items;
|
|
708
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
709
|
+
for (const row of items) {
|
|
710
|
+
const key = this._groupKeyOf(row, level);
|
|
711
|
+
const ks = String(key);
|
|
712
|
+
let bucket = buckets.get(ks);
|
|
713
|
+
if (!bucket) buckets.set(ks, bucket = {
|
|
714
|
+
key,
|
|
715
|
+
rows: []
|
|
716
|
+
});
|
|
717
|
+
bucket.rows.push(row);
|
|
718
|
+
}
|
|
719
|
+
return [...buckets.values()].map((b) => ({
|
|
720
|
+
[this.groupKey]: b.key,
|
|
721
|
+
[this.groupItems]: build(b.rows, level + 1)
|
|
722
|
+
}));
|
|
723
|
+
};
|
|
724
|
+
return build(rows, 0);
|
|
725
|
+
}
|
|
726
|
+
/** The nested group nodes to render — built client-side in `group` mode. */
|
|
727
|
+
_groupNodes() {
|
|
728
|
+
if (this.group) {
|
|
729
|
+
const leaves = this._visibleItems.filter((it) => this._searchMatches(it));
|
|
730
|
+
return this._buildClientTree(leaves);
|
|
731
|
+
}
|
|
732
|
+
return this._ds.visibleItems ?? [];
|
|
733
|
+
}
|
|
734
|
+
/** Every leaf row — for value/display lookup. */
|
|
735
|
+
get _leafItems() {
|
|
736
|
+
if (this._leafMemo?.epoch === this._itemsEpoch) return this._leafMemo.items;
|
|
737
|
+
const items = this._computeLeafItems();
|
|
738
|
+
this._leafMemo = {
|
|
739
|
+
epoch: this._itemsEpoch,
|
|
740
|
+
items
|
|
741
|
+
};
|
|
742
|
+
return items;
|
|
743
|
+
}
|
|
744
|
+
_computeLeafItems() {
|
|
745
|
+
if (!this._grouped) return this._normalizedItems;
|
|
746
|
+
if (this.group) return [...this._ds.sourceItems];
|
|
747
|
+
const out = [];
|
|
748
|
+
const walk = (nodes) => {
|
|
749
|
+
for (const n of nodes) if (this._isGroupNode(n)) walk(n[this.groupItems]);
|
|
750
|
+
else if (n != null) out.push(n);
|
|
751
|
+
};
|
|
752
|
+
walk(this._ds.sourceItems ?? []);
|
|
753
|
+
return out;
|
|
754
|
+
}
|
|
755
|
+
/**
|
|
756
|
+
* Flatten the visible group tree into ordered header / item render rows.
|
|
757
|
+
* Leaves are search-filtered (client mode); empty groups are dropped.
|
|
758
|
+
*/
|
|
759
|
+
_groupRows() {
|
|
760
|
+
const filterLeaves = !this.group;
|
|
761
|
+
const build = (nodes, level, parentKey) => {
|
|
762
|
+
const rows = [];
|
|
763
|
+
nodes.forEach((node, i) => {
|
|
764
|
+
if (!this._isGroupNode(node)) {
|
|
765
|
+
const item = node;
|
|
766
|
+
if (item == null) return;
|
|
767
|
+
if (filterLeaves && !this._searchMatches(item)) return;
|
|
768
|
+
rows.push({
|
|
769
|
+
kind: "item",
|
|
770
|
+
item,
|
|
771
|
+
index: -1
|
|
772
|
+
});
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
775
|
+
const rec = node;
|
|
776
|
+
const path = `${parentKey}/${String(rec[this.groupKey])}#${i}`;
|
|
777
|
+
const children = build(rec[this.groupItems] ?? [], level + 1, path);
|
|
778
|
+
if (!children.length) return;
|
|
779
|
+
rows.push({
|
|
780
|
+
kind: "group",
|
|
781
|
+
level,
|
|
782
|
+
label: this._resolveGroupLabel(rec, level),
|
|
783
|
+
key: `g:${level}:${path}`
|
|
784
|
+
});
|
|
785
|
+
rows.push(...children);
|
|
786
|
+
});
|
|
787
|
+
return rows;
|
|
788
|
+
};
|
|
789
|
+
let idx = 0;
|
|
790
|
+
return build(this._groupNodes(), 0, "").map((r) => r.kind === "item" ? {
|
|
791
|
+
...r,
|
|
792
|
+
index: idx++
|
|
793
|
+
} : r);
|
|
794
|
+
}
|
|
795
|
+
/** Whether `search-value` names anything explicitly (vs falling back). */
|
|
796
|
+
get _hasSearchValue() {
|
|
797
|
+
const sv = this.searchValue;
|
|
798
|
+
if (Array.isArray(sv)) return sv.length > 0;
|
|
799
|
+
return typeof sv === "string" && !!sv.trim();
|
|
800
|
+
}
|
|
801
|
+
/**
|
|
802
|
+
* The natural fields searched alongside the `'*'` default when `search-value` is
|
|
803
|
+
* empty — the safety net, not the whole list.
|
|
804
|
+
*
|
|
805
|
+
* `'*'` resolves against loaded rows, so on a bound DataSource it expands to
|
|
806
|
+
* NOTHING until the first page lands (nothing loads on open, and a query can
|
|
807
|
+
* fire inside the debounce) — these keep that first query working. They are also
|
|
808
|
+
* exempt from the remote string-only rule, so a numeric `key-value` stays
|
|
809
|
+
* searchable. `display-value` contributes only when it's a string; a function
|
|
810
|
+
* builds text that no field expression can reach, which is why `_searchMatches`
|
|
811
|
+
* keeps matching the rendered display separately.
|
|
812
|
+
*/
|
|
813
|
+
_fallbackSearchFields() {
|
|
814
|
+
return [typeof this.displayValue === "string" ? this.displayValue : void 0, this.keyValue];
|
|
815
|
+
}
|
|
816
|
+
/**
|
|
817
|
+
* A cheap signature of the rows' SHAPE, for the memo keys below.
|
|
818
|
+
*
|
|
819
|
+
* Row count alone isn't enough once `'*'` is in play: the resolved field list
|
|
820
|
+
* depends on the rows' keys, and a remote source paging from one full page to
|
|
821
|
+
* the next keeps the same length while the shape can differ. Sampling the first
|
|
822
|
+
* and last row keeps this O(1) while catching that case.
|
|
823
|
+
*/
|
|
824
|
+
_rowsShapeKey(rows) {
|
|
825
|
+
const keysOf = (row) => row && typeof row === "object" ? Object.keys(row).join(",") : typeof row;
|
|
826
|
+
if (!rows.length) return "0";
|
|
827
|
+
return `${rows.length}:${keysOf(rows[0])}|${keysOf(rows[rows.length - 1])}`;
|
|
828
|
+
}
|
|
829
|
+
/**
|
|
830
|
+
* `search-value` resolved to concrete entries — `*` patterns expanded against
|
|
831
|
+
* the loaded rows. Memoized: a pattern samples up to 20 rows, so resolving per
|
|
832
|
+
* item (this feeds `_searchMatches`) would be O(items × fields) per keystroke.
|
|
833
|
+
*
|
|
834
|
+
* With no `search-value` this defaults to `'*'` (every top-level field) plus the
|
|
835
|
+
* natural fallbacks — see {@link _fallbackSearchFields}.
|
|
836
|
+
*/
|
|
837
|
+
_searchEntries(remote) {
|
|
838
|
+
const rows = this._normalizedItems;
|
|
839
|
+
const key = `${this._searchVersion} ${remote ? 1 : 0} ${this._rowsShapeKey(rows)}`;
|
|
840
|
+
if (this._entriesCache?.key === key) return this._entriesCache.entries;
|
|
841
|
+
const entries = resolveSearchFields({
|
|
842
|
+
searchValue: this.searchValue,
|
|
843
|
+
fallbackFields: this._fallbackSearchFields(),
|
|
844
|
+
rows,
|
|
845
|
+
remote,
|
|
846
|
+
defaultToWildcard: true
|
|
847
|
+
});
|
|
848
|
+
this._entriesCache = {
|
|
849
|
+
key,
|
|
850
|
+
entries
|
|
851
|
+
};
|
|
852
|
+
return entries;
|
|
853
|
+
}
|
|
854
|
+
/** The compiled client-side predicate for the current query (memoized). */
|
|
855
|
+
_searchPredicate() {
|
|
856
|
+
const query = this._query.trim();
|
|
857
|
+
const operation = this.searchOperation || "contains";
|
|
858
|
+
const rows = this._normalizedItems;
|
|
859
|
+
const key = `${this._searchVersion} ${operation} ${this._rowsShapeKey(rows)} ${query}`;
|
|
860
|
+
if (this._predicateCache?.key === key) return this._predicateCache.pred;
|
|
861
|
+
const pred = searchRowPredicate(this._searchEntries(false), query, operation);
|
|
862
|
+
this._predicateCache = {
|
|
863
|
+
key,
|
|
864
|
+
pred
|
|
865
|
+
};
|
|
866
|
+
return pred;
|
|
867
|
+
}
|
|
868
|
+
/** A bound DataSource is searched on the server; a plain array, client-side. */
|
|
869
|
+
_serverSearch() {
|
|
870
|
+
return !!this.dataSource;
|
|
871
|
+
}
|
|
872
|
+
/** Client-side match test (server mode already filtered → always true). */
|
|
873
|
+
_searchMatches(item) {
|
|
874
|
+
if (this._serverSearch()) return true;
|
|
875
|
+
if (!this._searchActive) return true;
|
|
876
|
+
const q = this._query.trim().toLowerCase();
|
|
877
|
+
if (!q) return true;
|
|
878
|
+
if (this._hasSearchValue) {
|
|
879
|
+
const pred = this._searchPredicate();
|
|
880
|
+
return pred ? pred(item) : true;
|
|
881
|
+
}
|
|
882
|
+
const display = this._resolveItemDisplay(item).toLowerCase();
|
|
883
|
+
const val = this._resolveItemValue(item);
|
|
884
|
+
const valStr = val == null ? "" : String(val).toLowerCase();
|
|
885
|
+
const pred = this._searchPredicate();
|
|
886
|
+
return display.includes(q) || valStr.includes(q) || (pred ? pred(item) : false);
|
|
887
|
+
}
|
|
888
|
+
_onSearchInput(event) {
|
|
889
|
+
if (this.disabled || this.readonly) return;
|
|
890
|
+
this._query = event.target.value;
|
|
891
|
+
this._searchActive = true;
|
|
892
|
+
this._open = true;
|
|
893
|
+
this._activeIndex = 0;
|
|
894
|
+
this._cursorPending = false;
|
|
895
|
+
this.requestUpdate();
|
|
896
|
+
if (this._searchTimer) clearTimeout(this._searchTimer);
|
|
897
|
+
const wait = Math.max(0, Number(this.searchDebounce) || 0);
|
|
898
|
+
this._searchTimer = setTimeout(() => void this._applySearch(this._query), wait);
|
|
899
|
+
}
|
|
900
|
+
/** Run the search: server query (debounced) or just re-render for client filter. */
|
|
901
|
+
async _applySearch(query) {
|
|
902
|
+
if (!this._serverSearch()) {
|
|
903
|
+
this.requestUpdate();
|
|
904
|
+
return;
|
|
905
|
+
}
|
|
906
|
+
await this._sourceSearch.apply(this.dataSource, {
|
|
907
|
+
query,
|
|
908
|
+
searchValue: this.searchValue,
|
|
909
|
+
fallbackFields: this._fallbackSearchFields(),
|
|
910
|
+
rows: this._normalizedItems,
|
|
911
|
+
remote: true,
|
|
912
|
+
defaultToWildcard: true,
|
|
913
|
+
operation: this.searchOperation || "contains"
|
|
914
|
+
});
|
|
915
|
+
}
|
|
916
|
+
/** Clear the typed query (and the source query, on close / select). */
|
|
917
|
+
_resetSearch() {
|
|
918
|
+
if (this._searchTimer) {
|
|
919
|
+
clearTimeout(this._searchTimer);
|
|
920
|
+
this._searchTimer = void 0;
|
|
921
|
+
}
|
|
922
|
+
const had = this._searchActive && !!this._query;
|
|
923
|
+
this._query = "";
|
|
924
|
+
this._searchActive = false;
|
|
925
|
+
this._activeIndex = -1;
|
|
926
|
+
if (had && this._serverSearch()) this._applySearch("");
|
|
927
|
+
}
|
|
928
|
+
/** The label shown in the field while not actively typing a query. */
|
|
929
|
+
get _displayText() {
|
|
930
|
+
const item = this._selectedItem;
|
|
931
|
+
return item ? this._resolveItemDisplay(item) : "";
|
|
932
|
+
}
|
|
933
|
+
/** Placeholder for the search field — a search hint while open, else the prompt. */
|
|
934
|
+
get _fieldPlaceholder() {
|
|
935
|
+
if ((this._open || this._searchActive) && this.searchPlaceholder) return this.searchPlaceholder;
|
|
936
|
+
return this.placeholder;
|
|
937
|
+
}
|
|
938
|
+
/**
|
|
939
|
+
* The selectable rows in render order — drives keyboard nav (`_activeIndex`)
|
|
940
|
+
* for the searchable combobox. Mirrors what `_renderItems` paints.
|
|
941
|
+
*/
|
|
942
|
+
/**
|
|
943
|
+
* Where the keyboard cursor goes when the list opens: the row matching the
|
|
944
|
+
* current value, else the first row.
|
|
945
|
+
*
|
|
946
|
+
* Deliberately runs the SAME predicate that paints `.selected` in
|
|
947
|
+
* `_renderOption`, over `_filteredItems` — the very list ↑/↓ and Enter index
|
|
948
|
+
* into — so the cursor is guaranteed to land on the row drawn as selected.
|
|
949
|
+
* Going via `_selectedItem` + `indexOf` would not work: that searches
|
|
950
|
+
* `_leafItems`, an unfiltered/unpaged array whose `_normalizeItems` wraps
|
|
951
|
+
* primitives in fresh objects per call, so identity would not hold. Grouping
|
|
952
|
+
* needs no special case — `_groupRows()` numbers leaf rows only, which is
|
|
953
|
+
* exactly what `_filteredItems` reconstructs.
|
|
954
|
+
*
|
|
955
|
+
* `-1` when the list is empty; `0` when the selected row is not in it (a page
|
|
956
|
+
* the user hasn't scrolled to, or a server query that didn't return it), which
|
|
957
|
+
* is the behaviour this component has always had.
|
|
958
|
+
*/
|
|
959
|
+
_initialActiveIndex() {
|
|
960
|
+
const items = this._filteredItems;
|
|
961
|
+
if (!items.length) return -1;
|
|
962
|
+
const index = items.findIndex((item) => this._isSameValue(this._resolveItemValue(item), this.value));
|
|
963
|
+
return index >= 0 ? index : 0;
|
|
964
|
+
}
|
|
965
|
+
get _filteredItems() {
|
|
966
|
+
if (this._grouped) return this._groupRows().filter((r) => r.kind === "item").map((r) => r.item);
|
|
967
|
+
return this._visibleItems.filter((item) => this._searchMatches(item));
|
|
968
|
+
}
|
|
969
|
+
get _hasValue() {
|
|
970
|
+
return this.value !== null && this.value !== void 0 && this.value !== "";
|
|
971
|
+
}
|
|
972
|
+
get _hasLabelSlot() {
|
|
973
|
+
return this._hasLabelSlotState;
|
|
974
|
+
}
|
|
975
|
+
get _hasHelperSlot() {
|
|
976
|
+
return this._hasHelperSlotState;
|
|
977
|
+
}
|
|
978
|
+
get _hasPrefixSlot() {
|
|
979
|
+
return this._hasPrefixSlotState;
|
|
980
|
+
}
|
|
981
|
+
get _hasSuffixSlot() {
|
|
982
|
+
return this._hasSuffixSlotState;
|
|
983
|
+
}
|
|
984
|
+
get _resolvedValidationState() {
|
|
985
|
+
if (this.validationState && this.validationState !== "default") return this.validationState;
|
|
986
|
+
if (this.errorMessage) return "invalid";
|
|
987
|
+
if (this.successMessage) return "valid";
|
|
988
|
+
return "default";
|
|
989
|
+
}
|
|
990
|
+
get _wrapperClasses() {
|
|
991
|
+
return [
|
|
992
|
+
"mono-select",
|
|
993
|
+
this.size,
|
|
994
|
+
this.color,
|
|
995
|
+
this.variant,
|
|
996
|
+
this._open ? "open" : "",
|
|
997
|
+
this.disabled ? "disabled" : "",
|
|
998
|
+
this.readonly ? "readonly" : "",
|
|
999
|
+
this._resolvedValidationState !== "default" ? `is-${this._resolvedValidationState}` : "",
|
|
1000
|
+
this._hasValue ? "has-value" : "",
|
|
1001
|
+
this._hasPrefixSlot ? "has-prefix" : "",
|
|
1002
|
+
this._hasSuffixSlot ? "has-suffix" : "",
|
|
1003
|
+
this.cssClassName,
|
|
1004
|
+
this.cssClass?.root
|
|
1005
|
+
].filter(Boolean).join(" ");
|
|
1006
|
+
}
|
|
1007
|
+
get _triggerClasses() {
|
|
1008
|
+
return [
|
|
1009
|
+
this._cls("mono-select-trigger", "trigger"),
|
|
1010
|
+
this.size,
|
|
1011
|
+
this.color,
|
|
1012
|
+
this.variant,
|
|
1013
|
+
this.disabled ? "disabled" : "",
|
|
1014
|
+
this.readonly ? "readonly" : ""
|
|
1015
|
+
].filter(Boolean).join(" ");
|
|
1016
|
+
}
|
|
1017
|
+
_createModelDetail(args) {
|
|
1018
|
+
return {
|
|
1019
|
+
modelValue: args.modelValue,
|
|
1020
|
+
currentValue: args.modelValue,
|
|
1021
|
+
oldValue: args.oldValue,
|
|
1022
|
+
value: args.modelValue,
|
|
1023
|
+
selectedItem: this._leafItems.find((item) => this._isSameValue(this._resolveItemValue(item), args.modelValue)),
|
|
1024
|
+
sourceEvent: args.sourceEvent
|
|
1025
|
+
};
|
|
1026
|
+
}
|
|
1027
|
+
_emitChange(detail) {
|
|
1028
|
+
dispatchMonoEvent(this, "change", detail);
|
|
1029
|
+
}
|
|
1030
|
+
_emitClear(detail) {
|
|
1031
|
+
dispatchMonoEvent(this, "clear", detail);
|
|
1032
|
+
}
|
|
1033
|
+
_toggleOpen(event) {
|
|
1034
|
+
event?.stopPropagation();
|
|
1035
|
+
if (this.disabled || this.readonly) return;
|
|
1036
|
+
if (this._open) this._close();
|
|
1037
|
+
else this._open = true;
|
|
1038
|
+
}
|
|
1039
|
+
_close() {
|
|
1040
|
+
this._open = false;
|
|
1041
|
+
this._resetSearch();
|
|
1042
|
+
}
|
|
1043
|
+
_handleTriggerKeydown(event) {
|
|
1044
|
+
if (this.disabled || this.readonly) return;
|
|
1045
|
+
if (!this._open) {
|
|
1046
|
+
if (event.key === "Enter" || event.key === " " || event.key === "ArrowDown") {
|
|
1047
|
+
event.preventDefault();
|
|
1048
|
+
this._open = true;
|
|
1049
|
+
return;
|
|
1050
|
+
}
|
|
1051
|
+
if (event.key === "Escape") {
|
|
1052
|
+
event.preventDefault();
|
|
1053
|
+
this._close();
|
|
1054
|
+
}
|
|
1055
|
+
return;
|
|
1056
|
+
}
|
|
1057
|
+
this._handleListKeydown(event);
|
|
1058
|
+
}
|
|
1059
|
+
/**
|
|
1060
|
+
* ↑/↓/Enter/Esc against the rendered list, shared by the trigger and the
|
|
1061
|
+
* search field so both modes navigate identically.
|
|
1062
|
+
*/
|
|
1063
|
+
_handleListKeydown(event) {
|
|
1064
|
+
const items = this._filteredItems;
|
|
1065
|
+
if (event.key === "ArrowDown") {
|
|
1066
|
+
event.preventDefault();
|
|
1067
|
+
this._open = true;
|
|
1068
|
+
this._activeIndex = items.length ? Math.min(this._activeIndex + 1, items.length - 1) : -1;
|
|
1069
|
+
return true;
|
|
1070
|
+
}
|
|
1071
|
+
if (event.key === "ArrowUp") {
|
|
1072
|
+
event.preventDefault();
|
|
1073
|
+
this._activeIndex = items.length ? Math.max(this._activeIndex - 1, 0) : -1;
|
|
1074
|
+
return true;
|
|
1075
|
+
}
|
|
1076
|
+
if (event.key === "Enter") {
|
|
1077
|
+
const active = this._activeIndex >= 0 ? items[this._activeIndex] : void 0;
|
|
1078
|
+
if (!active) return false;
|
|
1079
|
+
event.preventDefault();
|
|
1080
|
+
if (!active.disabled) this._selectItem(active, event);
|
|
1081
|
+
return true;
|
|
1082
|
+
}
|
|
1083
|
+
if (event.key === "Escape") {
|
|
1084
|
+
event.preventDefault();
|
|
1085
|
+
this._close();
|
|
1086
|
+
return true;
|
|
1087
|
+
}
|
|
1088
|
+
return false;
|
|
1089
|
+
}
|
|
1090
|
+
/**
|
|
1091
|
+
* Focusing the field selects the shown label so the first keystroke replaces
|
|
1092
|
+
* it (type to filter). It does NOT open the dropdown: a Tab into the field is
|
|
1093
|
+
* not a request to see the list — typing, ↓, a click in the field or the
|
|
1094
|
+
* chevron are.
|
|
1095
|
+
*/
|
|
1096
|
+
_handleSearchFocus(event) {
|
|
1097
|
+
if (this.disabled || this.readonly) return;
|
|
1098
|
+
event.target.select();
|
|
1099
|
+
}
|
|
1100
|
+
/**
|
|
1101
|
+
* Clicking anywhere in a SEARCHABLE field opens it and focuses the input.
|
|
1102
|
+
* Opens only — a click in a text input while the list is open is caret
|
|
1103
|
+
* placement or text selection, never a toggle; the chevron, Escape and an
|
|
1104
|
+
* outside click close. (The plain trigger is a button that toggles instead:
|
|
1105
|
+
* nothing to type there, so a second click means "close".)
|
|
1106
|
+
*/
|
|
1107
|
+
_handleFieldClick(event) {
|
|
1108
|
+
event.stopPropagation();
|
|
1109
|
+
if (this.disabled || this.readonly) return;
|
|
1110
|
+
this._open = true;
|
|
1111
|
+
this._searchFieldEl?.focus();
|
|
1112
|
+
}
|
|
1113
|
+
/** Keyboard nav for the search field: arrows move, Enter selects, Esc closes. */
|
|
1114
|
+
_handleSearchKeydown(event) {
|
|
1115
|
+
if (this.disabled || this.readonly) return;
|
|
1116
|
+
this._handleListKeydown(event);
|
|
1117
|
+
}
|
|
1118
|
+
_selectItem(item, event) {
|
|
1119
|
+
event?.preventDefault();
|
|
1120
|
+
event?.stopPropagation();
|
|
1121
|
+
if (this.disabled || this.readonly || item.disabled) return;
|
|
1122
|
+
const oldValue = this.modelValue;
|
|
1123
|
+
const nextValue = this._resolveItemValue(item);
|
|
1124
|
+
this.value = nextValue;
|
|
1125
|
+
this.modelValue = nextValue;
|
|
1126
|
+
this._open = false;
|
|
1127
|
+
this._resetSearch();
|
|
1128
|
+
const detail = this._createModelDetail({
|
|
1129
|
+
modelValue: nextValue,
|
|
1130
|
+
oldValue,
|
|
1131
|
+
sourceEvent: event
|
|
1132
|
+
});
|
|
1133
|
+
this._emitChange(detail);
|
|
1134
|
+
if (this.searchable) this.updateComplete.then(() => this._searchFieldEl?.select());
|
|
1135
|
+
else this._triggerEl?.focus();
|
|
1136
|
+
}
|
|
1137
|
+
_clear(event) {
|
|
1138
|
+
event.preventDefault();
|
|
1139
|
+
event.stopPropagation();
|
|
1140
|
+
if (this.disabled || this.readonly) return;
|
|
1141
|
+
const oldValue = this.modelValue;
|
|
1142
|
+
const nextValue = null;
|
|
1143
|
+
this.value = nextValue;
|
|
1144
|
+
this.modelValue = nextValue;
|
|
1145
|
+
this._open = false;
|
|
1146
|
+
this._resetSearch();
|
|
1147
|
+
const detail = this._createModelDetail({
|
|
1148
|
+
modelValue: nextValue,
|
|
1149
|
+
oldValue,
|
|
1150
|
+
sourceEvent: event
|
|
1151
|
+
});
|
|
1152
|
+
this._emitChange(detail);
|
|
1153
|
+
this._emitClear(detail);
|
|
1154
|
+
if (this.searchable) this._searchFieldEl?.focus();
|
|
1155
|
+
}
|
|
1156
|
+
_renderLabel() {
|
|
1157
|
+
const hasContent = !!this.label || this._hasLabelSlot;
|
|
1158
|
+
if (!hasContent && !this._slotsAlwaysRender) return nothing;
|
|
1159
|
+
return html`
|
|
1160
|
+
<label
|
|
1161
|
+
class=${this._cls("mono-select-label", "label")}
|
|
1162
|
+
mono-label
|
|
1163
|
+
for=${this._selectId}
|
|
1164
|
+
?mono-empty=${!hasContent}
|
|
1165
|
+
>
|
|
1166
|
+
${this._slotOutlet("label", this.label)}
|
|
1167
|
+
|
|
1168
|
+
${this.required ? html`
|
|
1169
|
+
<span class=${this._cls("mono-select-required", "required")} mono-required-mark>
|
|
1170
|
+
*
|
|
1171
|
+
</span>
|
|
1172
|
+
` : nothing}
|
|
1173
|
+
</label>
|
|
1174
|
+
`;
|
|
1175
|
+
}
|
|
1176
|
+
_renderValue() {
|
|
1177
|
+
if (this._hasValue && this._selectedItem) return html`
|
|
1178
|
+
<span class=${this._cls("mono-select-value", "value")} mono-value>
|
|
1179
|
+
${this._hasPrefixSlot || this._slotsAlwaysRender ? this._slotOutlet("prefix") : nothing}
|
|
1180
|
+
|
|
1181
|
+
<span>${this._resolveItemDisplay(this._selectedItem)}</span>
|
|
1182
|
+
|
|
1183
|
+
${this._hasSuffixSlot || this._slotsAlwaysRender ? this._slotOutlet("suffix") : nothing}
|
|
1184
|
+
</span>
|
|
1185
|
+
`;
|
|
1186
|
+
return html`
|
|
1187
|
+
<span
|
|
1188
|
+
class=${`${this._cls("mono-select-value", "value")} ${this._cls("mono-select-placeholder", "placeholder")}`}
|
|
1189
|
+
mono-value
|
|
1190
|
+
mono-placeholder
|
|
1191
|
+
>
|
|
1192
|
+
${this.placeholder}
|
|
1193
|
+
</span>
|
|
1194
|
+
`;
|
|
1195
|
+
}
|
|
1196
|
+
/** A single selectable option button. `index` drives the keyboard-active highlight. */
|
|
1197
|
+
_renderOption(item, index = -1) {
|
|
1198
|
+
const selected = this._isSameValue(this._resolveItemValue(item), this.value);
|
|
1199
|
+
const active = index >= 0 && index === this._activeIndex;
|
|
1200
|
+
return html`
|
|
1201
|
+
<button
|
|
1202
|
+
type="button"
|
|
1203
|
+
role="option"
|
|
1204
|
+
class=${[
|
|
1205
|
+
this._cls("mono-select-item", "item"),
|
|
1206
|
+
active ? `active ${this.cssClass?.itemActive ?? ""}` : "",
|
|
1207
|
+
selected ? `selected ${this.cssClass?.itemSelected ?? ""}` : "",
|
|
1208
|
+
item.disabled ? `disabled ${this.cssClass?.itemDisabled ?? ""}` : ""
|
|
1209
|
+
].filter(Boolean).join(" ")}
|
|
1210
|
+
mono-item
|
|
1211
|
+
?mono-active=${active}
|
|
1212
|
+
?mono-selected=${selected}
|
|
1213
|
+
?mono-disabled=${!!item.disabled}
|
|
1214
|
+
aria-selected=${selected ? "true" : "false"}
|
|
1215
|
+
?disabled=${item.disabled}
|
|
1216
|
+
@mousedown=${(event) => event.preventDefault()}
|
|
1217
|
+
@click=${(event) => this._selectItem(item, event)}
|
|
1218
|
+
>
|
|
1219
|
+
${this._resolveItemDisplay(item)}
|
|
1220
|
+
</button>
|
|
1221
|
+
`;
|
|
1222
|
+
}
|
|
1223
|
+
/**
|
|
1224
|
+
* The flat entry list published to `form.items()[key].list`.
|
|
1225
|
+
*
|
|
1226
|
+
* The SAME sequence the component renders — group headers interleaved with their leaves — so a
|
|
1227
|
+
* consumer looping it produces one node per row, in order, with nothing to pair up by hand.
|
|
1228
|
+
*
|
|
1229
|
+
* `key` is `item[keyValue]` via `_resolveItemValue`, the same value selection is keyed by, so
|
|
1230
|
+
* the feature introduces no second notion of a key.
|
|
1231
|
+
*/
|
|
1232
|
+
_listEntries() {
|
|
1233
|
+
const rowEntry = (item, level, index) => ({
|
|
1234
|
+
type: "row",
|
|
1235
|
+
key: String(this._resolveItemValue(item) ?? ""),
|
|
1236
|
+
item,
|
|
1237
|
+
level,
|
|
1238
|
+
selected: this._isSameValue(this._resolveItemValue(item), this.value),
|
|
1239
|
+
active: index >= 0 && index === this._activeIndex
|
|
1240
|
+
});
|
|
1241
|
+
if (this._grouped) {
|
|
1242
|
+
const rows = this._groupRows();
|
|
1243
|
+
const leavesFrom = (start, level) => {
|
|
1244
|
+
const out = [];
|
|
1245
|
+
for (let i = start + 1; i < rows.length; i++) {
|
|
1246
|
+
const row = rows[i];
|
|
1247
|
+
if (row.kind === "group") {
|
|
1248
|
+
if (row.level <= level) break;
|
|
1249
|
+
continue;
|
|
1250
|
+
}
|
|
1251
|
+
out.push(row.item);
|
|
1252
|
+
}
|
|
1253
|
+
return out;
|
|
1254
|
+
};
|
|
1255
|
+
let rowLevel = 0;
|
|
1256
|
+
return rows.map((row, i) => {
|
|
1257
|
+
if (row.kind === "group") {
|
|
1258
|
+
rowLevel = row.level + 1;
|
|
1259
|
+
return {
|
|
1260
|
+
type: "group",
|
|
1261
|
+
key: row.key,
|
|
1262
|
+
label: row.label,
|
|
1263
|
+
level: row.level,
|
|
1264
|
+
items: leavesFrom(i, row.level)
|
|
1265
|
+
};
|
|
1266
|
+
}
|
|
1267
|
+
return rowEntry(row.item, rowLevel, row.index);
|
|
1268
|
+
});
|
|
1269
|
+
}
|
|
1270
|
+
return this._filteredItems.map((item, index) => rowEntry(item, 0, index));
|
|
1271
|
+
}
|
|
1272
|
+
/**
|
|
1273
|
+
* Hand the form the current entries — but only a NEW array when they actually moved.
|
|
1274
|
+
*
|
|
1275
|
+
* This runs from `updated()`, so it fires on every render; the controller notifies on a changed
|
|
1276
|
+
* list, and that notify re-renders this control. Returning the same array reference is what keeps
|
|
1277
|
+
* that from looping forever. Identity of `item` counts as a change: a reloaded DataSource hands
|
|
1278
|
+
* back fresh row objects under the same keys, and a consumer reading `e.item.Nama` must see them.
|
|
1279
|
+
*/
|
|
1280
|
+
_syncListEntries() {
|
|
1281
|
+
const next = this._listEntries();
|
|
1282
|
+
const prev = this._publishedEntries;
|
|
1283
|
+
let same = prev.length === next.length;
|
|
1284
|
+
if (same) for (let i = 0; i < next.length; i++) {
|
|
1285
|
+
const a = prev[i];
|
|
1286
|
+
const b = next[i];
|
|
1287
|
+
if (a.type !== b.type || a.key !== b.key || a.item !== b.item || a.selected !== b.selected || a.active !== b.active) {
|
|
1288
|
+
same = false;
|
|
1289
|
+
break;
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
if (same) return;
|
|
1293
|
+
this._publishedEntries = next;
|
|
1294
|
+
this._publishList(next);
|
|
1295
|
+
}
|
|
1296
|
+
/**
|
|
1297
|
+
* Where the consumer's `slot="list"` content goes — overridden per build.
|
|
1298
|
+
*
|
|
1299
|
+
* mono places that content as ONE block and never reaches inside it. Moving a `v-for`'s children
|
|
1300
|
+
* is not survivable: Vue inserts a new row with `parent.insertBefore(node, anchor)` where the
|
|
1301
|
+
* anchor is the existing node at that position, so relocating one makes the consumer's next
|
|
1302
|
+
* insert throw `NotFoundError`. Hence one block, and hence `data-mono-item-key` — with the rows
|
|
1303
|
+
* out of reach, a delegated click is the only way back to the item.
|
|
1304
|
+
*/
|
|
1305
|
+
renderListSlot() {
|
|
1306
|
+
return html``;
|
|
1307
|
+
}
|
|
1308
|
+
/**
|
|
1309
|
+
* The entry a click landed on — by POSITION, so a consumer writes a plain `v-for` and nothing else.
|
|
1310
|
+
*
|
|
1311
|
+
* mono cannot read a node's item off the node: it published the list, but the DOM was built by
|
|
1312
|
+
* someone else. What it CAN do is count. The wrapper's Nth element child is the Nth published
|
|
1313
|
+
* entry, because that is the contract the slot already states — one flat loop, one node per entry,
|
|
1314
|
+
* in order — and here that contract is CHECKED rather than assumed: if the two lengths disagree,
|
|
1315
|
+
* this refuses the click instead of picking the wrong row.
|
|
1316
|
+
*
|
|
1317
|
+
* Position is resolved at CLICK time, never cached. That is what makes it safe with no observer
|
|
1318
|
+
* and no re-stamping: by the time a human clicks, the framework has long finished patching, so
|
|
1319
|
+
* there is no window where a stale pairing could be consulted.
|
|
1320
|
+
*
|
|
1321
|
+
* `data-mono-item-key` still wins when present — the escape hatch for a wrapper that cannot emit
|
|
1322
|
+
* exactly one element per entry (a sticky header of your own, a row that renders as a fragment).
|
|
1323
|
+
*/
|
|
1324
|
+
/**
|
|
1325
|
+
* The consumer's `slot="list"` wrapper, wherever the build keeps it.
|
|
1326
|
+
*
|
|
1327
|
+
* The shadow build never moves it — it stays a light child of the host and is PROJECTED — so
|
|
1328
|
+
* that is the default. The light build moves it into the panel and overrides this with the node
|
|
1329
|
+
* it captured, which is also findable while the panel is closed and the wrapper parked.
|
|
1330
|
+
*/
|
|
1331
|
+
get _listSlotWrapper() {
|
|
1332
|
+
return this._lateListSlot.find();
|
|
1333
|
+
}
|
|
1334
|
+
/**
|
|
1335
|
+
* Re-decorate whenever the consumer re-renders their rows.
|
|
1336
|
+
*
|
|
1337
|
+
* `_syncListChrome()` runs from `updated()`, but a framework patches the wrapper on ITS next
|
|
1338
|
+
* tick — so a row the search box just revealed would be born undecorated and stay that way until
|
|
1339
|
+
* something else made mono render. This closes that gap.
|
|
1340
|
+
*
|
|
1341
|
+
* `childList` on the WRAPPER, which is exactly the churn {@link LateSlotWatcher} refuses on the
|
|
1342
|
+
* host: there the consumer's row traffic is noise, here it IS the signal. No `subtree`, so
|
|
1343
|
+
* mono's own attribute writes cannot re-trigger it.
|
|
1344
|
+
*/
|
|
1345
|
+
_watchListChrome() {
|
|
1346
|
+
if (typeof MutationObserver === "undefined") return;
|
|
1347
|
+
const wrapper = this._listSlotWrapper;
|
|
1348
|
+
if (!wrapper || wrapper === this._observedListWrapper) return;
|
|
1349
|
+
this._listChromeObserver?.disconnect();
|
|
1350
|
+
this._observedListWrapper = wrapper;
|
|
1351
|
+
this._listChromeObserver = new MutationObserver(() => this._syncListChrome());
|
|
1352
|
+
this._listChromeObserver.observe(wrapper, { childList: true });
|
|
1353
|
+
}
|
|
1354
|
+
_stopWatchingListChrome() {
|
|
1355
|
+
this._listChromeObserver?.disconnect();
|
|
1356
|
+
this._listChromeObserver = void 0;
|
|
1357
|
+
this._observedListWrapper = void 0;
|
|
1358
|
+
}
|
|
1359
|
+
/**
|
|
1360
|
+
* Decorate the lines the consumer rendered — the half of this feature that keeps the SLOT about
|
|
1361
|
+
* markup and mono about behaviour.
|
|
1362
|
+
*
|
|
1363
|
+
* Your template says what a line LOOKS like; the state it is in is stamped here, as `data-*`
|
|
1364
|
+
* attributes, so nothing in that template has to bind `e.selected` or `e.active` to say so.
|
|
1365
|
+
*
|
|
1366
|
+
* Where the tag input also injects a checkbox, this stops at the stamp: a select carries no
|
|
1367
|
+
* checkbox and no select-all, so there is no chrome to put anywhere.
|
|
1368
|
+
*
|
|
1369
|
+
* Three rules keep this safe beside a framework:
|
|
1370
|
+
* · children are ANNOTATED only, never moved, reordered or removed — every `insertBefore`
|
|
1371
|
+
* anchor a `v-for` patches against stays valid;
|
|
1372
|
+
* · `data-*` only, never `class` — `class` is the consumer's binding and would be clobbered;
|
|
1373
|
+
* · nothing is stamped unless the lines and the published entries match 1:1.
|
|
1374
|
+
*/
|
|
1375
|
+
_syncListChrome() {
|
|
1376
|
+
if (!this._hasListSlotState) return;
|
|
1377
|
+
const wrapper = this._listSlotWrapper;
|
|
1378
|
+
if (!wrapper) return;
|
|
1379
|
+
const children = Array.from(wrapper.children);
|
|
1380
|
+
const entries = this._publishedEntries;
|
|
1381
|
+
if (children.length !== entries.length) return;
|
|
1382
|
+
for (let i = 0; i < children.length; i++) {
|
|
1383
|
+
const node = children[i];
|
|
1384
|
+
const entry = entries[i];
|
|
1385
|
+
node.setAttribute("data-mono-type", entry.type);
|
|
1386
|
+
node.setAttribute("data-mono-level", String(entry.level ?? 0));
|
|
1387
|
+
node.setAttribute("data-mono-key", entry.key);
|
|
1388
|
+
if (entry.type === "group") continue;
|
|
1389
|
+
node.toggleAttribute("data-mono-selected", !!entry.selected);
|
|
1390
|
+
node.toggleAttribute("data-mono-active", !!entry.active);
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
_entryFromNode(node) {
|
|
1394
|
+
const keyed = node.closest?.("[data-mono-item-key]");
|
|
1395
|
+
if (keyed) {
|
|
1396
|
+
const key = keyed.getAttribute("data-mono-item-key");
|
|
1397
|
+
return this._publishedEntries.find((e) => e.type === "row" && e.key === key);
|
|
1398
|
+
}
|
|
1399
|
+
const wrapper = node.closest?.("[slot=\"list\"]");
|
|
1400
|
+
if (!wrapper) return void 0;
|
|
1401
|
+
let row = node;
|
|
1402
|
+
while (row && row.parentElement !== wrapper) row = row.parentElement;
|
|
1403
|
+
if (!row) return void 0;
|
|
1404
|
+
const children = Array.from(wrapper.children);
|
|
1405
|
+
if (children.length !== this._publishedEntries.length) {
|
|
1406
|
+
console.warn(`[mono-select] slot="list" rendered ${children.length} element(s) for ${this._publishedEntries.length} option(s), so a click cannot be paired with its row. Render exactly one element per entry, or put data-mono-item-key="<entry.key>" on each row.`);
|
|
1407
|
+
return;
|
|
1408
|
+
}
|
|
1409
|
+
const entry = this._publishedEntries[children.indexOf(row)];
|
|
1410
|
+
return entry?.type === "row" ? entry : void 0;
|
|
1411
|
+
}
|
|
1412
|
+
_emptyRow() {
|
|
1413
|
+
const text = this.dataSource && this._ds.loading ? "Loading…" : this._query ? "No matches" : "No items";
|
|
1414
|
+
return html`<div class=${this._cls("mono-select-item disabled", "itemDisabled")} mono-empty-row>${text}</div>`;
|
|
1415
|
+
}
|
|
1416
|
+
_renderItems() {
|
|
1417
|
+
if (this._hasListSlotState) return html`
|
|
1418
|
+
${this._filteredItems.length ? nothing : this._emptyRow()}
|
|
1419
|
+
${this.renderListSlot()}
|
|
1420
|
+
`;
|
|
1421
|
+
if (this._grouped) {
|
|
1422
|
+
const rows = this._groupRows();
|
|
1423
|
+
if (!rows.some((r) => r.kind === "item")) return this._emptyRow();
|
|
1424
|
+
return html`
|
|
1425
|
+
${rows.map((row) => row.kind === "group" ? html`<div
|
|
1426
|
+
class=${`${this._cls("mono-select-group", "group")}${this.groupSticky ? " sticky" : ""}`}
|
|
1427
|
+
mono-group
|
|
1428
|
+
mono-level=${row.level}
|
|
1429
|
+
?mono-sticky=${this.groupSticky}
|
|
1430
|
+
data-level=${row.level}
|
|
1431
|
+
role="presentation"
|
|
1432
|
+
>
|
|
1433
|
+
${row.label}
|
|
1434
|
+
</div>` : this._renderOption(row.item, row.index))}
|
|
1435
|
+
`;
|
|
1436
|
+
}
|
|
1437
|
+
const items = this._visibleItems.filter((item) => this._searchMatches(item));
|
|
1438
|
+
if (!items.length) return this._emptyRow();
|
|
1439
|
+
return html`${items.map((item, index) => this._renderOption(item, index))}`;
|
|
1440
|
+
}
|
|
1441
|
+
_renderLoadMore() {
|
|
1442
|
+
if (!this._loadMoreMode) return nothing;
|
|
1443
|
+
if (!this._normalizedItems.length || this._ds.atLastPage) return nothing;
|
|
1444
|
+
if (this._ds.loadingMore) return html`
|
|
1445
|
+
<div class=${`${this._cls("mono-select-load-more", "loadMore")} loading`} mono-load-more mono-loading>
|
|
1446
|
+
Loading…
|
|
1447
|
+
</div>
|
|
1448
|
+
`;
|
|
1449
|
+
if (this._loadMoreMode !== "button") return nothing;
|
|
1450
|
+
return html`
|
|
1451
|
+
<button
|
|
1452
|
+
type="button"
|
|
1453
|
+
class=${this._cls("mono-select-load-more", "loadMore")}
|
|
1454
|
+
mono-load-more
|
|
1455
|
+
@click=${(event) => {
|
|
1456
|
+
event.preventDefault();
|
|
1457
|
+
event.stopPropagation();
|
|
1458
|
+
this._ds.loadMore();
|
|
1459
|
+
}}
|
|
1460
|
+
>
|
|
1461
|
+
Load more
|
|
1462
|
+
</button>
|
|
1463
|
+
`;
|
|
1464
|
+
}
|
|
1465
|
+
_renderHelper() {
|
|
1466
|
+
const base = this._cls("mono-select-message", "message");
|
|
1467
|
+
if (this.validationMessage) {
|
|
1468
|
+
const state = this._resolvedValidationState;
|
|
1469
|
+
return html`
|
|
1470
|
+
<div class=${`${base} ${state}`} mono-message=${state} role=${state === "invalid" ? "alert" : nothing}>
|
|
1471
|
+
${this.validationMessage}
|
|
1472
|
+
</div>
|
|
1473
|
+
`;
|
|
1474
|
+
}
|
|
1475
|
+
if (this.errorMessage) return html`
|
|
1476
|
+
<div class=${`${base} invalid`} mono-message="invalid" role="alert">
|
|
1477
|
+
${this.errorMessage}
|
|
1478
|
+
</div>
|
|
1479
|
+
`;
|
|
1480
|
+
if (this.successMessage) return html`
|
|
1481
|
+
<div class=${`${base} valid`} mono-message="valid">
|
|
1482
|
+
${this.successMessage}
|
|
1483
|
+
</div>
|
|
1484
|
+
`;
|
|
1485
|
+
if (this.helperText || this._hasHelperSlot || this._slotsAlwaysRender) return html`
|
|
1486
|
+
<div
|
|
1487
|
+
class=${`${base} helper`}
|
|
1488
|
+
mono-message="helper"
|
|
1489
|
+
?mono-empty=${!this.helperText && !this._hasHelperSlot}
|
|
1490
|
+
>
|
|
1491
|
+
${this._slotOutlet("helper", this.helperText)}
|
|
1492
|
+
</div>
|
|
1493
|
+
`;
|
|
1494
|
+
return nothing;
|
|
1495
|
+
}
|
|
1496
|
+
/** Shared clear (×) / chevron action. `toggleArrow` lets the chevron close an
|
|
1497
|
+
* already-open dropdown in the searchable field (the plain button toggles itself).
|
|
1498
|
+
*
|
|
1499
|
+
* ONE glyph, matching `<mono-tag-input>` and `<mono-dropdown-table>`: with a
|
|
1500
|
+
* clearable value the corner shows `✕` alone — clearing is the useful action
|
|
1501
|
+
* then, and the chevron would only say what the value already says. Without a
|
|
1502
|
+
* value (or `clearable` off) the chevron is alone. `disabled` / `readonly`
|
|
1503
|
+
* show NEITHER: the field refuses every gesture, so a chevron would promise an
|
|
1504
|
+
* open it never delivers. The actions span still renders so the gutter — and
|
|
1505
|
+
* the text beside it — stays put when the state toggles.
|
|
1506
|
+
*
|
|
1507
|
+
* THE VALUE WINS over the open state. On a searchable field the chevron is the
|
|
1508
|
+
* only mouse way to CLOSE — the body OPENS but never closes there (a click in a
|
|
1509
|
+
* text input is caret placement, not a toggle) — and it was once kept beside
|
|
1510
|
+
* `✕` for exactly that reason. The rule now is the simpler one: while there is
|
|
1511
|
+
* something to clear there is no chevron, open or closed; a searchable field
|
|
1512
|
+
* with a value closes by picking, Escape or an outside click. `role="button"`
|
|
1513
|
+
* on a span, not a `<button>`: the plain trigger is itself a button and buttons
|
|
1514
|
+
* do not nest. `mousedown.preventDefault` keeps focus where it is (the search
|
|
1515
|
+
* input); `_toggleOpen` stops propagation so the plain trigger does not toggle
|
|
1516
|
+
* a second time. */
|
|
1517
|
+
_renderActions() {
|
|
1518
|
+
const inert = this.disabled || this.readonly;
|
|
1519
|
+
const canClear = this.clearable && this._hasValue && !inert;
|
|
1520
|
+
const showArrow = !inert && !canClear;
|
|
1521
|
+
return html`
|
|
1522
|
+
<span class=${this._cls("mono-select-actions", "actions")} mono-actions>
|
|
1523
|
+
${canClear ? html`
|
|
1524
|
+
<span
|
|
1525
|
+
role="button"
|
|
1526
|
+
tabindex="-1"
|
|
1527
|
+
class=${this._cls("mono-select-clear", "clear")}
|
|
1528
|
+
mono-clear
|
|
1529
|
+
aria-label="Clear select"
|
|
1530
|
+
@mousedown=${(event) => event.preventDefault()}
|
|
1531
|
+
@click=${this._clear}
|
|
1532
|
+
>
|
|
1533
|
+
${this.renderIcon("close")}
|
|
1534
|
+
</span>
|
|
1535
|
+
` : nothing}
|
|
1536
|
+
${showArrow ? html`
|
|
1537
|
+
<span
|
|
1538
|
+
role="button"
|
|
1539
|
+
tabindex="-1"
|
|
1540
|
+
class=${this._cls("mono-select-arrow", "arrow")}
|
|
1541
|
+
mono-arrow
|
|
1542
|
+
aria-label="Toggle options"
|
|
1543
|
+
aria-expanded=${this._open ? "true" : "false"}
|
|
1544
|
+
@mousedown=${(event) => event.preventDefault()}
|
|
1545
|
+
@click=${this._toggleOpen}
|
|
1546
|
+
>
|
|
1547
|
+
${this.renderIcon("chevron")}
|
|
1548
|
+
</span>
|
|
1549
|
+
` : nothing}
|
|
1550
|
+
</span>
|
|
1551
|
+
`;
|
|
1552
|
+
}
|
|
1553
|
+
/** Plain trigger: a button showing the selected value (non-searchable). */
|
|
1554
|
+
_renderButtonTrigger(ariaLabel, describedBy) {
|
|
1555
|
+
return html`
|
|
1556
|
+
<button
|
|
1557
|
+
id=${this._selectId}
|
|
1558
|
+
type="button"
|
|
1559
|
+
class=${this._triggerClasses}
|
|
1560
|
+
mono-trigger
|
|
1561
|
+
?disabled=${this.disabled}
|
|
1562
|
+
aria-haspopup="listbox"
|
|
1563
|
+
aria-expanded=${this._open ? "true" : "false"}
|
|
1564
|
+
aria-controls=${this._listboxId}
|
|
1565
|
+
aria-label=${ifDefined(ariaLabel)}
|
|
1566
|
+
aria-describedby=${ifDefined(describedBy)}
|
|
1567
|
+
@click=${this._toggleOpen}
|
|
1568
|
+
@keydown=${this._handleTriggerKeydown}
|
|
1569
|
+
>
|
|
1570
|
+
${this._renderValue()}
|
|
1571
|
+
${this._renderActions()}
|
|
1572
|
+
</button>
|
|
1573
|
+
`;
|
|
1574
|
+
}
|
|
1575
|
+
/** Searchable trigger: the field itself is a search input (combobox). */
|
|
1576
|
+
_renderSearchTrigger(ariaLabel, describedBy) {
|
|
1577
|
+
return html`
|
|
1578
|
+
<div class=${this._triggerClasses} mono-trigger @click=${this._handleFieldClick}>
|
|
1579
|
+
<input
|
|
1580
|
+
id=${this._selectId}
|
|
1581
|
+
class=${this._cls("mono-select-search-field", "searchField")}
|
|
1582
|
+
mono-search-field
|
|
1583
|
+
type="text"
|
|
1584
|
+
role="combobox"
|
|
1585
|
+
autocomplete="off"
|
|
1586
|
+
aria-haspopup="listbox"
|
|
1587
|
+
aria-expanded=${this._open ? "true" : "false"}
|
|
1588
|
+
aria-controls=${this._listboxId}
|
|
1589
|
+
aria-label=${ifDefined(ariaLabel)}
|
|
1590
|
+
aria-describedby=${ifDefined(describedBy)}
|
|
1591
|
+
.value=${this._searchActive ? this._query : this._displayText}
|
|
1592
|
+
placeholder=${this._fieldPlaceholder}
|
|
1593
|
+
?disabled=${this.disabled}
|
|
1594
|
+
?readonly=${this.readonly}
|
|
1595
|
+
@input=${this._onSearchInput}
|
|
1596
|
+
@focus=${this._handleSearchFocus}
|
|
1597
|
+
@keydown=${this._handleSearchKeydown}
|
|
1598
|
+
/>
|
|
1599
|
+
${this._renderActions()}
|
|
1600
|
+
</div>
|
|
1601
|
+
`;
|
|
1602
|
+
}
|
|
1603
|
+
/** Inline sizing applied to the root wrapper. */
|
|
1604
|
+
_sizeStyle() {
|
|
1605
|
+
return buildSizeStyle(this);
|
|
1606
|
+
}
|
|
1607
|
+
render() {
|
|
1608
|
+
const describedBy = this.validationMessage || this.errorMessage || this.successMessage || this.helperText || this._hasHelperSlot ? this._messageId : void 0;
|
|
1609
|
+
const ariaLabel = this.ariaLabelText || this.label || this.placeholder || void 0;
|
|
1610
|
+
const state = this._resolvedValidationState;
|
|
1611
|
+
return html`
|
|
1612
|
+
<div
|
|
1613
|
+
class=${this._wrapperClasses}
|
|
1614
|
+
style=${styleMap(this._sizeStyle())}
|
|
1615
|
+
mono-select
|
|
1616
|
+
mono-size=${this.size === "md" ? nothing : this.size}
|
|
1617
|
+
mono-color=${this.color === "primary" ? nothing : this.color}
|
|
1618
|
+
mono-variant=${this.variant === "outlined" ? nothing : this.variant}
|
|
1619
|
+
mono-validation-state=${state === "default" ? nothing : state}
|
|
1620
|
+
?mono-open=${this._open}
|
|
1621
|
+
?mono-disabled=${this.disabled}
|
|
1622
|
+
?mono-readonly=${this.readonly}
|
|
1623
|
+
?mono-required=${this.required}
|
|
1624
|
+
?mono-clearable=${this.clearable}
|
|
1625
|
+
?mono-searchable=${this.searchable}
|
|
1626
|
+
>
|
|
1627
|
+
${this._renderLabel()}
|
|
1628
|
+
|
|
1629
|
+
${this.searchable ? this._renderSearchTrigger(ariaLabel, describedBy) : this._renderButtonTrigger(ariaLabel, describedBy)}
|
|
1630
|
+
|
|
1631
|
+
<div
|
|
1632
|
+
id=${this._listboxId}
|
|
1633
|
+
role="listbox"
|
|
1634
|
+
class=${this._cls("mono-select-dropdown", "dropdown")}
|
|
1635
|
+
mono-dropdown
|
|
1636
|
+
style=${styleMap(this._dropdownPanelStyle)}
|
|
1637
|
+
>
|
|
1638
|
+
<div
|
|
1639
|
+
class=${this._cls("mono-select-dropdown-body", "dropdownBody")}
|
|
1640
|
+
mono-dropdown-body
|
|
1641
|
+
style=${styleMap(this._dropdownBodyStyle)}
|
|
1642
|
+
@scroll=${this._handleDropdownScroll}
|
|
1643
|
+
>
|
|
1644
|
+
${this._open ? this._renderItems() : nothing}
|
|
1645
|
+
${this._open ? this._renderLoadMore() : nothing}
|
|
1646
|
+
</div>
|
|
1647
|
+
</div>
|
|
1648
|
+
|
|
1649
|
+
<div id=${this._messageId} class=${this.cssClass?.messageWrap ?? ""} mono-message-wrap>
|
|
1650
|
+
${this._renderHelper()}
|
|
1651
|
+
</div>
|
|
1652
|
+
</div>
|
|
1653
|
+
`;
|
|
1654
|
+
}
|
|
1655
|
+
focus(options) {
|
|
1656
|
+
if (this.searchable) this._searchFieldEl?.focus(options);
|
|
1657
|
+
else this._triggerEl?.focus(options);
|
|
1658
|
+
}
|
|
1659
|
+
blur() {
|
|
1660
|
+
if (this.searchable) this._searchFieldEl?.blur();
|
|
1661
|
+
else this._triggerEl?.blur();
|
|
1662
|
+
}
|
|
1663
|
+
/** Whether the dropdown panel is currently open. */
|
|
1664
|
+
get isOpen() {
|
|
1665
|
+
return this._open;
|
|
1666
|
+
}
|
|
1667
|
+
open() {
|
|
1668
|
+
if (this.disabled || this.readonly) return;
|
|
1669
|
+
this._open = true;
|
|
1670
|
+
}
|
|
1671
|
+
close() {
|
|
1672
|
+
this._close();
|
|
1673
|
+
}
|
|
1674
|
+
toggle() {
|
|
1675
|
+
if (this.disabled || this.readonly) return;
|
|
1676
|
+
if (this._open) this._close();
|
|
1677
|
+
else this._open = true;
|
|
1678
|
+
}
|
|
1679
|
+
/** Coerce a possibly-stringy SSR value to a real boolean (matches
|
|
1680
|
+
* `booleanStringConverter`: a bare / empty attribute means present → true). */
|
|
1681
|
+
_toBoolean(value) {
|
|
1682
|
+
if (typeof value === "boolean") return value;
|
|
1683
|
+
if (value == null) return false;
|
|
1684
|
+
const s = String(value).toLowerCase().trim();
|
|
1685
|
+
return s === "" || s === "true";
|
|
1686
|
+
}
|
|
1687
|
+
/** Whether the slot regions render even when empty. Light: no (omit empty
|
|
1688
|
+
* regions). Shadow: yes — the native `<slot>`s must exist to project DSD
|
|
1689
|
+
* content + be scanned (hidden via `[mono-empty]` when empty). */
|
|
1690
|
+
get _slotsAlwaysRender() {
|
|
1691
|
+
return false;
|
|
1692
|
+
}
|
|
1693
|
+
_hasSlot(name) {
|
|
1694
|
+
return name === "label" ? this._hasLabelSlotState : name === "helper" ? this._hasHelperSlotState : name === "prefix" ? this._hasPrefixSlotState : name === "suffix" ? this._hasSuffixSlotState : this._hasListSlotState;
|
|
1695
|
+
}
|
|
1696
|
+
_setSlotState(name, has) {
|
|
1697
|
+
if (name === "label") this._hasLabelSlotState = has;
|
|
1698
|
+
else if (name === "helper") this._hasHelperSlotState = has;
|
|
1699
|
+
else if (name === "prefix") this._hasPrefixSlotState = has;
|
|
1700
|
+
else if (name === "suffix") this._hasSuffixSlotState = has;
|
|
1701
|
+
else this._hasListSlotState = has;
|
|
1702
|
+
}
|
|
1703
|
+
/**
|
|
1704
|
+
* Slot outlet. Light build (default): a `data-mono-slot` placeholder the
|
|
1705
|
+
* captured light-DOM nodes are re-parented into when present, else the prop
|
|
1706
|
+
* `fallback`. Shadow build overrides this with a native `<slot name>` that
|
|
1707
|
+
* carries the fallback as native slot content.
|
|
1708
|
+
*/
|
|
1709
|
+
_slotOutlet(name, fallback = nothing) {
|
|
1710
|
+
return this._hasSlot(name) ? html`<span data-mono-slot=${name}></span>` : html`${fallback}`;
|
|
1711
|
+
}
|
|
1712
|
+
/**
|
|
1713
|
+
* Icon hook. Light build (default): the global `.mono-icon` / `i-mdi-*` UnoCSS
|
|
1714
|
+
* icon. Shadow overrides with inline SVG (UnoCSS can't reach a shadow root).
|
|
1715
|
+
*/
|
|
1716
|
+
renderIcon(name) {
|
|
1717
|
+
return html`<span class=${`mono-icon ${name === "close" ? "i-mdi-close" : "i-mdi-chevron-down"}`} mono-icon aria-hidden="true"></span>`;
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1720
|
+
__decorate([property({ type: String })], MonoSelectCoreClass.prototype, "size", void 0);
|
|
1721
|
+
__decorate([property({ type: String })], MonoSelectCoreClass.prototype, "color", void 0);
|
|
1722
|
+
__decorate([property({ type: String })], MonoSelectCoreClass.prototype, "variant", void 0);
|
|
1723
|
+
__decorate([property({ attribute: false })], MonoSelectCoreClass.prototype, "modelValue", void 0);
|
|
1724
|
+
__decorate([property({ attribute: false })], MonoSelectCoreClass.prototype, "value", void 0);
|
|
1725
|
+
__decorate([property({ type: String })], MonoSelectCoreClass.prototype, "name", void 0);
|
|
1726
|
+
__decorate([property({ type: String })], MonoSelectCoreClass.prototype, "label", void 0);
|
|
1727
|
+
__decorate([property({ type: String })], MonoSelectCoreClass.prototype, "placeholder", void 0);
|
|
1728
|
+
__decorate([property({
|
|
1729
|
+
type: String,
|
|
1730
|
+
attribute: "helper-text"
|
|
1731
|
+
})], MonoSelectCoreClass.prototype, "helperText", void 0);
|
|
1732
|
+
__decorate([property({
|
|
1733
|
+
type: String,
|
|
1734
|
+
attribute: "validation-state"
|
|
1735
|
+
})], MonoSelectCoreClass.prototype, "validationState", void 0);
|
|
1736
|
+
__decorate([property({
|
|
1737
|
+
type: String,
|
|
1738
|
+
attribute: "validation-message"
|
|
1739
|
+
})], MonoSelectCoreClass.prototype, "validationMessage", void 0);
|
|
1740
|
+
__decorate([property({
|
|
1741
|
+
type: String,
|
|
1742
|
+
attribute: "error-message"
|
|
1743
|
+
})], MonoSelectCoreClass.prototype, "errorMessage", void 0);
|
|
1744
|
+
__decorate([property({
|
|
1745
|
+
type: String,
|
|
1746
|
+
attribute: "success-message"
|
|
1747
|
+
})], MonoSelectCoreClass.prototype, "successMessage", void 0);
|
|
1748
|
+
__decorate([property({
|
|
1749
|
+
type: String,
|
|
1750
|
+
attribute: "aria-label"
|
|
1751
|
+
})], MonoSelectCoreClass.prototype, "ariaLabelText", void 0);
|
|
1752
|
+
__decorate([property({
|
|
1753
|
+
reflect: true,
|
|
1754
|
+
converter: booleanStringConverter
|
|
1755
|
+
})], MonoSelectCoreClass.prototype, "disabled", void 0);
|
|
1756
|
+
__decorate([property({
|
|
1757
|
+
reflect: true,
|
|
1758
|
+
converter: booleanStringConverter
|
|
1759
|
+
})], MonoSelectCoreClass.prototype, "readonly", void 0);
|
|
1760
|
+
__decorate([property({
|
|
1761
|
+
reflect: true,
|
|
1762
|
+
converter: booleanStringConverter
|
|
1763
|
+
})], MonoSelectCoreClass.prototype, "required", void 0);
|
|
1764
|
+
__decorate([property({
|
|
1765
|
+
reflect: true,
|
|
1766
|
+
converter: booleanStringConverter
|
|
1767
|
+
})], MonoSelectCoreClass.prototype, "clearable", void 0);
|
|
1768
|
+
__decorate([property({
|
|
1769
|
+
attribute: false,
|
|
1770
|
+
hasChanged: arrayHasChanged
|
|
1771
|
+
})], MonoSelectCoreClass.prototype, "items", void 0);
|
|
1772
|
+
__decorate([property({ attribute: false })], MonoSelectCoreClass.prototype, "dataSource", void 0);
|
|
1773
|
+
__decorate([property({
|
|
1774
|
+
attribute: "immediate",
|
|
1775
|
+
reflect: true,
|
|
1776
|
+
converter: booleanStringConverter
|
|
1777
|
+
})], MonoSelectCoreClass.prototype, "immediate", void 0);
|
|
1778
|
+
__decorate([property({
|
|
1779
|
+
attribute: "load-more",
|
|
1780
|
+
reflect: true
|
|
1781
|
+
})], MonoSelectCoreClass.prototype, "loadMore", void 0);
|
|
1782
|
+
__decorate([property({
|
|
1783
|
+
attribute: "page-size",
|
|
1784
|
+
reflect: true,
|
|
1785
|
+
type: Number
|
|
1786
|
+
})], MonoSelectCoreClass.prototype, "pageSize", void 0);
|
|
1787
|
+
__decorate([property({ attribute: false })], MonoSelectCoreClass.prototype, "dropdown", void 0);
|
|
1788
|
+
__decorate([property({
|
|
1789
|
+
attribute: "dropdown-height",
|
|
1790
|
+
reflect: true
|
|
1791
|
+
})], MonoSelectCoreClass.prototype, "dropdownHeight", void 0);
|
|
1792
|
+
__decorate([property({
|
|
1793
|
+
attribute: "dropdown-max-height",
|
|
1794
|
+
reflect: true
|
|
1795
|
+
})], MonoSelectCoreClass.prototype, "dropdownMaxHeight", void 0);
|
|
1796
|
+
__decorate([property({ converter: booleanStringConverter })], MonoSelectCoreClass.prototype, "flip", void 0);
|
|
1797
|
+
__decorate([property({ converter: booleanStringConverter })], MonoSelectCoreClass.prototype, "shift", void 0);
|
|
1798
|
+
__decorate([property({
|
|
1799
|
+
type: String,
|
|
1800
|
+
attribute: "key-value",
|
|
1801
|
+
reflect: true
|
|
1802
|
+
})], MonoSelectCoreClass.prototype, "keyValue", void 0);
|
|
1803
|
+
__decorate([property({ attribute: false })], MonoSelectCoreClass.prototype, "displayValue", void 0);
|
|
1804
|
+
__decorate([property({
|
|
1805
|
+
attribute: false,
|
|
1806
|
+
hasChanged: arrayHasChanged
|
|
1807
|
+
})], MonoSelectCoreClass.prototype, "displayGroup", void 0);
|
|
1808
|
+
__decorate([property({
|
|
1809
|
+
type: String,
|
|
1810
|
+
attribute: "group-key",
|
|
1811
|
+
reflect: true
|
|
1812
|
+
})], MonoSelectCoreClass.prototype, "groupKey", void 0);
|
|
1813
|
+
__decorate([property({
|
|
1814
|
+
type: String,
|
|
1815
|
+
attribute: "group-items",
|
|
1816
|
+
reflect: true
|
|
1817
|
+
})], MonoSelectCoreClass.prototype, "groupItems", void 0);
|
|
1818
|
+
__decorate([property({
|
|
1819
|
+
attribute: "group",
|
|
1820
|
+
reflect: true,
|
|
1821
|
+
converter: booleanStringConverter
|
|
1822
|
+
})], MonoSelectCoreClass.prototype, "group", void 0);
|
|
1823
|
+
__decorate([property({
|
|
1824
|
+
attribute: "group-sticky",
|
|
1825
|
+
reflect: true,
|
|
1826
|
+
converter: booleanStringConverter
|
|
1827
|
+
})], MonoSelectCoreClass.prototype, "groupSticky", void 0);
|
|
1828
|
+
__decorate([property({
|
|
1829
|
+
attribute: "searchable",
|
|
1830
|
+
reflect: true,
|
|
1831
|
+
converter: booleanStringConverter
|
|
1832
|
+
})], MonoSelectCoreClass.prototype, "searchable", void 0);
|
|
1833
|
+
__decorate([property({
|
|
1834
|
+
attribute: "stay-open",
|
|
1835
|
+
reflect: true,
|
|
1836
|
+
converter: booleanStringConverter
|
|
1837
|
+
})], MonoSelectCoreClass.prototype, "stayOpen", void 0);
|
|
1838
|
+
__decorate([property({
|
|
1839
|
+
attribute: "search-value",
|
|
1840
|
+
hasChanged: arrayHasChanged
|
|
1841
|
+
})], MonoSelectCoreClass.prototype, "searchValue", void 0);
|
|
1842
|
+
__decorate([property({
|
|
1843
|
+
type: String,
|
|
1844
|
+
attribute: "search-operation"
|
|
1845
|
+
})], MonoSelectCoreClass.prototype, "searchOperation", void 0);
|
|
1846
|
+
__decorate([property({
|
|
1847
|
+
attribute: "search-debounce",
|
|
1848
|
+
type: Number
|
|
1849
|
+
})], MonoSelectCoreClass.prototype, "searchDebounce", void 0);
|
|
1850
|
+
__decorate([property({
|
|
1851
|
+
type: String,
|
|
1852
|
+
attribute: "search-placeholder"
|
|
1853
|
+
})], MonoSelectCoreClass.prototype, "searchPlaceholder", void 0);
|
|
1854
|
+
__decorate([property({
|
|
1855
|
+
attribute: false,
|
|
1856
|
+
hasChanged: rateLimitHasChanged
|
|
1857
|
+
})], MonoSelectCoreClass.prototype, "cssClass", void 0);
|
|
1858
|
+
__decorate([property({ attribute: false })], MonoSelectCoreClass.prototype, "cssClassName", void 0);
|
|
1859
|
+
__decorate([state()], MonoSelectCoreClass.prototype, "_open", void 0);
|
|
1860
|
+
__decorate([state()], MonoSelectCoreClass.prototype, "_query", void 0);
|
|
1861
|
+
__decorate([state()], MonoSelectCoreClass.prototype, "_searchActive", void 0);
|
|
1862
|
+
__decorate([state()], MonoSelectCoreClass.prototype, "_activeIndex", void 0);
|
|
1863
|
+
__decorate([state()], MonoSelectCoreClass.prototype, "_scrollAutoMaxHeight", void 0);
|
|
1864
|
+
__decorate([state()], MonoSelectCoreClass.prototype, "_hasLabelSlotState", void 0);
|
|
1865
|
+
__decorate([state()], MonoSelectCoreClass.prototype, "_hasHelperSlotState", void 0);
|
|
1866
|
+
__decorate([state()], MonoSelectCoreClass.prototype, "_hasPrefixSlotState", void 0);
|
|
1867
|
+
__decorate([state()], MonoSelectCoreClass.prototype, "_hasSuffixSlotState", void 0);
|
|
1868
|
+
__decorate([state()], MonoSelectCoreClass.prototype, "_hasListSlotState", void 0);
|
|
1869
|
+
__decorate([query(".mono-select-search-field")], MonoSelectCoreClass.prototype, "_searchFieldEl", void 0);
|
|
1870
|
+
__decorate([query(".mono-select-trigger")], MonoSelectCoreClass.prototype, "_triggerEl", void 0);
|
|
1871
|
+
__decorate([property({ type: String })], MonoSelectCoreClass.prototype, "width", void 0);
|
|
1872
|
+
__decorate([property({ type: String })], MonoSelectCoreClass.prototype, "height", void 0);
|
|
1873
|
+
__decorate([property({
|
|
1874
|
+
type: String,
|
|
1875
|
+
attribute: "min-width"
|
|
1876
|
+
})], MonoSelectCoreClass.prototype, "minWidth", void 0);
|
|
1877
|
+
__decorate([property({
|
|
1878
|
+
type: String,
|
|
1879
|
+
attribute: "max-width"
|
|
1880
|
+
})], MonoSelectCoreClass.prototype, "maxWidth", void 0);
|
|
1881
|
+
__decorate([property({
|
|
1882
|
+
type: String,
|
|
1883
|
+
attribute: "min-height"
|
|
1884
|
+
})], MonoSelectCoreClass.prototype, "minHeight", void 0);
|
|
1885
|
+
__decorate([property({
|
|
1886
|
+
type: String,
|
|
1887
|
+
attribute: "max-height"
|
|
1888
|
+
})], MonoSelectCoreClass.prototype, "maxHeight", void 0);
|
|
1889
|
+
return MonoSelectCoreClass;
|
|
1890
|
+
};
|
|
1891
|
+
//#endregion
|
|
1892
|
+
//#region src/components/select/select.css?raw
|
|
1893
|
+
var select_default = "/* =========================================================================\r\n mono-select — a port of Basecoat's `.select` (the custom one, `.select:not(select)`)\r\n and `.combobox` (basecoat-css@1.0.2, vega style), on the `.field` / `.label`\r\n chrome mono-input already ported.\r\n\r\n Styled by ATTRIBUTE, like Basecoat (`.select > button`, `[role='option'].active`)\r\n — and the attributes mirror the element's props one for one, so hand-written\r\n markup reads like the Lit / Vue tag:\r\n\r\n <mono-select size=\"sm\" color=\"danger\" variant=\"filled\" label=\"Fruit\">\r\n <div mono-select mono-size=\"sm\" mono-color=\"danger\" mono-variant=\"filled\">\r\n <label mono-label>Fruit</label>\r\n <button mono-trigger><span mono-value mono-placeholder>Pick</span>\r\n <span mono-actions><span mono-arrow>…</span></span></button>\r\n <div mono-dropdown><div mono-dropdown-body><button mono-item>…</button></div></div>\r\n </div>\r\n\r\n An absent attribute is the prop's default (`:not([mono-size])` = md,\r\n `:not([mono-color])` = primary, `:not([mono-variant])` = outlined). The element\r\n renders these attributes on its wrapper (both builds) plus `mono-open` while\r\n the panel is open; the old classes (`.mono-select.sm.open`) are still emitted\r\n as inert hooks for consumer CSS until 2.0 but no rule here reads them.\r\n\r\n Selector map (ours ≡ upstream):\r\n [mono-select] ≡ .field (gap-3, as margins — see the root rule) + .select (position: relative)\r\n [mono-select] > [mono-label] ≡ .field > label / .label\r\n [mono-select] > [mono-trigger] ≡ .select > button (h-9 rounded-md border-input ps-2.5 pe-2 text-sm shadow-xs)\r\n [mono-select][mono-searchable] > [mono-trigger] ≡ .combobox > input[role='combobox'] (same box; the input sits inside it)\r\n [mono-trigger] > [mono-value] ≡ .select > button > span (flex-1 truncate text-start)\r\n [mono-trigger] > [mono-native] ≡ EXTENSION — a plain <select> may stand in for the value + panel (appearance: none)\r\n [mono-actions] > [mono-arrow] > [mono-icon] ≡ .select > button > svg (size-4 text-muted-foreground)\r\n [mono-actions] > [mono-clear] ≡ .combobox [data-clear] (size-6, painted as .btn[data-variant='ghost'])\r\n [mono-dropdown] ≡ .select [data-popover] (bg-popover ring-1 ring-foreground/10 rounded-md shadow-md)\r\n [mono-dropdown-body] ≡ .combobox [role='listbox'] (max-h-72 overflow-y-auto p-1 scroll-py-1)\r\n [mono-item] ≡ .select [role='option'] (gap-2 rounded-sm py-1.5 ps-2 pe-8 text-sm)\r\n [mono-item][mono-active] / :hover ≡ [role='option'].active (bg-muted text-foreground)\r\n [mono-item][mono-selected] ≡ [role='option'][aria-selected='true'] (the --check-icon at the end)\r\n [mono-group] ≡ .select [role='heading'] (px-2 py-1.5 text-xs text-muted-foreground)\r\n [mono-empty-row] ≡ .select [role='listbox']::before (py-6 text-center text-sm)\r\n [mono-load-more] ≡ EXTENSION (an option-shaped ghost button)\r\n [mono-message-wrap] > [mono-message] ≡ .field > p / .field [role='alert']\r\n [mono-validation-state=\"invalid\"] ≡ .select > button[aria-invalid='true']\r\n [mono-validation-state=\"valid|warning\"] ≡ EXTENSION (the invalid pattern in --success / --warning)\r\n [mono-size=\"xs|sm|lg|xl|xxl\"] ≡ EXTENSION (Basecoat has only data-size=sm; the ladder is --mono-control-height-*)\r\n [mono-variant=\"filled\"] ≡ EXTENSION (luma's .select > button: border-transparent bg-input/50)\r\n [mono-variant=\"underlined\"] ≡ EXTENSION (sera's: rounded-none border-b-input px-0, no ring)\r\n\r\n Inner parts are attributes too: [mono-label] (+ [mono-required-mark]),\r\n [mono-trigger], [mono-value] (+ [mono-placeholder]), [mono-search-field],\r\n [mono-native], [mono-actions], [mono-clear], [mono-arrow], [mono-icon],\r\n [mono-dropdown], [mono-dropdown-body], [mono-item] (+ [mono-active] /\r\n [mono-selected] / [mono-disabled]), [mono-group] (+ [mono-sticky],\r\n [mono-level=\"n\"]), [mono-empty-row], [mono-load-more] (+ [mono-loading]),\r\n [mono-list-slot], [mono-message-wrap] > [mono-message=\"helper|valid|invalid|warning\"].\r\n The shadow build marks an unassigned slot wrapper [mono-empty].\r\n\r\n THE PANEL IS PORTALED. The light build moves [mono-dropdown] into a\r\n `<div data-mono-popup-portal>` under <body> while open (composables/popup-\r\n portal.ts), and the portal mirrors the wrapper's class AND its mono-*\r\n attributes — so `[mono-select] > [mono-dropdown]` keeps matching there and\r\n the `--_mono-select-*` resolvers declared on `[mono-select]` re-resolve on\r\n the portal. Nothing here may rely on the panel being inside the trigger's\r\n host, and every option rule is scoped under `[mono-select]`.\r\n\r\n Values are copied from the compiled vendor sheet (vendor/basecoat/basecoat-\r\n vega.cdn.css) through the token layer; `dark:` variants travel as\r\n `--mono-mode-*` tokens (a selector cannot cross a shadow boundary; an\r\n inherited custom property can). FLAVORS set the `--mono-select-*` knobs read\r\n below — the same set as mono-input (`--mono-select-outline-*` for the outlined\r\n variant alone) plus `--mono-select-dropdown-{radius,padding,shadow,ring}`,\r\n `--mono-select-option-{radius,padding-x,padding-y,font-size,line-height,gap,font-weight}`,\r\n `--mono-select-group-*`, `--mono-select-icon-size`. Every fallback here is vega's\r\n value (`node scripts/basecoat-styles.mjs --varying \"^(\\.select:not\\(select\\)|\\.combobox)\"`).\r\n ========================================================================= */\r\n\r\nmono-select {\r\n display: block;\r\n}\r\n\r\n[mono-select] {\r\n /* ── palette: each slot is a public knob over a Basecoat token ─────────── */\r\n --_mono-select-text: var(--mono-select-color, var(--mono-select-text, var(--foreground)));\r\n --_mono-select-placeholder: var(--mono-select-placeholder, var(--muted-foreground));\r\n --_mono-select-muted: var(--mono-select-muted, var(--muted-foreground));\r\n --_mono-select-primary: var(--mono-select-primary, var(--ring));\r\n --_mono-select-secondary: var(--mono-select-secondary, var(--muted-foreground));\r\n --_mono-select-success: var(--mono-select-success, var(--success));\r\n --_mono-select-danger: var(--mono-select-danger, var(--destructive));\r\n --_mono-select-warning: var(--mono-select-warning, var(--warning));\r\n --_mono-select-info: var(--mono-select-info, var(--info));\r\n --_mono-select-teal: var(--mono-select-teal, var(--teal));\r\n --_mono-select-purple: var(--mono-select-purple, var(--purple));\r\n --_mono-select-neutral: var(--mono-select-neutral, var(--neutral));\r\n --_mono-select-dark: var(--mono-select-dark, var(--dark));\r\n --_mono-select-valid: var(--mono-select-valid, var(--success));\r\n --_mono-select-invalid: var(--mono-select-invalid, var(--destructive));\r\n\r\n /* ── the painted result — three tiers, base = .select > button (vega) ─── */\r\n --_mono-select-ring-color: var(--mono-select-ring-color, var(--mono-select-focus-color, var(--_mono-select-ring-color-preset, var(--_mono-select-primary))));\r\n --_mono-select-ring-width: var(--mono-select-ring-width, var(--_mono-select-ring-width-preset, var(--mono-ring-width)));\r\n --_mono-select-ring-alpha: var(--mono-select-ring-alpha, var(--mono-ring-alpha));\r\n --_mono-select-border-color: var(--mono-select-rest-border, var(--mono-select-border-color, var(--mono-select-border, var(--_mono-select-border-color-preset, var(--input)))));\r\n --_mono-select-bg: var(--mono-select-bg, var(--mono-select-surface, var(--_mono-select-bg-preset, var(--mono-mode-surface))));\r\n --_mono-select-hover-bg: var(--mono-select-hover-bg, var(--_mono-select-hover-bg-preset, var(--_mono-select-bg)));\r\n --_mono-select-shadow: var(--mono-select-shadow, var(--_mono-select-shadow-preset, 0 0 #0000));\r\n --_mono-select-icon: var(--mono-select-icon-size, calc(var(--mono-spacing) * 4));\r\n\r\n /* ── md metrics live on the unqualified root ON PURPOSE: hand-written\r\n `<div mono-select>` that names no size renders exactly like size=\"md\".\r\n basecoat@1.0.2 styles/vega.css .select:not(select) > button — h-9 gap-1.5\r\n rounded-md ps-2.5 pe-2 text-sm ── */\r\n --_mono-select-height: var(--mono-select-height-md, var(--mono-control-height-md));\r\n --_mono-select-radius: var(--mono-select-radius-md, var(--_mono-select-radius-preset, var(--mono-select-radius, var(--mono-radius-md))));\r\n --_mono-select-padding-start: var(--mono-select-padding-x-md, var(--mono-select-padding-x, var(--_mono-select-padding-x-preset, calc(var(--mono-spacing) * 2.5))));\r\n --_mono-select-padding-end: var(--mono-select-padding-end-md, var(--mono-select-padding-x, var(--_mono-select-padding-x-preset, calc(var(--mono-spacing) * 2))));\r\n --_mono-select-gap: var(--mono-select-trigger-gap, calc(var(--mono-spacing) * 1.5));\r\n --_mono-select-font-size: var(--mono-select-font-md, var(--mono-text-sm));\r\n --_mono-select-line-height: var(--mono-select-line-height, var(--mono-select-line-height-md, var(--mono-text-sm--lh)));\r\n --_mono-select-action: calc(var(--mono-spacing) * 6);\r\n\r\n /* basecoat@1.0.2 styles/vega.css .field — flex w-full flex-col gap-3; mono: BLOCK\r\n flow with the gap as margins, so a hand-written panel that no controller\r\n positions lands at its static position — right under the trigger, above the\r\n message — instead of a flex container's content-box top */\r\n --_mono-select-gap-y: var(--mono-select-gap, calc(var(--mono-spacing) * 3));\r\n position: relative;\r\n display: block;\r\n width: 100%;\r\n font-family: inherit;\r\n color: var(--_mono-select-text);\r\n}\r\n\r\n/* A page-level `* { box-sizing: border-box }` reset does NOT cross a shadow\r\n boundary; scoped here so both builds measure the same. */\r\n[mono-select],\r\n[mono-select] *,\r\n[mono-select] *::before,\r\n[mono-select] *::after {\r\n box-sizing: border-box;\r\n}\r\n\r\n[mono-select] :is([mono-label], [mono-message])[mono-empty] {\r\n display: none;\r\n}\r\n\r\n/* =========================================\r\n Sizes — the trigger's painted height IS the token (tests/perf/field-heights)\r\n EXTENSION: Basecoat's select has only data-size=sm; the ladder is the shared\r\n --mono-control-height-* scale and the text follows .btn's steps.\r\n ========================================= */\r\n\r\n[mono-select][mono-size=\"xs\"] {\r\n --_mono-select-height: var(--mono-select-height-xs, var(--mono-control-height-xs));\r\n --_mono-select-radius: var(--mono-select-radius-xs, var(--_mono-select-radius-preset, var(--mono-select-radius, var(--mono-radius-md))));\r\n --_mono-select-padding-start: var(--mono-select-padding-x-xs, var(--mono-select-padding-x, var(--_mono-select-padding-x-preset, calc(var(--mono-spacing) * 2))));\r\n --_mono-select-padding-end: var(--mono-select-padding-end-xs, var(--mono-select-padding-x, var(--_mono-select-padding-x-preset, calc(var(--mono-spacing) * 1.5))));\r\n --_mono-select-gap: var(--mono-select-trigger-gap, var(--mono-spacing));\r\n --_mono-select-font-size: var(--mono-select-font-xs, var(--mono-text-xs));\r\n --_mono-select-line-height: var(--mono-select-line-height, var(--mono-select-line-height-xs, var(--mono-text-xs--lh)));\r\n --_mono-select-icon: var(--mono-select-icon-size, calc(var(--mono-spacing) * 3.5));\r\n --_mono-select-action: calc(var(--mono-spacing) * 4);\r\n}\r\n\r\n/* basecoat@1.0.2 styles/vega.css .select:not(select) > button — data-[size=sm]:h-8 */\r\n[mono-select][mono-size=\"sm\"] {\r\n --_mono-select-height: var(--mono-select-height-sm, var(--mono-control-height-sm));\r\n --_mono-select-radius: var(--mono-select-radius-sm, var(--_mono-select-radius-preset, var(--mono-select-radius, var(--mono-radius-md))));\r\n --_mono-select-padding-start: var(--mono-select-padding-x-sm, var(--mono-select-padding-x, var(--_mono-select-padding-x-preset, calc(var(--mono-spacing) * 2.5))));\r\n --_mono-select-padding-end: var(--mono-select-padding-end-sm, var(--mono-select-padding-x, var(--_mono-select-padding-x-preset, calc(var(--mono-spacing) * 2))));\r\n --_mono-select-font-size: var(--mono-select-font-sm, var(--mono-select-font-md, var(--mono-text-sm)));\r\n --_mono-select-line-height: var(--mono-select-line-height, var(--mono-select-line-height-sm, var(--mono-text-sm--lh)));\r\n --_mono-select-action: calc(var(--mono-spacing) * 5);\r\n}\r\n\r\n[mono-select][mono-size=\"lg\"] {\r\n --_mono-select-height: var(--mono-select-height-lg, var(--mono-control-height-lg));\r\n --_mono-select-radius: var(--mono-select-radius-lg, var(--_mono-select-radius-preset, var(--mono-select-radius, var(--mono-radius-md))));\r\n --_mono-select-padding-start: var(--mono-select-padding-x-lg, var(--mono-select-padding-x, var(--_mono-select-padding-x-preset, calc(var(--mono-spacing) * 2.5))));\r\n --_mono-select-padding-end: var(--mono-select-padding-end-lg, var(--mono-select-padding-x, var(--_mono-select-padding-x-preset, calc(var(--mono-spacing) * 2))));\r\n --_mono-select-font-size: var(--mono-select-font-lg, var(--mono-select-font-md, var(--mono-text-sm)));\r\n --_mono-select-line-height: var(--mono-select-line-height, var(--mono-select-line-height-lg, var(--mono-text-sm--lh)));\r\n}\r\n\r\n[mono-select][mono-size=\"xl\"] {\r\n --_mono-select-height: var(--mono-select-height-xl, var(--mono-control-height-xl));\r\n --_mono-select-radius: var(--mono-select-radius-xl, var(--_mono-select-radius-preset, var(--mono-select-radius, var(--mono-radius-md))));\r\n --_mono-select-padding-start: var(--mono-select-padding-x-xl, var(--mono-select-padding-x, var(--_mono-select-padding-x-preset, calc(var(--mono-spacing) * 3))));\r\n --_mono-select-padding-end: var(--mono-select-padding-end-xl, var(--mono-select-padding-x, var(--_mono-select-padding-x-preset, calc(var(--mono-spacing) * 2.5))));\r\n --_mono-select-gap: var(--mono-select-trigger-gap, calc(var(--mono-spacing) * 2));\r\n --_mono-select-font-size: var(--mono-select-font-xl, var(--mono-text-base));\r\n --_mono-select-line-height: var(--mono-select-line-height, var(--mono-select-line-height-xl, var(--mono-text-base--lh)));\r\n --_mono-select-icon: var(--mono-select-icon-size, calc(var(--mono-spacing) * 5));\r\n --_mono-select-action: calc(var(--mono-spacing) * 7);\r\n}\r\n\r\n[mono-select][mono-size=\"xxl\"] {\r\n --_mono-select-height: var(--mono-select-height-xxl, var(--mono-control-height-xxl));\r\n --_mono-select-radius: var(--mono-select-radius-xxl, var(--_mono-select-radius-preset, var(--mono-select-radius, var(--mono-radius-md))));\r\n --_mono-select-padding-start: var(--mono-select-padding-x-xxl, var(--mono-select-padding-x, var(--_mono-select-padding-x-preset, calc(var(--mono-spacing) * 4))));\r\n --_mono-select-padding-end: var(--mono-select-padding-end-xxl, var(--mono-select-padding-x, var(--_mono-select-padding-x-preset, calc(var(--mono-spacing) * 3))));\r\n --_mono-select-gap: var(--mono-select-trigger-gap, calc(var(--mono-spacing) * 2));\r\n --_mono-select-font-size: var(--mono-select-font-xxl, var(--mono-text-lg));\r\n --_mono-select-line-height: var(--mono-select-line-height, var(--mono-select-line-height-xxl, var(--mono-text-lg--lh)));\r\n --_mono-select-icon: var(--mono-select-icon-size, calc(var(--mono-spacing) * 5));\r\n --_mono-select-action: calc(var(--mono-spacing) * 8);\r\n}\r\n\r\n/* =========================================\r\n Variants — each writes only `*-preset` slots\r\n ========================================= */\r\n\r\n/* basecoat@1.0.2 styles/vega.css .select:not(select) > button — rounded-md border\r\n border-input bg-transparent shadow-xs (dark:bg-input/30 dark:hover:bg-input/50\r\n via the mode tokens). `--mono-select-outline-*` restyle THIS variant alone. */\r\n[mono-select]:is(:not([mono-variant]), [mono-variant=\"outlined\"]) {\r\n --_mono-select-bg-preset: var(--mono-select-outline-bg);\r\n --_mono-select-hover-bg-preset: var(--mono-select-outline-hover-bg, var(--mono-mode-field-hover-bg));\r\n --_mono-select-border-color-preset: var(--mono-select-outline-border-color);\r\n --_mono-select-side-border-color-preset: var(--mono-select-outline-side-border-color);\r\n --_mono-select-shadow-preset: var(--mono-select-outline-shadow, var(--mono-shadow-xs));\r\n --_mono-select-ring-width-preset: var(--mono-select-outline-ring-width);\r\n --_mono-select-radius-preset: var(--mono-select-outline-radius);\r\n --_mono-select-padding-x-preset: var(--mono-select-outline-padding-x);\r\n}\r\n\r\n/* EXTENSION — filled ≡ basecoat@1.0.2 styles/luma.css .select:not(select) > button:\r\n border-transparent bg-input/50, no shadow-xs, no hover */\r\n[mono-select][mono-variant=\"filled\"] {\r\n --_mono-select-bg-preset: var(--mono-select-filled-bg, color-mix(in oklab, var(--input) 50%, transparent));\r\n --_mono-select-hover-bg-preset: var(--_mono-select-bg);\r\n --_mono-select-border-color-preset: transparent;\r\n --_mono-select-shadow-preset: 0 0 #0000;\r\n}\r\n\r\n/* EXTENSION — underlined ≡ basecoat@1.0.2 styles/sera.css .select:not(select) > button:\r\n rounded-none border-transparent border-b-input bg-transparent px-0, no shadow,\r\n no ring, focus-visible:border-b-ring */\r\n[mono-select][mono-variant=\"underlined\"] {\r\n --_mono-select-bg-preset: transparent;\r\n --_mono-select-hover-bg-preset: transparent;\r\n --_mono-select-side-border-color-preset: transparent;\r\n --_mono-select-shadow-preset: 0 0 #0000;\r\n --_mono-select-ring-width-preset: 0px;\r\n --_mono-select-radius-preset: 0;\r\n --_mono-select-padding-x-preset: 0;\r\n}\r\n\r\n/* =========================================\r\n Colours — the `color` prop is the FOCUS colour (ring + focused border)\r\n ========================================= */\r\n\r\n[mono-select]:is(:not([mono-color]), [mono-color=\"primary\"]) {\r\n --_mono-select-ring-color-preset: var(--_mono-select-primary);\r\n}\r\n[mono-select][mono-color=\"secondary\"] {\r\n --_mono-select-ring-color-preset: var(--_mono-select-secondary);\r\n}\r\n[mono-select][mono-color=\"success\"] {\r\n --_mono-select-ring-color-preset: var(--_mono-select-success);\r\n}\r\n[mono-select][mono-color=\"danger\"] {\r\n --_mono-select-ring-color-preset: var(--_mono-select-danger);\r\n}\r\n[mono-select][mono-color=\"warning\"] {\r\n --_mono-select-ring-color-preset: var(--_mono-select-warning);\r\n}\r\n[mono-select][mono-color=\"info\"] {\r\n --_mono-select-ring-color-preset: var(--_mono-select-info);\r\n}\r\n[mono-select][mono-color=\"teal\"] {\r\n --_mono-select-ring-color-preset: var(--_mono-select-teal);\r\n}\r\n[mono-select][mono-color=\"purple\"] {\r\n --_mono-select-ring-color-preset: var(--_mono-select-purple);\r\n}\r\n[mono-select][mono-color=\"neutral\"] {\r\n --_mono-select-ring-color-preset: var(--_mono-select-neutral);\r\n}\r\n[mono-select][mono-color=\"dark\"] {\r\n --_mono-select-ring-color-preset: var(--_mono-select-dark);\r\n}\r\n\r\n/* =========================================\r\n Label\r\n ========================================= */\r\n\r\n/* basecoat@1.0.2 styles/vega.css .field > label, .label — flex items-center\r\n gap-2 text-sm leading-none font-medium select-none w-fit */\r\n[mono-select] > [mono-label] {\r\n display: flex;\r\n align-items: center;\r\n width: fit-content;\r\n margin: 0 0 var(--_mono-select-gap-y);\r\n gap: var(--mono-select-label-gap, calc(var(--mono-spacing) * 2));\r\n font-size: var(--mono-select-label-font-size, var(--mono-text-sm));\r\n line-height: var(--mono-select-label-line-height, 1);\r\n font-weight: var(--mono-select-label-font-weight, var(--mono-label-font-weight, var(--mono-font-weight-medium)));\r\n text-transform: var(--mono-select-label-text-transform, none);\r\n letter-spacing: var(--mono-select-label-letter-spacing, normal);\r\n color: var(--_mono-select-text);\r\n user-select: none;\r\n}\r\n\r\n[mono-select][mono-disabled] > [mono-label] {\r\n opacity: 0.5;\r\n pointer-events: none;\r\n}\r\n\r\n/* basecoat@1.0.2 styles/vega.css .field — data-invalid:text-destructive */\r\n[mono-select][mono-validation-state=\"invalid\"] > [mono-label] {\r\n color: var(--_mono-select-invalid);\r\n}\r\n\r\n[mono-select] [mono-required-mark] {\r\n color: var(--_mono-select-danger);\r\n}\r\n\r\n/* =========================================\r\n The trigger — the bordered box (a <button>, or a <div> holding the combobox input)\r\n ========================================= */\r\n\r\n/* basecoat@1.0.2 components/select.css .select:not(select) > button */\r\n/* basecoat@1.0.2 styles/vega.css .select:not(select) > button — h-9 gap-1.5\r\n rounded-md border border-input bg-transparent py-2 ps-2.5 pe-2 text-sm shadow-xs\r\n focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50\r\n aria-invalid:… dark:hover:bg-input/50; mono: `--tw-ring-*` flattened to the\r\n ring + shadow slots, the height is the control token (no block padding — the\r\n token owns the height), the side edges read their own slot */\r\n[mono-select] > [mono-trigger] {\r\n --_mono-select-bc: var(--_mono-select-border-color);\r\n --_mono-select-side-bc: var(--mono-select-side-border-color, var(--_mono-select-side-border-color-preset, var(--_mono-select-bc)));\r\n --_mono-select-ring: 0 0 #0000;\r\n\r\n position: relative;\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n gap: var(--_mono-select-gap);\r\n width: 100%;\r\n min-width: 0;\r\n min-height: var(--_mono-select-height);\r\n margin: 0;\r\n padding-block: var(--mono-select-padding-y, 0);\r\n padding-inline: var(--_mono-select-padding-start) var(--_mono-select-padding-end);\r\n outline-style: none;\r\n border: var(--mono-border-width) solid var(--_mono-select-bc);\r\n border-top-color: var(--_mono-select-side-bc);\r\n border-inline-color: var(--_mono-select-side-bc);\r\n border-radius: var(--_mono-select-radius);\r\n background: var(--_mono-select-bg);\r\n color: var(--_mono-select-text);\r\n box-shadow: var(--_mono-select-ring), var(--_mono-select-shadow);\r\n font-family: inherit;\r\n font-size: var(--_mono-select-font-size);\r\n line-height: var(--_mono-select-line-height);\r\n font-weight: var(--mono-font-weight-normal);\r\n white-space: nowrap;\r\n text-align: start;\r\n cursor: pointer;\r\n user-select: none;\r\n transition-property: color, box-shadow, border-color, background-color;\r\n transition-timing-function: var(--mono-ease);\r\n transition-duration: var(--mono-duration);\r\n\r\n &:focus,\r\n &:focus-visible,\r\n &:focus-within {\r\n outline: none !important;\r\n }\r\n\r\n /* focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 —\r\n the combobox form is a <div> whose <input> takes focus, hence :focus-within */\r\n &:focus-visible,\r\n &:focus-within {\r\n --_mono-select-bc: var(--_mono-select-ring-color);\r\n --_mono-select-ring: 0 0 0 var(--_mono-select-ring-width) color-mix(in oklab, var(--_mono-select-ring-color) var(--_mono-select-ring-alpha), transparent);\r\n }\r\n\r\n & svg,\r\n & [mono-icon] {\r\n pointer-events: none;\r\n flex-shrink: 0;\r\n }\r\n}\r\n\r\n/* dark:hover:bg-input/50 (light: none) — carried by --mono-mode-field-hover-bg */\r\n@media (hover: hover) {\r\n [mono-select]:not([mono-disabled]):not([mono-readonly]) > [mono-trigger]:hover {\r\n background: var(--_mono-select-hover-bg);\r\n }\r\n}\r\n\r\n/* basecoat@1.0.2 styles/vega.css .select:not(select) > button — aria-invalid:border-destructive\r\n aria-invalid:ring-3 aria-invalid:ring-destructive/20 (dark: /50, /40 via the mode tokens) */\r\n[mono-select][mono-validation-state=\"invalid\"] > [mono-trigger],\r\n[mono-select] > [mono-trigger][aria-invalid=\"true\"] {\r\n --_mono-select-bc: var(--mono-mode-invalid-border);\r\n --_mono-select-ring: 0 0 0 var(--_mono-select-ring-width) var(--mono-mode-invalid-ring);\r\n}\r\n\r\n/* EXTENSION — valid / warning are the invalid pattern in the role's colour */\r\n[mono-select][mono-validation-state=\"valid\"] > [mono-trigger] {\r\n --_mono-select-bc: color-mix(in oklab, var(--_mono-select-valid) var(--mono-mode-state-border-alpha), transparent);\r\n --_mono-select-ring: 0 0 0 var(--_mono-select-ring-width) color-mix(in oklab, var(--_mono-select-valid) var(--mono-mode-state-ring-alpha), transparent);\r\n}\r\n[mono-select][mono-validation-state=\"warning\"] > [mono-trigger] {\r\n --_mono-select-bc: color-mix(in oklab, var(--_mono-select-warning) var(--mono-mode-state-border-alpha), transparent);\r\n --_mono-select-ring: 0 0 0 var(--_mono-select-ring-width) color-mix(in oklab, var(--_mono-select-warning) var(--mono-mode-state-ring-alpha), transparent);\r\n}\r\n\r\n/* EXTENSION — readonly: focusable, on a muted surface, no gestures */\r\n[mono-select][mono-readonly] > [mono-trigger] {\r\n background: var(--mono-select-readonly-bg, var(--muted));\r\n cursor: default;\r\n}\r\n\r\n/* basecoat@1.0.2 components/select.css .select:not(select) > button — disabled:\r\n pointer-events-none cursor-not-allowed opacity-50 */\r\n[mono-select][mono-disabled] > [mono-trigger],\r\n[mono-select] > [mono-trigger]:disabled,\r\n/* a raw readonly select can only disable its native <select>; the root attribute wins */\r\n[mono-select]:not([mono-readonly]) > [mono-trigger]:has(> [mono-native]:disabled) {\r\n opacity: 0.5;\r\n pointer-events: none;\r\n cursor: not-allowed;\r\n background: var(--mono-select-disabled-bg, var(--_mono-select-bg));\r\n}\r\n\r\n/* =========================================\r\n Value / search field / native <select>\r\n ========================================= */\r\n\r\n/* basecoat@1.0.2 components/select.css .select:not(select) > button > span —\r\n flex flex-1 overflow-hidden text-ellipsis whitespace-nowrap text-start */\r\n/* basecoat@1.0.2 styles/vega.css .select:not(select) > button > span — gap-1.5 */\r\n[mono-select] [mono-value] {\r\n flex: 1 1 auto;\r\n min-width: 0;\r\n display: flex;\r\n align-items: center;\r\n gap: var(--_mono-select-gap);\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n text-align: start;\r\n color: var(--_mono-select-text);\r\n}\r\n\r\n[mono-select] [mono-value] > span {\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n\r\n[mono-select] [mono-value][mono-placeholder] {\r\n color: var(--_mono-select-placeholder);\r\n}\r\n\r\n/* basecoat@1.0.2 components/combobox.css .combobox > input[role='combobox'] — the\r\n search input lives INSIDE our trigger box, so it is borderless like\r\n .input-group > input and the box around it carries the chrome */\r\n[mono-select] [mono-search-field],\r\n[mono-select] [mono-native] {\r\n flex: 1 1 auto;\r\n width: 100%;\r\n min-width: 0;\r\n align-self: stretch;\r\n appearance: none;\r\n margin: 0;\r\n padding: 0;\r\n border: 0;\r\n border-radius: 0;\r\n outline: none;\r\n background: transparent;\r\n box-shadow: none;\r\n color: var(--_mono-select-text);\r\n font: inherit;\r\n line-height: var(--_mono-select-line-height);\r\n\r\n &:focus,\r\n &:focus-visible {\r\n outline: none !important;\r\n }\r\n\r\n &::placeholder {\r\n color: var(--_mono-select-placeholder);\r\n }\r\n\r\n &:disabled {\r\n cursor: not-allowed;\r\n }\r\n}\r\n\r\n[mono-select] [mono-search-field] {\r\n cursor: text;\r\n}\r\n\r\n[mono-select] [mono-native] {\r\n cursor: inherit;\r\n}\r\n\r\n[mono-select] [mono-native] option {\r\n color: var(--_mono-select-text);\r\n background: var(--popover);\r\n}\r\n\r\n/* =========================================\r\n Actions — the chevron and the clear button\r\n ========================================= */\r\n\r\n[mono-select] [mono-actions] {\r\n display: flex;\r\n align-items: center;\r\n gap: var(--mono-spacing);\r\n flex-shrink: 0;\r\n line-height: 1;\r\n}\r\n\r\n/* basecoat@1.0.2 styles/vega.css .select:not(select) > button > svg — size-4\r\n text-muted-foreground; mono: the glyph sits in a square action box so the\r\n chevron and the clear button occupy the same gutter */\r\n/* basecoat@1.0.2 components/combobox.css .combobox [data-clear] — size-6 border-0\r\n bg-transparent p-0 text-current */\r\n[mono-select] [mono-arrow],\r\n[mono-select] [mono-clear] {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n flex-shrink: 0;\r\n width: var(--_mono-select-action);\r\n height: var(--_mono-select-action);\r\n margin: 0;\r\n padding: 0;\r\n border: 0;\r\n border-radius: var(--mono-select-clear-radius, calc(var(--radius) - 5px));\r\n background: transparent;\r\n color: var(--_mono-select-muted);\r\n font: inherit;\r\n line-height: 1;\r\n cursor: pointer;\r\n transition-property: color, background-color, transform;\r\n transition-timing-function: var(--mono-ease);\r\n transition-duration: var(--mono-duration);\r\n}\r\n\r\n[mono-select] :is([mono-arrow], [mono-clear]) > :is(svg, .mono-icon, [mono-icon]) {\r\n display: block;\r\n width: var(--_mono-select-icon);\r\n height: var(--_mono-select-icon);\r\n pointer-events: none;\r\n}\r\n\r\n/* EXTENSION — the chevron turns while the panel is open */\r\n[mono-select][mono-open] [mono-arrow] > :is(svg, .mono-icon, [mono-icon]) {\r\n transform: rotate(180deg);\r\n}\r\n\r\n/* basecoat@1.0.2 styles/vega.css .btn[data-variant='ghost'] — hover:bg-muted\r\n hover:text-foreground (dark:hover:bg-muted/50 via --mono-mode-ghost-hover) */\r\n@media (hover: hover) {\r\n [mono-select] :is([mono-arrow], [mono-clear]):hover {\r\n background: var(--mono-mode-ghost-hover);\r\n color: var(--_mono-select-text);\r\n }\r\n}\r\n\r\n/* =========================================\r\n The panel\r\n ========================================= */\r\n\r\n/* basecoat@1.0.2 components/popover.css [data-popover] — absolute z-50 min-w-full\r\n overflow-x-hidden; mono: `display: none` while closed (the contents are only\r\n rendered while open), `--mono-popup-z` from the shared popup stack and\r\n `--mono-popup-avail-h` from the portal controller cap the whole panel */\r\n/* basecoat@1.0.2 styles/vega.css .select:not(select) [data-popover] — bg-popover\r\n text-popover-foreground rounded-md shadow-md ring-1 ring-foreground/10; the\r\n `p-1` moves to the scrolling body (the combobox layout), so the scrollbar\r\n never paints over the padding */\r\n[mono-select] > [mono-dropdown] {\r\n position: absolute;\r\n /* `top: auto` = the static position: the panel follows the trigger in the DOM,\r\n so in block flow it lands right under it (the popup controller overrides\r\n this inline for the element; hand-written markup relies on it). */\r\n top: auto;\r\n /* the 6px offset as a transform: the controller writes `transform: none` inline\r\n with its fixed position, so only the hand-written panel is pushed down */\r\n transform: translateY(calc(var(--mono-spacing) * 1.5));\r\n /* Both edges pinned, so the panel matches the field by default. An inline\r\n `width` from `:dropdown.prop=\"{ width }\"` is then the over-constrained case,\r\n which CSS resolves by ignoring `right` — the panel keeps this left edge and\r\n takes the given width. */\r\n left: 0;\r\n right: 0;\r\n z-index: var(--mono-popup-z, 1000);\r\n display: none;\r\n /* Basecoat's `min-w-[max(100%,9rem)]` is relative to the .select box; a portaled\r\n panel is position: fixed, where 100% would be the viewport — the controller\r\n writes the anchor's width inline instead, so only the floor stays. */\r\n min-width: var(--mono-select-dropdown-min-width, 9rem);\r\n max-height: var(--mono-popup-avail-h, none);\r\n overflow: hidden;\r\n isolation: isolate;\r\n border-radius: var(--mono-select-dropdown-radius, var(--mono-radius-md));\r\n background: var(--mono-select-dropdown-bg, var(--popover));\r\n color: var(--mono-select-dropdown-color, var(--popover-foreground));\r\n box-shadow: var(--mono-select-dropdown-ring, 0 0 0 1px color-mix(in oklab, var(--foreground) 10%, transparent)), var(--mono-select-dropdown-shadow, var(--mono-shadow-md));\r\n font-size: var(--mono-select-option-font-size, var(--mono-text-sm));\r\n line-height: var(--mono-select-option-line-height, var(--mono-text-sm--lh));\r\n}\r\n\r\n[mono-select][mono-open] > [mono-dropdown] {\r\n /* A flex column (not `block`) so the body can shrink past its own height when\r\n the panel is clamped above. */\r\n display: flex;\r\n flex-direction: column;\r\n}\r\n\r\n/* basecoat@1.0.2 styles/vega.css .combobox [role='listbox'] — max-h-[min(18rem,\r\n var(--available-height,18rem))] scroll-py-1 overflow-y-auto p-1 */\r\n[mono-select] [mono-dropdown-body] {\r\n flex: 1 1 auto;\r\n min-height: 0;\r\n max-height: 18rem;\r\n padding: var(--mono-select-dropdown-padding, var(--mono-spacing));\r\n overflow: auto;\r\n overscroll-behavior: contain;\r\n scroll-padding-block: var(--mono-select-dropdown-padding, var(--mono-spacing));\r\n outline-style: none;\r\n}\r\n\r\n/* =========================================\r\n Options\r\n -----------------------------------------\r\n Each rule also lists the stamped twin of a row rendered through `slot=\"list\"`\r\n (`[data-mono-type='row']`, `[data-mono-active]`, `[data-mono-selected]`), so\r\n the two can never drift: what you render in the slot IS an option. `:where()`\r\n wraps only the CONTAINER, keeping the twin at attribute weight.\r\n ========================================= */\r\n\r\n/* basecoat@1.0.2 components/select.css .select:not(select) [role='option'] — relative\r\n flex w-full cursor-default items-center overflow-hidden text-ellipsis whitespace-\r\n nowrap outline-none select-none; disabled: pointer-events-none opacity-50 */\r\n/* basecoat@1.0.2 styles/vega.css .select:not(select) [role='option'] — gap-2\r\n rounded-sm py-1.5 ps-2 pe-8 text-sm, svg size-4 */\r\n[mono-select] [mono-item],\r\n[mono-select] :where([mono-list-slot]) [data-mono-type='row'] {\r\n position: relative;\r\n display: flex;\r\n width: 100%;\r\n align-items: center;\r\n gap: var(--mono-select-option-gap, calc(var(--mono-spacing) * 2));\r\n margin: 0;\r\n padding-block: var(--mono-select-option-padding-y, calc(var(--mono-spacing) * 1.5));\r\n padding-inline: var(--mono-select-option-padding-x, calc(var(--mono-spacing) * 2)) var(--mono-select-option-padding-end, calc(var(--mono-spacing) * 8));\r\n min-height: var(--mono-select-option-min-height, 0);\r\n border: 0;\r\n border-radius: var(--mono-select-option-radius, var(--mono-radius-sm));\r\n /* longhands, so the selected row's check (a background-image) survives the\r\n active / hover background */\r\n background-color: transparent;\r\n background-image: none;\r\n color: var(--_mono-select-text);\r\n font-family: inherit;\r\n font-size: var(--mono-select-option-font-size, var(--mono-text-sm));\r\n line-height: var(--mono-select-option-line-height, var(--mono-text-sm--lh));\r\n font-weight: var(--mono-select-option-font-weight, var(--mono-font-weight-normal));\r\n text-align: start;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n outline-style: none;\r\n user-select: none;\r\n cursor: default;\r\n transition-property: color, background-color;\r\n transition-timing-function: var(--mono-ease);\r\n transition-duration: var(--mono-duration-fast);\r\n}\r\n\r\n/* EXTENSION: a hair of air between rows. Upstream stacks its options flush, so an\r\n active row directly under the selected one read as ONE tall highlight; a 2px\r\n seam keeps the two rounded-sm washes apart. `--mono-select-option-spacing`. */\r\n[mono-select] [mono-item] + [mono-item],\r\n[mono-select] :where([mono-list-slot]) [data-mono-type='row'] + [data-mono-type='row'] {\r\n margin-top: var(--mono-select-option-spacing, 2px);\r\n}\r\n\r\n[mono-select] [mono-item] svg:not([class*='size-']),\r\n[mono-select] [mono-item] .mono-icon {\r\n width: var(--_mono-select-icon);\r\n height: var(--_mono-select-icon);\r\n flex-shrink: 0;\r\n pointer-events: none;\r\n}\r\n\r\n/* basecoat@1.0.2 styles/vega.css .select:not(select) [role='option'].active, .select:not(select) [role='option']:focus-visible\r\n — bg-muted text-foreground. The keyboard cursor and the pointer share one look. */\r\n[mono-select] [mono-item][mono-active]:not([mono-disabled]):not(:disabled),\r\n[mono-select] [mono-item]:focus-visible,\r\n[mono-select] :where([mono-list-slot]) [data-mono-active] {\r\n background-color: var(--mono-select-option-active-bg, var(--muted));\r\n color: var(--mono-select-option-active-color, var(--_mono-select-text));\r\n}\r\n\r\n/* basecoat@1.0.2 components/select.css .select:not(select):not([data-select-initialized]) [role='option']:not([aria-disabled='true']):not(:disabled):hover, .select:not(select) [role='option'].active\r\n — the pointer highlight is NOT behind (hover: hover) upstream */\r\n[mono-select] [mono-item]:hover:not([mono-disabled]):not(:disabled),\r\n[mono-select] :where([mono-list-slot]) [data-mono-type='row']:hover {\r\n background-color: var(--mono-select-option-active-bg, var(--muted));\r\n color: var(--mono-select-option-active-color, var(--_mono-select-text));\r\n}\r\n\r\n/* basecoat@1.0.2 components/select.css .select:not(select) [role='option'][aria-selected='true']\r\n — the --check-icon at the end (bg-size .875rem, center right .5rem) */\r\n[mono-select] [mono-item][mono-selected],\r\n[mono-select] :where([mono-list-slot]) [data-mono-type='row'][data-mono-selected] {\r\n background-image: var(--mono-select-check-icon, var(--check-icon));\r\n background-size: var(--mono-select-check-size, 0.875rem);\r\n background-position: center right calc(var(--mono-spacing) * 2);\r\n background-repeat: no-repeat;\r\n font-weight: var(--mono-select-option-selected-font-weight, var(--mono-select-option-font-weight, var(--mono-font-weight-normal)));\r\n}\r\n\r\n[mono-select] [mono-item][mono-selected]:dir(rtl),\r\n[mono-select] :where([mono-list-slot]) [data-mono-type='row'][data-mono-selected]:dir(rtl) {\r\n background-position: center left calc(var(--mono-spacing) * 2);\r\n}\r\n\r\n[mono-select] [mono-item][mono-disabled],\r\n[mono-select] [mono-item]:disabled {\r\n opacity: 0.5;\r\n pointer-events: none;\r\n cursor: not-allowed;\r\n}\r\n\r\n/* basecoat@1.0.2 styles/vega.css .select:not(select) [role='listbox']:not(:has([data-value]:not([aria-hidden='true'])))::before\r\n — py-6 text-center text-sm (the \"No results found\" row) */\r\n[mono-select] [mono-empty-row] {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n padding-block: calc(var(--mono-spacing) * 6);\r\n padding-inline: calc(var(--mono-spacing) * 3);\r\n font-size: var(--mono-select-option-font-size, var(--mono-text-sm));\r\n line-height: var(--mono-select-option-line-height, var(--mono-text-sm--lh));\r\n color: var(--_mono-select-muted);\r\n text-align: center;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n cursor: default;\r\n user-select: none;\r\n}\r\n\r\n/* basecoat@1.0.2 styles/vega.css .select:not(select) [role='heading'] — px-2 py-1.5\r\n text-xs text-muted-foreground; EXTENSION: one indent step per nesting level */\r\n[mono-select] [mono-group],\r\n[mono-select] :where([mono-list-slot]) [data-mono-type='group'] {\r\n --_ms-group-level: 0;\r\n padding-block: var(--mono-select-group-padding-y, calc(var(--mono-spacing) * 1.5));\r\n padding-inline: var(--mono-select-group-padding-x, calc(var(--mono-spacing) * 2));\r\n padding-inline-start: calc(var(--mono-select-group-padding-x, calc(var(--mono-spacing) * 2)) + var(--_ms-group-level) * calc(var(--mono-spacing) * 2));\r\n font-size: var(--mono-select-group-font-size, var(--mono-text-xs));\r\n line-height: var(--mono-select-group-line-height, var(--mono-text-xs--lh));\r\n font-weight: var(--mono-select-group-font-weight, var(--mono-font-weight-normal));\r\n text-transform: var(--mono-select-group-text-transform, none);\r\n letter-spacing: var(--mono-select-group-letter-spacing, normal);\r\n color: var(--_mono-select-muted);\r\n cursor: default;\r\n user-select: none;\r\n}\r\n\r\n[mono-select] [mono-group][mono-level='1'],\r\n[mono-select] :where([mono-list-slot]) [data-mono-type='group'][data-mono-level='1'] { --_ms-group-level: 1; }\r\n[mono-select] [mono-group][mono-level='2'],\r\n[mono-select] :where([mono-list-slot]) [data-mono-type='group'][data-mono-level='2'] { --_ms-group-level: 2; }\r\n[mono-select] [mono-group][mono-level='3'],\r\n[mono-select] :where([mono-list-slot]) [data-mono-type='group'][data-mono-level='3'] { --_ms-group-level: 3; }\r\n\r\n/* group-sticky: pin headers while their rows scroll; nested levels stack on the\r\n panel's own surface so options scroll cleanly underneath. */\r\n[mono-select] [mono-group][mono-sticky] {\r\n position: sticky;\r\n top: calc(var(--_ms-group-level) * 1.5rem);\r\n z-index: calc(5 - var(--_ms-group-level));\r\n background: var(--mono-select-dropdown-bg, var(--popover));\r\n}\r\n\r\n/* EXTENSION — the load-more affordance: an option-shaped ghost button */\r\n[mono-select] [mono-load-more] {\r\n display: flex;\r\n width: 100%;\r\n align-items: center;\r\n justify-content: center;\r\n gap: var(--mono-select-option-gap, calc(var(--mono-spacing) * 2));\r\n margin: 0;\r\n padding-block: var(--mono-select-option-padding-y, calc(var(--mono-spacing) * 1.5));\r\n padding-inline: var(--mono-select-option-padding-x, calc(var(--mono-spacing) * 2));\r\n border: 0;\r\n border-radius: var(--mono-select-option-radius, var(--mono-radius-sm));\r\n background: transparent;\r\n color: var(--_mono-select-muted);\r\n font-family: inherit;\r\n font-size: var(--mono-select-option-font-size, var(--mono-text-sm));\r\n line-height: var(--mono-select-option-line-height, var(--mono-text-sm--lh));\r\n font-weight: var(--mono-font-weight-medium);\r\n cursor: pointer;\r\n transition-property: color, background-color;\r\n transition-timing-function: var(--mono-ease);\r\n transition-duration: var(--mono-duration-fast);\r\n}\r\n\r\n@media (hover: hover) {\r\n [mono-select] [mono-load-more]:hover:not([mono-loading]) {\r\n background-color: var(--mono-select-option-active-bg, var(--muted));\r\n color: var(--_mono-select-text);\r\n }\r\n}\r\n\r\n[mono-select] [mono-load-more][mono-loading] {\r\n cursor: default;\r\n opacity: 0.7;\r\n}\r\n\r\n/* Consumer-rendered option rows (slot=\"list\"). `display: contents` so mono's own\r\n placement wrapper generates no box: the rows the consumer writes lay out as if\r\n they were direct children of the panel. */\r\n[mono-select] [mono-list-slot] {\r\n display: contents;\r\n}\r\n\r\n/* =========================================\r\n Message — helper / validation text under the field\r\n ========================================= */\r\n\r\n/* basecoat@1.0.2 styles/vega.css .fieldset legend + p, .field > p, .field section > p\r\n — text-sm text-muted-foreground leading-normal font-normal */\r\n[mono-select] > [mono-message-wrap] {\r\n display: block;\r\n margin-top: var(--_mono-select-gap-y);\r\n}\r\n\r\n[mono-select] > [mono-message-wrap]:not(:has([mono-message]:not([mono-empty]))) {\r\n display: none;\r\n}\r\n\r\n[mono-select] [mono-message] {\r\n font-size: var(--mono-select-message-font-size, var(--mono-text-sm));\r\n line-height: var(--mono-select-message-line-height, var(--mono-leading-normal));\r\n font-weight: var(--mono-font-weight-normal);\r\n text-align: start;\r\n color: var(--_mono-select-muted);\r\n}\r\n\r\n/* basecoat@1.0.2 styles/vega.css .field [role=\"alert\"] — text-destructive text-sm */\r\n[mono-select] [mono-message=\"invalid\"] {\r\n color: var(--_mono-select-invalid);\r\n}\r\n\r\n[mono-select] [mono-message=\"valid\"] {\r\n color: var(--_mono-select-valid);\r\n}\r\n\r\n[mono-select] [mono-message=\"warning\"] {\r\n color: var(--_mono-select-warning);\r\n}\r\n\r\n@media (prefers-reduced-motion: reduce) {\r\n [mono-select] > [mono-trigger],\r\n [mono-select] [mono-arrow],\r\n [mono-select] [mono-clear],\r\n [mono-select] [mono-item] {\r\n transition: none;\r\n }\r\n}\r\n";
|
|
1894
|
+
//#endregion
|
|
1895
|
+
//#region src/components/select/mono-select.shadow.ts
|
|
1896
|
+
var SHADOW_EXTRA_CSS = `
|
|
1897
|
+
[mono-value] > slot[name='prefix'],
|
|
1898
|
+
[mono-value] > slot[name='suffix'] {
|
|
1899
|
+
display: contents;
|
|
1900
|
+
}
|
|
1901
|
+
`;
|
|
1902
|
+
var MonoSelectShadow = class MonoSelectShadow extends withShadowUtilityStyles(MonoSelectCore(LitElement)) {
|
|
1903
|
+
static {
|
|
1904
|
+
this.disableWarning?.("change-in-update");
|
|
1905
|
+
}
|
|
1906
|
+
static {
|
|
1907
|
+
this.styles = [unsafeCSS(toShadowCss(select_default, {
|
|
1908
|
+
host: "mono-select",
|
|
1909
|
+
append: SHADOW_EXTRA_CSS
|
|
1910
|
+
}))];
|
|
1911
|
+
}
|
|
1912
|
+
get _slotsAlwaysRender() {
|
|
1913
|
+
return true;
|
|
1914
|
+
}
|
|
1915
|
+
connectedCallback() {
|
|
1916
|
+
super.connectedCallback();
|
|
1917
|
+
this._onLateListSlot();
|
|
1918
|
+
if (isServer) return;
|
|
1919
|
+
flushSsrHydration(this);
|
|
1920
|
+
}
|
|
1921
|
+
firstUpdated(changed) {
|
|
1922
|
+
super.firstUpdated(changed);
|
|
1923
|
+
if (isServer) return;
|
|
1924
|
+
this._scanSlots();
|
|
1925
|
+
}
|
|
1926
|
+
updated(changed) {
|
|
1927
|
+
super.updated(changed);
|
|
1928
|
+
if (isServer) return;
|
|
1929
|
+
this._watchListChrome();
|
|
1930
|
+
this._syncListChrome();
|
|
1931
|
+
}
|
|
1932
|
+
/** A wrapper appeared after connect — the flag is all this build needs, projection does the rest. */
|
|
1933
|
+
_onLateListSlot() {
|
|
1934
|
+
const has = !!this._lateListSlot.find();
|
|
1935
|
+
if (has !== this._hasListSlotState) this._setSlotState("list", has);
|
|
1936
|
+
}
|
|
1937
|
+
_scanSlots() {
|
|
1938
|
+
for (const name of [
|
|
1939
|
+
"label",
|
|
1940
|
+
"helper",
|
|
1941
|
+
"prefix",
|
|
1942
|
+
"suffix"
|
|
1943
|
+
]) {
|
|
1944
|
+
const slot = this.renderRoot.querySelector(`slot[name="${name}"]`);
|
|
1945
|
+
this._setSlotState(name, this._slotHasContent(slot));
|
|
1946
|
+
}
|
|
1947
|
+
this._onLateListSlot();
|
|
1948
|
+
}
|
|
1949
|
+
_slotHasContent(slot) {
|
|
1950
|
+
return !!slot && slot.assignedNodes({ flatten: true }).some((n) => n.nodeType === Node.ELEMENT_NODE || !!(n.textContent ?? "").trim());
|
|
1951
|
+
}
|
|
1952
|
+
_onSlotChange(name, event) {
|
|
1953
|
+
this._setSlotState(name, this._slotHasContent(event.target));
|
|
1954
|
+
}
|
|
1955
|
+
/**
|
|
1956
|
+
* The consumer's list wrapper, PROJECTED rather than moved.
|
|
1957
|
+
*
|
|
1958
|
+
* Projection is what makes this work in a shadow root at all: slotted content stays in the light
|
|
1959
|
+
* DOM, so the app's own stylesheet still reaches it. Moving those nodes inside the shadow root
|
|
1960
|
+
* would cut them off from it — the same reason this build inlines SVGs instead of icon classes.
|
|
1961
|
+
*/
|
|
1962
|
+
renderListSlot() {
|
|
1963
|
+
return html`<div class="mono-select-list-slot" mono-list-slot @click=${this._onListSlotClick}>
|
|
1964
|
+
<slot name="list" @slotchange=${() => this._scanSlots()}></slot>
|
|
1965
|
+
</div>`;
|
|
1966
|
+
}
|
|
1967
|
+
/** Native `<slot>` carrying the prop fallback as native slot content. */
|
|
1968
|
+
_slotOutlet(name, fallback = nothing) {
|
|
1969
|
+
return html`<slot
|
|
1970
|
+
name=${name}
|
|
1971
|
+
@slotchange=${(e) => this._onSlotChange(name, e)}
|
|
1972
|
+
>${fallback}</slot
|
|
1973
|
+
>`;
|
|
1974
|
+
}
|
|
1975
|
+
/** Inline SVG — the global `.mono-icon`/`i-mdi-*` UnoCSS icons can't reach a
|
|
1976
|
+
* shadow root. */
|
|
1977
|
+
renderIcon(name) {
|
|
1978
|
+
return html`<svg
|
|
1979
|
+
class="mono-icon"
|
|
1980
|
+
mono-icon
|
|
1981
|
+
viewBox="0 0 24 24"
|
|
1982
|
+
width="1em"
|
|
1983
|
+
height="1em"
|
|
1984
|
+
fill="currentColor"
|
|
1985
|
+
aria-hidden="true"
|
|
1986
|
+
>
|
|
1987
|
+
<path d=${name === "close" ? "M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" : "M7.41 8.58 12 13.17l4.59-4.59L18 10l-6 6-6-6z"}></path>
|
|
1988
|
+
</svg>`;
|
|
1989
|
+
}
|
|
1990
|
+
};
|
|
1991
|
+
MonoSelectShadow = __decorate([customElement("mono-shadow-select")], MonoSelectShadow);
|
|
1992
|
+
//#endregion
|
|
1993
|
+
//#region src/components/select/select-utils.ts
|
|
1994
|
+
function validateSelectProps(props) {
|
|
1995
|
+
const validSizes = [
|
|
1996
|
+
"xs",
|
|
1997
|
+
"sm",
|
|
1998
|
+
"md",
|
|
1999
|
+
"lg",
|
|
2000
|
+
"xl",
|
|
2001
|
+
"xxl"
|
|
2002
|
+
];
|
|
2003
|
+
const validColors = [
|
|
2004
|
+
"primary",
|
|
2005
|
+
"secondary",
|
|
2006
|
+
"success",
|
|
2007
|
+
"danger",
|
|
2008
|
+
"warning",
|
|
2009
|
+
"info",
|
|
2010
|
+
"teal",
|
|
2011
|
+
"purple",
|
|
2012
|
+
"neutral",
|
|
2013
|
+
"dark"
|
|
2014
|
+
];
|
|
2015
|
+
const validVariants = [
|
|
2016
|
+
"outlined",
|
|
2017
|
+
"filled",
|
|
2018
|
+
"underlined"
|
|
2019
|
+
];
|
|
2020
|
+
const validStates = [
|
|
2021
|
+
"default",
|
|
2022
|
+
"valid",
|
|
2023
|
+
"invalid",
|
|
2024
|
+
"warning"
|
|
2025
|
+
];
|
|
2026
|
+
if (props.size && !validSizes.includes(props.size)) return false;
|
|
2027
|
+
if (props.color && !validColors.includes(props.color)) return false;
|
|
2028
|
+
if (props.variant && !validVariants.includes(props.variant)) return false;
|
|
2029
|
+
if (props.validationState && !validStates.includes(props.validationState)) return false;
|
|
2030
|
+
return true;
|
|
2031
|
+
}
|
|
2032
|
+
//#endregion
|
|
2033
|
+
export { MonoSelectCore, MonoSelectShadow, validateSelectProps };
|