@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,2819 @@
|
|
|
1
|
+
import { r as readAllRows } from "../data-source-read-DL88aH8t.js";
|
|
2
|
+
import { f as searchRowPredicate, r as MonoSourceSearch, u as resolveSearchFields } from "../data-search-Bwo5bg8K.js";
|
|
3
|
+
import { n as unwrapReactive, r as unwrapReactiveDeep } from "../reactive-D3EERqgO.js";
|
|
4
|
+
import { l as monoHostChildNodes } from "../mono-ui-CPV7rrdo.js";
|
|
5
|
+
import { t as customElement } from "../mono-element-B0kP_96P.js";
|
|
6
|
+
import { a as defineHybridPropAliases, n as arrayHasChanged, r as booleanStringConverter, t as __decorate } from "../decorate-DEXtNagw.js";
|
|
7
|
+
import { t as dispatchMonoEvent } from "../mono-event-Bi1qP9uN.js";
|
|
8
|
+
import { s as placeSlotNode, t as LateSlotWatcher } from "../light-slots-DW1WgfgT.js";
|
|
9
|
+
import { n as toCssSize, t as buildSizeStyle } from "../css-size-DhHSVZJK.js";
|
|
10
|
+
import { t as PopupPortalController } from "../popup-portal-BziRX1yG.js";
|
|
11
|
+
import { n as chevronIcon, t as caretIcon } from "../field-icons-BoOG6KrL.js";
|
|
12
|
+
import { t as MonoFormControlCore } from "../form-control-core-eeRr0zLU.js";
|
|
13
|
+
import { t as DataSourceController } from "../data-source-controller-C50Qyfzh.js";
|
|
14
|
+
import { n as visibleChipCap, r as ChipStripController, t as resolveChipLimit } from "../chip-limits-BMoO31JM.js";
|
|
15
|
+
import { LitElement, html, isServer, nothing, unsafeCSS } from "lit";
|
|
16
|
+
import { property, query, state } from "lit/decorators.js";
|
|
17
|
+
import { ifDefined } from "lit/directives/if-defined.js";
|
|
18
|
+
import { styleMap } from "lit/directives/style-map.js";
|
|
19
|
+
//#region src/components/tag-input/tag-input-core.ts
|
|
20
|
+
var numberStringConverter = {
|
|
21
|
+
fromAttribute(value) {
|
|
22
|
+
if (value === null || value === "") return void 0;
|
|
23
|
+
const parsed = Number(value);
|
|
24
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
25
|
+
},
|
|
26
|
+
toAttribute(value) {
|
|
27
|
+
if (value === void 0 || value === null) return null;
|
|
28
|
+
return String(value);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* `MonoTagInputCore` — render-mode-agnostic logic for `mono-tag-input` (props,
|
|
33
|
+
* hybrid aliases, array value/model sync, DataSource paging, search, grouping,
|
|
34
|
+
* keyboard, tag chips, the popup controller, and the full `render()`). SSR-safe:
|
|
35
|
+
* every `document`/`window`/focus access is `isServer`-guarded. Each build
|
|
36
|
+
* supplies `createRenderRoot()` + `static styles`, the slot strategy (light
|
|
37
|
+
* captures children into `data-mono-slot` placeholders; shadow uses native
|
|
38
|
+
* `<slot>`), and the `_slotOutlet` / `renderIcon` hooks. Mirrors `select-core`.
|
|
39
|
+
*/
|
|
40
|
+
var MonoTagInputCore = (superClass) => {
|
|
41
|
+
class MonoTagInputCoreClass extends MonoFormControlCore(superClass) {
|
|
42
|
+
constructor(...args) {
|
|
43
|
+
super(...args);
|
|
44
|
+
this.size = "md";
|
|
45
|
+
this.color = "primary";
|
|
46
|
+
this.variant = "outlined";
|
|
47
|
+
this.chip = {};
|
|
48
|
+
this.modelValue = [];
|
|
49
|
+
this.value = [];
|
|
50
|
+
this.name = "";
|
|
51
|
+
this.label = "";
|
|
52
|
+
this.placeholder = "Add tag...";
|
|
53
|
+
this.helperText = "";
|
|
54
|
+
this.validationState = "default";
|
|
55
|
+
this.validationMessage = "";
|
|
56
|
+
this.errorMessage = "";
|
|
57
|
+
this.successMessage = "";
|
|
58
|
+
this.disabled = false;
|
|
59
|
+
this.readonly = false;
|
|
60
|
+
this.required = false;
|
|
61
|
+
this.clearable = false;
|
|
62
|
+
this.allowCustom = true;
|
|
63
|
+
this.checkable = false;
|
|
64
|
+
this.selectAll = true;
|
|
65
|
+
this.selectAllLabel = "All";
|
|
66
|
+
this.groupSelectAll = true;
|
|
67
|
+
this.items = [];
|
|
68
|
+
this.dataSource = null;
|
|
69
|
+
this.immediate = true;
|
|
70
|
+
this.pageSize = 10;
|
|
71
|
+
this.dropdownHeight = "";
|
|
72
|
+
this.dropdownMaxHeight = "";
|
|
73
|
+
this.flip = true;
|
|
74
|
+
this.shift = true;
|
|
75
|
+
this.keyValue = "";
|
|
76
|
+
this.displayValue = "";
|
|
77
|
+
this.displayGroup = [];
|
|
78
|
+
this.groupKey = "key";
|
|
79
|
+
this.groupItems = "items";
|
|
80
|
+
this.group = false;
|
|
81
|
+
this.groupSticky = false;
|
|
82
|
+
this.searchable = true;
|
|
83
|
+
this.stayOpen = false;
|
|
84
|
+
this.searchValue = "";
|
|
85
|
+
this.searchOperation = "contains";
|
|
86
|
+
this.searchDebounce = 300;
|
|
87
|
+
this.cssClass = {};
|
|
88
|
+
this.cssClassName = "";
|
|
89
|
+
this._inputValue = "";
|
|
90
|
+
this._open = false;
|
|
91
|
+
this._activeIndex = -1;
|
|
92
|
+
this._cursorPending = false;
|
|
93
|
+
this._moreOpen = false;
|
|
94
|
+
this._selectAllPending = false;
|
|
95
|
+
this._scrollAutoMaxHeight = "";
|
|
96
|
+
this._hasLabelSlotState = false;
|
|
97
|
+
this._hasHelperSlotState = false;
|
|
98
|
+
this._chipStrip = new ChipStripController(this, {
|
|
99
|
+
strip: () => this.renderRoot?.querySelector(".mono-tag-input-chip-strip"),
|
|
100
|
+
enabled: () => this._chipBehaviour === "inline"
|
|
101
|
+
});
|
|
102
|
+
this._popup = new PopupPortalController(this, {
|
|
103
|
+
getPanel: () => this.renderRoot.querySelector(".mono-tag-input-dropdown"),
|
|
104
|
+
getAnchor: () => this.renderRoot.querySelector(".mono-tag-input-field"),
|
|
105
|
+
getStyleScope: () => this.renderRoot.querySelector(".mono-tag-input"),
|
|
106
|
+
isOpen: () => this._open,
|
|
107
|
+
matchWidth: () => !toCssSize(this.dropdown?.width),
|
|
108
|
+
offset: () => 6,
|
|
109
|
+
flip: () => this.flip,
|
|
110
|
+
shift: () => this.shift,
|
|
111
|
+
constrainSize: () => true
|
|
112
|
+
});
|
|
113
|
+
this._morePopup = new PopupPortalController(this, {
|
|
114
|
+
getPanel: () => this.renderRoot.querySelector(".mono-tag-input-more-panel"),
|
|
115
|
+
getAnchor: () => this.renderRoot.querySelector(".mono-tag-input-field"),
|
|
116
|
+
getStyleScope: () => this.renderRoot.querySelector(".mono-tag-input"),
|
|
117
|
+
isOpen: () => this._moreOpen,
|
|
118
|
+
matchWidth: () => true,
|
|
119
|
+
offset: () => 6,
|
|
120
|
+
flip: () => true,
|
|
121
|
+
shift: () => true,
|
|
122
|
+
constrainSize: () => true
|
|
123
|
+
});
|
|
124
|
+
this._inputId = `mono-tag-input-${Math.random().toString(36).slice(2)}`;
|
|
125
|
+
this._messageId = `${this._inputId}-message`;
|
|
126
|
+
this._listboxId = `${this._inputId}-listbox`;
|
|
127
|
+
this._lateListSlot = new LateSlotWatcher(this, "list", () => this._onLateListSlot());
|
|
128
|
+
this._sourceSearch = new MonoSourceSearch();
|
|
129
|
+
this._searchVersion = 0;
|
|
130
|
+
this._selectedItemCache = /* @__PURE__ */ new Map();
|
|
131
|
+
this._handleDocumentClick = (event) => {
|
|
132
|
+
if (this.stayOpen) return;
|
|
133
|
+
if (!this._open && !this._moreOpen) return;
|
|
134
|
+
const path = event.composedPath();
|
|
135
|
+
if (path.includes(this) || this._popup.containsInPath(path) || this._morePopup.containsInPath(path)) return;
|
|
136
|
+
this._close();
|
|
137
|
+
this._moreOpen = false;
|
|
138
|
+
};
|
|
139
|
+
this._handleDocumentFocusIn = (event) => {
|
|
140
|
+
if (this.stayOpen) return;
|
|
141
|
+
if (!this._open && !this._moreOpen) return;
|
|
142
|
+
const path = event.composedPath();
|
|
143
|
+
if (path.includes(this) || this._popup.containsInPath(path) || this._morePopup.containsInPath(path)) return;
|
|
144
|
+
this._close();
|
|
145
|
+
this._moreOpen = false;
|
|
146
|
+
};
|
|
147
|
+
this._handleDocumentKeydown = (event) => {
|
|
148
|
+
if (!this._open && !this._moreOpen) return;
|
|
149
|
+
if (event.key === "Escape") {
|
|
150
|
+
event.preventDefault();
|
|
151
|
+
this._close();
|
|
152
|
+
this._moreOpen = false;
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
this._renderedChipCount = 0;
|
|
156
|
+
this._measuredChipCount = 0;
|
|
157
|
+
this._handleDropdownScroll = (event) => {
|
|
158
|
+
if (this._loadMoreMode !== "scroll") return;
|
|
159
|
+
if (this._ds.loadingMore || this._ds.atLastPage) return;
|
|
160
|
+
const el = event.currentTarget;
|
|
161
|
+
if (!el) return;
|
|
162
|
+
if (el.scrollHeight - el.scrollTop - el.clientHeight <= 24) this._ds.loadMore();
|
|
163
|
+
};
|
|
164
|
+
this._hasListSlotState = false;
|
|
165
|
+
this._publishedEntries = [];
|
|
166
|
+
this._onListSlotClick = (event) => {
|
|
167
|
+
if (this.disabled || this.readonly) return;
|
|
168
|
+
const target = event.target;
|
|
169
|
+
const entry = target ? this._entryFromNode(target) : void 0;
|
|
170
|
+
if (!entry) return;
|
|
171
|
+
if (entry.type === "group") {
|
|
172
|
+
if (!this.checkable || !this.groupSelectAll) return;
|
|
173
|
+
const usable = (entry.items ?? []).filter((item) => this._isSelectable(item));
|
|
174
|
+
if (!usable.length) return;
|
|
175
|
+
event.preventDefault();
|
|
176
|
+
this._toggleMany(usable, event);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
const item = entry.item;
|
|
180
|
+
if (!item || !this._isSelectable(item)) return;
|
|
181
|
+
event.preventDefault();
|
|
182
|
+
this._toggleValue(this._resolveItemValue(item), event);
|
|
183
|
+
};
|
|
184
|
+
defineHybridPropAliases(this, [
|
|
185
|
+
"modelValue",
|
|
186
|
+
"helperText",
|
|
187
|
+
"validationState",
|
|
188
|
+
"validationMessage",
|
|
189
|
+
"errorMessage",
|
|
190
|
+
"successMessage",
|
|
191
|
+
"allowCustom",
|
|
192
|
+
"maxVisible",
|
|
193
|
+
"minVisible",
|
|
194
|
+
"ariaLabelText",
|
|
195
|
+
"cssClass",
|
|
196
|
+
"keyValue",
|
|
197
|
+
"displayValue",
|
|
198
|
+
"displayGroup",
|
|
199
|
+
"groupKey",
|
|
200
|
+
"groupItems",
|
|
201
|
+
"groupSticky",
|
|
202
|
+
"groupSelectAll",
|
|
203
|
+
"selectAll",
|
|
204
|
+
"selectAllLabel",
|
|
205
|
+
"searchValue",
|
|
206
|
+
"searchOperation",
|
|
207
|
+
"searchDebounce",
|
|
208
|
+
"dataSource",
|
|
209
|
+
"loadMore",
|
|
210
|
+
"pageSize",
|
|
211
|
+
"dropdownHeight",
|
|
212
|
+
"dropdownMaxHeight",
|
|
213
|
+
"minWidth",
|
|
214
|
+
"maxWidth",
|
|
215
|
+
"minHeight",
|
|
216
|
+
"maxHeight",
|
|
217
|
+
"stayOpen"
|
|
218
|
+
]);
|
|
219
|
+
/**
|
|
220
|
+
* Vue support:
|
|
221
|
+
*
|
|
222
|
+
* <mono-tag-input :cssClass="{}" />
|
|
223
|
+
* <mono-tag-input :css-class="{}" />
|
|
224
|
+
* <mono-tag-input :cssclass="{}" />
|
|
225
|
+
*/
|
|
226
|
+
Object.defineProperty(this, "css-class", {
|
|
227
|
+
get: () => this.cssClass,
|
|
228
|
+
set: (value) => {
|
|
229
|
+
this._setCssClass(value);
|
|
230
|
+
},
|
|
231
|
+
configurable: true,
|
|
232
|
+
enumerable: false
|
|
233
|
+
});
|
|
234
|
+
Object.defineProperty(this, "cssclass", {
|
|
235
|
+
get: () => this.cssClass,
|
|
236
|
+
set: (value) => {
|
|
237
|
+
this._setCssClass(value);
|
|
238
|
+
},
|
|
239
|
+
configurable: true,
|
|
240
|
+
enumerable: false
|
|
241
|
+
});
|
|
242
|
+
Object.defineProperty(this, "ariaLabel", {
|
|
243
|
+
get: () => this.ariaLabelText,
|
|
244
|
+
set: (value) => {
|
|
245
|
+
this.ariaLabelText = value == null ? void 0 : String(value);
|
|
246
|
+
},
|
|
247
|
+
configurable: true,
|
|
248
|
+
enumerable: false
|
|
249
|
+
});
|
|
250
|
+
Object.defineProperty(this, "aria-label", {
|
|
251
|
+
get: () => this.ariaLabelText,
|
|
252
|
+
set: (value) => {
|
|
253
|
+
this.ariaLabelText = value == null ? void 0 : String(value);
|
|
254
|
+
},
|
|
255
|
+
configurable: true,
|
|
256
|
+
enumerable: false
|
|
257
|
+
});
|
|
258
|
+
Object.defineProperty(this, "arialabel", {
|
|
259
|
+
get: () => this.ariaLabelText,
|
|
260
|
+
set: (value) => {
|
|
261
|
+
this.ariaLabelText = value == null ? void 0 : String(value);
|
|
262
|
+
},
|
|
263
|
+
configurable: true,
|
|
264
|
+
enumerable: false
|
|
265
|
+
});
|
|
266
|
+
this._ds = new DataSourceController(this, {
|
|
267
|
+
getDataSource: () => this.dataSource,
|
|
268
|
+
getItems: () => this.items,
|
|
269
|
+
getImmediate: () => this.immediate,
|
|
270
|
+
getLoadMoreMode: () => this._loadMoreMode,
|
|
271
|
+
getPageSize: () => this._pageSize
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
static {
|
|
275
|
+
this.monoPendingAuto = "data";
|
|
276
|
+
}
|
|
277
|
+
_monoPendingReady() {
|
|
278
|
+
return !this.dataSource || !this._ds.loading;
|
|
279
|
+
}
|
|
280
|
+
static get observedAttributes() {
|
|
281
|
+
return [
|
|
282
|
+
...super.observedAttributes ?? [],
|
|
283
|
+
"modelvalue",
|
|
284
|
+
"helpertext",
|
|
285
|
+
"validationstate",
|
|
286
|
+
"validationmessage",
|
|
287
|
+
"errormessage",
|
|
288
|
+
"successmessage",
|
|
289
|
+
"allowcustom",
|
|
290
|
+
"maxvisible",
|
|
291
|
+
"minvisible",
|
|
292
|
+
"arialabeltext",
|
|
293
|
+
"arialabel",
|
|
294
|
+
"css-class",
|
|
295
|
+
"cssclass",
|
|
296
|
+
"chip",
|
|
297
|
+
"keyvalue",
|
|
298
|
+
"displayvalue",
|
|
299
|
+
"display-value",
|
|
300
|
+
"stayopen"
|
|
301
|
+
];
|
|
302
|
+
}
|
|
303
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
304
|
+
super.attributeChangedCallback(name, oldValue, newValue);
|
|
305
|
+
if (oldValue === newValue) return;
|
|
306
|
+
if (name === "modelvalue") {
|
|
307
|
+
this.modelValue = this._normalizeValue(newValue);
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
if (name === "helpertext") {
|
|
311
|
+
this.helperText = newValue ?? "";
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
if (name === "validationstate") {
|
|
315
|
+
this.validationState = newValue ?? "default";
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
if (name === "validationmessage") {
|
|
319
|
+
this.validationMessage = newValue ?? "";
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
if (name === "errormessage") {
|
|
323
|
+
this.errorMessage = newValue ?? "";
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
if (name === "successmessage") {
|
|
327
|
+
this.successMessage = newValue ?? "";
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
if (name === "allowcustom") {
|
|
331
|
+
this.allowCustom = this._toBoolean(newValue);
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
if (name === "maxvisible") {
|
|
335
|
+
this.maxVisible = this._toOptionalNumber(newValue);
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
if (name === "minvisible") {
|
|
339
|
+
this.minVisible = this._toOptionalNumber(newValue);
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
if (name === "arialabeltext" || name === "arialabel") {
|
|
343
|
+
this.ariaLabelText = newValue ?? void 0;
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
if (name === "keyvalue") {
|
|
347
|
+
this.keyValue = newValue ?? "";
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
if (name === "displayvalue" || name === "display-value") {
|
|
351
|
+
if (typeof this.displayValue === "function") return;
|
|
352
|
+
const next = newValue ?? "";
|
|
353
|
+
if (this._looksLikeSerializedFunction(next)) return;
|
|
354
|
+
this.displayValue = next;
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
if (name === "stayopen") {
|
|
358
|
+
this.stayOpen = this._toBoolean(newValue);
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
if (name === "css-class" || name === "cssclass") {
|
|
362
|
+
this._setCssClass(newValue);
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
if (name === "chip") this._setChip(newValue);
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* The dropdown panel is relocated into a `<body>` portal while open — query
|
|
369
|
+
* it through `panelRoot` (the portal when adopted, else the host render root).
|
|
370
|
+
*/
|
|
371
|
+
get _dropdownEl() {
|
|
372
|
+
return this._popup.panelRoot.querySelector(".mono-tag-input-dropdown");
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Where the consumer's list wrapper is parked, through the SAME portal-aware root as the panel
|
|
376
|
+
* itself — while the dropdown is open it lives in a body portal, so a host query would miss it.
|
|
377
|
+
*/
|
|
378
|
+
get _listSlotTarget() {
|
|
379
|
+
return this._popup.panelRoot.querySelector("[data-mono-slot=\"list\"]");
|
|
380
|
+
}
|
|
381
|
+
/** A late wrapper arrived. Overridden per build — one adopts it, the other rescans. */
|
|
382
|
+
_onLateListSlot() {}
|
|
383
|
+
connectedCallback() {
|
|
384
|
+
super.connectedCallback();
|
|
385
|
+
this._lateListSlot.start();
|
|
386
|
+
if (isServer) return;
|
|
387
|
+
document.addEventListener("click", this._handleDocumentClick, true);
|
|
388
|
+
document.addEventListener("focusin", this._handleDocumentFocusIn, true);
|
|
389
|
+
document.addEventListener("keydown", this._handleDocumentKeydown);
|
|
390
|
+
}
|
|
391
|
+
disconnectedCallback() {
|
|
392
|
+
if (this._searchTimer) {
|
|
393
|
+
clearTimeout(this._searchTimer);
|
|
394
|
+
this._searchTimer = void 0;
|
|
395
|
+
}
|
|
396
|
+
this._sourceSearch.clear(this.dataSource);
|
|
397
|
+
this._lateListSlot.stop();
|
|
398
|
+
this._stopWatchingListChrome();
|
|
399
|
+
if (!isServer) {
|
|
400
|
+
document.removeEventListener("click", this._handleDocumentClick, true);
|
|
401
|
+
document.removeEventListener("focusin", this._handleDocumentFocusIn, true);
|
|
402
|
+
document.removeEventListener("keydown", this._handleDocumentKeydown);
|
|
403
|
+
}
|
|
404
|
+
super.disconnectedCallback();
|
|
405
|
+
}
|
|
406
|
+
willUpdate(changed) {
|
|
407
|
+
for (const key of [
|
|
408
|
+
"disabled",
|
|
409
|
+
"readonly",
|
|
410
|
+
"required",
|
|
411
|
+
"clearable",
|
|
412
|
+
"allowCustom",
|
|
413
|
+
"checkable",
|
|
414
|
+
"immediate",
|
|
415
|
+
"group",
|
|
416
|
+
"groupSticky",
|
|
417
|
+
"searchable",
|
|
418
|
+
"stayOpen",
|
|
419
|
+
"selectAll",
|
|
420
|
+
"groupSelectAll"
|
|
421
|
+
]) {
|
|
422
|
+
const v = this[key];
|
|
423
|
+
if (typeof v !== "boolean") this[key] = this._toBoolean(v);
|
|
424
|
+
}
|
|
425
|
+
if (changed.has("modelValue") && !this._arrayEqual(this.value, this.modelValue)) this.value = [...unwrapReactiveDeep(this.modelValue)];
|
|
426
|
+
if (changed.has("value") && !this._arrayEqual(this.modelValue, this.value)) this.modelValue = [...unwrapReactiveDeep(this.value)];
|
|
427
|
+
if (this.group && (changed.has("dataSource") || changed.has("displayGroup") || changed.has("group"))) {
|
|
428
|
+
const fields = this._groupSortFields();
|
|
429
|
+
if (fields.length) this.dataSource?.sort?.(fields);
|
|
430
|
+
}
|
|
431
|
+
if (changed.has("dataSource")) {
|
|
432
|
+
this._ds.bind(this.dataSource);
|
|
433
|
+
this._sourceSearch.bind(this.dataSource);
|
|
434
|
+
}
|
|
435
|
+
if (changed.has("searchValue") || changed.has("searchOperation") || changed.has("displayValue") || changed.has("keyValue") || changed.has("dataSource") || changed.has("items")) this._searchVersion++;
|
|
436
|
+
if (changed.has("immediate")) this._ds.maybeImmediateLoad();
|
|
437
|
+
if (changed.has("loadMore")) this._ds.onLoadMoreModeChange();
|
|
438
|
+
if (changed.has("items") || changed.has("loadMore") || changed.has("pageSize")) this._ds.resetVisible();
|
|
439
|
+
}
|
|
440
|
+
updated(changed) {
|
|
441
|
+
super.updated(changed);
|
|
442
|
+
this._syncListEntries();
|
|
443
|
+
if (isServer) return;
|
|
444
|
+
this._rememberSelected(this._selectedValues);
|
|
445
|
+
if (changed.has("_open")) {
|
|
446
|
+
this._cursorPending = this._open;
|
|
447
|
+
if (!this._open) this._activeIndex = -1;
|
|
448
|
+
}
|
|
449
|
+
if (this._moreOpen && !this._overflowChips.length) this._moreOpen = false;
|
|
450
|
+
if (this._cursorPending && this._open && this._filteredItems.length) {
|
|
451
|
+
this._activeIndex = this._initialActiveIndex();
|
|
452
|
+
this._cursorPending = false;
|
|
453
|
+
}
|
|
454
|
+
if (changed.has("_activeIndex") && this._open && this._activeIndex >= 0) (this._popup.panelRoot?.querySelectorAll?.(".mono-tag-input-item")?.[this._activeIndex])?.scrollIntoView?.({ block: "nearest" });
|
|
455
|
+
this._updateScrollAutoHeight();
|
|
456
|
+
if (changed.has("chip") || changed.has("size") || changed.has("disabled") || changed.has("readonly") || this._renderedChipCount !== this._measuredChipCount) {
|
|
457
|
+
this._measuredChipCount = this._renderedChipCount;
|
|
458
|
+
this._chipStrip.invalidate();
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
_setCssClass(value) {
|
|
462
|
+
if (value == null) {
|
|
463
|
+
this.cssClass = {};
|
|
464
|
+
this.cssClassName = "";
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
if (typeof value === "object") {
|
|
468
|
+
this.cssClass = value;
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
if (typeof value === "string") {
|
|
472
|
+
const trimmed = value.trim();
|
|
473
|
+
if (!trimmed) {
|
|
474
|
+
this.cssClass = {};
|
|
475
|
+
this.cssClassName = "";
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* Optional HTML object support:
|
|
480
|
+
*
|
|
481
|
+
* <mono-tag-input css-class='{"root":"...", "field":"..."}'></mono-tag-input>
|
|
482
|
+
*/
|
|
483
|
+
if (trimmed.startsWith("{") && trimmed.endsWith("}")) try {
|
|
484
|
+
this.cssClass = JSON.parse(trimmed);
|
|
485
|
+
return;
|
|
486
|
+
} catch {}
|
|
487
|
+
this.cssClassName = trimmed;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* `chip` is an object prop, so the real binding is `:chip.prop="{…}"`. This
|
|
492
|
+
* covers the two ways a *string* can arrive: a hand-written JSON attribute
|
|
493
|
+
* (`chip='{"size":"md"}'`, incl. DSD/SSR), and Vue's `String(value)` mirror of
|
|
494
|
+
* a plain `:chip="{…}"` binding — which yields `"[object Object]"` and must be
|
|
495
|
+
* ignored, or it would wipe the property set moments later.
|
|
496
|
+
*/
|
|
497
|
+
_setChip(value) {
|
|
498
|
+
if (value == null) {
|
|
499
|
+
this.chip = {};
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
if (typeof value === "object") {
|
|
503
|
+
this.chip = value;
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
if (typeof value !== "string") return;
|
|
507
|
+
const trimmed = value.trim();
|
|
508
|
+
if (!trimmed) {
|
|
509
|
+
this.chip = {};
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) return;
|
|
513
|
+
try {
|
|
514
|
+
this.chip = JSON.parse(trimmed);
|
|
515
|
+
} catch {}
|
|
516
|
+
}
|
|
517
|
+
_toBoolean(value) {
|
|
518
|
+
if (typeof value === "boolean") return value;
|
|
519
|
+
if (typeof value === "string") {
|
|
520
|
+
const normalized = value.toLowerCase().trim();
|
|
521
|
+
return normalized === "" || normalized === "true";
|
|
522
|
+
}
|
|
523
|
+
return Boolean(value);
|
|
524
|
+
}
|
|
525
|
+
_toOptionalNumber(value) {
|
|
526
|
+
if (value === void 0 || value === null || value === "") return void 0;
|
|
527
|
+
const parsed = Number(value);
|
|
528
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
529
|
+
}
|
|
530
|
+
_normalizeValue(value) {
|
|
531
|
+
if (Array.isArray(value)) return value.filter((item) => item !== null && item !== void 0);
|
|
532
|
+
if (typeof value === "string") {
|
|
533
|
+
const trimmed = value.trim();
|
|
534
|
+
if (!trimmed) return [];
|
|
535
|
+
if (trimmed.startsWith("[") && trimmed.endsWith("]")) try {
|
|
536
|
+
return this._normalizeValue(JSON.parse(trimmed));
|
|
537
|
+
} catch {
|
|
538
|
+
return [];
|
|
539
|
+
}
|
|
540
|
+
return trimmed.split(",").map((item) => item.trim()).filter(Boolean);
|
|
541
|
+
}
|
|
542
|
+
return [];
|
|
543
|
+
}
|
|
544
|
+
_normalizeItems(items) {
|
|
545
|
+
if (Array.isArray(items)) return items.map((item) => {
|
|
546
|
+
if (typeof item === "object" && item !== null) return item;
|
|
547
|
+
return { value: item };
|
|
548
|
+
});
|
|
549
|
+
if (typeof items === "string") try {
|
|
550
|
+
const parsed = JSON.parse(items);
|
|
551
|
+
return this._normalizeItems(parsed);
|
|
552
|
+
} catch {
|
|
553
|
+
return [];
|
|
554
|
+
}
|
|
555
|
+
return [];
|
|
556
|
+
}
|
|
557
|
+
_resolveItemValue(item) {
|
|
558
|
+
if (item == null) return item;
|
|
559
|
+
if (typeof item !== "object") return item;
|
|
560
|
+
if (this.keyValue && this.keyValue in item) return item[this.keyValue];
|
|
561
|
+
if (!this.keyValue) {
|
|
562
|
+
if ("value" in item) return item.value;
|
|
563
|
+
return item;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
/** Whether `item` resolves to a value that can actually be stored (see above). */
|
|
567
|
+
_isSelectable(item) {
|
|
568
|
+
if (item == null || item.disabled) return false;
|
|
569
|
+
return this._resolveItemValue(item) !== void 0;
|
|
570
|
+
}
|
|
571
|
+
_resolveItemDisplay(item) {
|
|
572
|
+
if (item == null) return "";
|
|
573
|
+
if (typeof this.displayValue === "function") return String(this.displayValue(item));
|
|
574
|
+
if (typeof this.displayValue === "string" && this.displayValue) {
|
|
575
|
+
if (typeof item === "object" && this.displayValue in item) return String(item[this.displayValue]);
|
|
576
|
+
return "";
|
|
577
|
+
}
|
|
578
|
+
if (typeof item === "object" && "label" in item) {
|
|
579
|
+
const label = item.label;
|
|
580
|
+
return label == null ? "" : String(label);
|
|
581
|
+
}
|
|
582
|
+
if (typeof item === "object" && "value" in item) {
|
|
583
|
+
const value = item.value;
|
|
584
|
+
return value == null ? "" : String(value);
|
|
585
|
+
}
|
|
586
|
+
return String(item);
|
|
587
|
+
}
|
|
588
|
+
_looksLikeSerializedFunction(value) {
|
|
589
|
+
const trimmed = value.trim();
|
|
590
|
+
if (!trimmed) return false;
|
|
591
|
+
return /^(?:async\s+)?(?:function\b|\([^)]*\)\s*=>|[A-Za-z_$][\w$]*\s*=>)/.test(trimmed);
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Value equality. With no `key-value` the whole item IS the value, so this is
|
|
595
|
+
* identity — with one correction that is load-bearing under Vue.
|
|
596
|
+
*
|
|
597
|
+
* The model round-trips through the consumer's `ref`, which hands each tag back
|
|
598
|
+
* wrapped in a **reactive Proxy**; `items` normally stays raw, so `proxy === row`
|
|
599
|
+
* is false, an already-selected option reads as unselected, and clicking it
|
|
600
|
+
* again APPENDS a duplicate instead of toggling it off. Comparing the raw
|
|
601
|
+
* targets restores it. Still identity, not deep equality: two distinct rows with
|
|
602
|
+
* equal contents remain different values.
|
|
603
|
+
*/
|
|
604
|
+
_isSameValue(a, b) {
|
|
605
|
+
if (a === b) return true;
|
|
606
|
+
if (a == null || b == null) return false;
|
|
607
|
+
const rawA = unwrapReactive(a);
|
|
608
|
+
const rawB = unwrapReactive(b);
|
|
609
|
+
if (rawA === rawB) return true;
|
|
610
|
+
if (typeof rawA !== "object" || typeof rawB !== "object") return false;
|
|
611
|
+
return false;
|
|
612
|
+
}
|
|
613
|
+
_arrayEqual(a, b) {
|
|
614
|
+
if (a.length !== b.length) return false;
|
|
615
|
+
return a.every((item, index) => this._isSameValue(item, b[index]));
|
|
616
|
+
}
|
|
617
|
+
_cls(base, key) {
|
|
618
|
+
const extra = this.cssClass?.[key];
|
|
619
|
+
return extra ? `${base} ${extra}` : base;
|
|
620
|
+
}
|
|
621
|
+
/** Full normalized source (for resolving chip labels by value). */
|
|
622
|
+
get _normalizedItems() {
|
|
623
|
+
return this._normalizeItems(this._ds.sourceItems);
|
|
624
|
+
}
|
|
625
|
+
/** Normalized rows actually available to show (paged slice in array mode). */
|
|
626
|
+
get _visibleItems() {
|
|
627
|
+
return this._normalizeItems(this._ds.visibleItems);
|
|
628
|
+
}
|
|
629
|
+
/** Effective load-more mode (scroll is the default when enabled). */
|
|
630
|
+
get _loadMoreMode() {
|
|
631
|
+
const v = this.loadMore;
|
|
632
|
+
if (v === void 0 || v === null || v === false) return void 0;
|
|
633
|
+
return v === "button" ? "button" : "scroll";
|
|
634
|
+
}
|
|
635
|
+
/** Sanitised chunk size for array-mode paging (>= 1). */
|
|
636
|
+
get _pageSize() {
|
|
637
|
+
const n = Math.floor(Number(this.pageSize));
|
|
638
|
+
return Number.isFinite(n) && n > 0 ? n : 10;
|
|
639
|
+
}
|
|
640
|
+
get _selectedValues() {
|
|
641
|
+
return this.value ?? [];
|
|
642
|
+
}
|
|
643
|
+
get _hasValue() {
|
|
644
|
+
return this._selectedValues.length > 0;
|
|
645
|
+
}
|
|
646
|
+
get _hasLabelSlot() {
|
|
647
|
+
return this._hasLabelSlotState;
|
|
648
|
+
}
|
|
649
|
+
get _hasHelperSlot() {
|
|
650
|
+
return this._hasHelperSlotState;
|
|
651
|
+
}
|
|
652
|
+
get _resolvedValidationState() {
|
|
653
|
+
if (this.validationState && this.validationState !== "default") return this.validationState;
|
|
654
|
+
if (this.errorMessage) return "invalid";
|
|
655
|
+
if (this.successMessage) return "valid";
|
|
656
|
+
return "default";
|
|
657
|
+
}
|
|
658
|
+
_isSelected(item) {
|
|
659
|
+
const value = this._resolveItemValue(item);
|
|
660
|
+
return this._selectedValues.some((v) => this._isSameValue(v, value));
|
|
661
|
+
}
|
|
662
|
+
/** Whether `search-value` names anything explicitly (vs falling back). */
|
|
663
|
+
get _hasSearchValue() {
|
|
664
|
+
const sv = this.searchValue;
|
|
665
|
+
if (Array.isArray(sv)) return sv.length > 0;
|
|
666
|
+
return typeof sv === "string" && !!sv.trim();
|
|
667
|
+
}
|
|
668
|
+
/**
|
|
669
|
+
* The natural fields searched alongside the `'*'` default when `search-value` is
|
|
670
|
+
* empty — the safety net, not the whole list.
|
|
671
|
+
*
|
|
672
|
+
* `'*'` resolves against loaded rows, so on a bound DataSource it expands to
|
|
673
|
+
* NOTHING until the first page lands (nothing loads on open, and a query can
|
|
674
|
+
* fire inside the debounce) — these keep that first query working. They are also
|
|
675
|
+
* exempt from the remote string-only rule, so a numeric `key-value` stays
|
|
676
|
+
* searchable. `display-value` contributes only when it's a string; a function
|
|
677
|
+
* builds text that no field expression can reach, which is why `_searchMatches`
|
|
678
|
+
* keeps matching the rendered display separately.
|
|
679
|
+
*/
|
|
680
|
+
_fallbackSearchFields() {
|
|
681
|
+
return [typeof this.displayValue === "string" ? this.displayValue : void 0, this.keyValue];
|
|
682
|
+
}
|
|
683
|
+
/**
|
|
684
|
+
* A cheap signature of the rows' SHAPE, for the memo keys below.
|
|
685
|
+
*
|
|
686
|
+
* Row count alone isn't enough once `'*'` is in play: the resolved field list
|
|
687
|
+
* depends on the rows' keys, and a remote source paging from one full page to
|
|
688
|
+
* the next keeps the same length while the shape can differ. Sampling the first
|
|
689
|
+
* and last row keeps this O(1) while catching that case.
|
|
690
|
+
*/
|
|
691
|
+
_rowsShapeKey(rows) {
|
|
692
|
+
const keysOf = (row) => row && typeof row === "object" ? Object.keys(row).join(",") : typeof row;
|
|
693
|
+
if (!rows.length) return "0";
|
|
694
|
+
return `${rows.length}:${keysOf(rows[0])}|${keysOf(rows[rows.length - 1])}`;
|
|
695
|
+
}
|
|
696
|
+
/**
|
|
697
|
+
* `search-value` resolved to concrete entries — `*` patterns expanded against
|
|
698
|
+
* the loaded rows. Memoized: a pattern samples up to 20 rows, so resolving per
|
|
699
|
+
* item (this feeds `_searchMatches`) would be O(items × fields) per keystroke.
|
|
700
|
+
*
|
|
701
|
+
* With no `search-value` this defaults to `'*'` (every top-level field) plus the
|
|
702
|
+
* natural fallbacks — see {@link _fallbackSearchFields}.
|
|
703
|
+
*/
|
|
704
|
+
_searchEntries(remote) {
|
|
705
|
+
const rows = this._normalizedItems;
|
|
706
|
+
const key = `${this._searchVersion} ${remote ? 1 : 0} ${this._rowsShapeKey(rows)}`;
|
|
707
|
+
if (this._entriesCache?.key === key) return this._entriesCache.entries;
|
|
708
|
+
const entries = resolveSearchFields({
|
|
709
|
+
searchValue: this.searchValue,
|
|
710
|
+
fallbackFields: this._fallbackSearchFields(),
|
|
711
|
+
rows,
|
|
712
|
+
remote,
|
|
713
|
+
defaultToWildcard: true
|
|
714
|
+
});
|
|
715
|
+
this._entriesCache = {
|
|
716
|
+
key,
|
|
717
|
+
entries
|
|
718
|
+
};
|
|
719
|
+
return entries;
|
|
720
|
+
}
|
|
721
|
+
/** The compiled client-side predicate for the current query (memoized). */
|
|
722
|
+
_searchPredicate() {
|
|
723
|
+
const query = this._inputValue.trim();
|
|
724
|
+
const operation = this.searchOperation || "contains";
|
|
725
|
+
const rows = this._normalizedItems;
|
|
726
|
+
const key = `${this._searchVersion} ${operation} ${this._rowsShapeKey(rows)} ${query}`;
|
|
727
|
+
if (this._predicateCache?.key === key) return this._predicateCache.pred;
|
|
728
|
+
const pred = searchRowPredicate(this._searchEntries(false), query, operation);
|
|
729
|
+
this._predicateCache = {
|
|
730
|
+
key,
|
|
731
|
+
pred
|
|
732
|
+
};
|
|
733
|
+
return pred;
|
|
734
|
+
}
|
|
735
|
+
/** A bound DataSource is searched on the server; a plain array, client-side. */
|
|
736
|
+
_serverSearch() {
|
|
737
|
+
return !!this.dataSource;
|
|
738
|
+
}
|
|
739
|
+
/** Run the server search, reset to page 0. */
|
|
740
|
+
async _applySearch(query) {
|
|
741
|
+
if (!this._serverSearch()) return;
|
|
742
|
+
await this._sourceSearch.apply(this.dataSource, {
|
|
743
|
+
query,
|
|
744
|
+
searchValue: this.searchValue,
|
|
745
|
+
fallbackFields: this._fallbackSearchFields(),
|
|
746
|
+
rows: this._normalizedItems,
|
|
747
|
+
remote: true,
|
|
748
|
+
defaultToWildcard: true,
|
|
749
|
+
operation: this.searchOperation || "contains"
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
/**
|
|
753
|
+
* Clear the typed query — the visible one AND the one applied to the source.
|
|
754
|
+
*
|
|
755
|
+
* These are two independent tracks, and with a bound DataSource only the second
|
|
756
|
+
* one actually filters anything: `_searchMatches` short-circuits to `true`
|
|
757
|
+
* because the rows arrive pre-filtered. So clearing `_inputValue` on its own
|
|
758
|
+
* looks like it worked and changes nothing, which is exactly how a query that
|
|
759
|
+
* is no longer visible anywhere kept filtering the list.
|
|
760
|
+
*
|
|
761
|
+
* Cancelling the debounce FIRST is load-bearing: a timer armed before the reset
|
|
762
|
+
* fires afterwards and re-applies the stale query.
|
|
763
|
+
*/
|
|
764
|
+
_resetSearch() {
|
|
765
|
+
if (this._searchTimer) {
|
|
766
|
+
clearTimeout(this._searchTimer);
|
|
767
|
+
this._searchTimer = void 0;
|
|
768
|
+
}
|
|
769
|
+
const had = !!this._inputValue;
|
|
770
|
+
this._inputValue = "";
|
|
771
|
+
this._activeIndex = -1;
|
|
772
|
+
if (had && this._serverSearch()) this._applySearch("");
|
|
773
|
+
}
|
|
774
|
+
/**
|
|
775
|
+
* The single way the panel closes. Every exit resets the search, so reopening
|
|
776
|
+
* never shows a list filtered by a query the box no longer holds.
|
|
777
|
+
*/
|
|
778
|
+
_close() {
|
|
779
|
+
this._open = false;
|
|
780
|
+
this._resetSearch();
|
|
781
|
+
}
|
|
782
|
+
/** Debounce a server search for the current input text. */
|
|
783
|
+
_scheduleSearch() {
|
|
784
|
+
if (!this.searchable || !this._serverSearch()) return;
|
|
785
|
+
if (this._searchTimer) clearTimeout(this._searchTimer);
|
|
786
|
+
const wait = Math.max(0, Number(this.searchDebounce) || 0);
|
|
787
|
+
this._searchTimer = setTimeout(() => void this._applySearch(this._inputValue), wait);
|
|
788
|
+
}
|
|
789
|
+
/** Whether an option matches the current typed query. */
|
|
790
|
+
_searchMatches(item) {
|
|
791
|
+
if (!this.searchable) return true;
|
|
792
|
+
if (this._serverSearch()) return true;
|
|
793
|
+
const query = this._inputValue.trim().toLowerCase();
|
|
794
|
+
if (!query) return true;
|
|
795
|
+
if (this._hasSearchValue) {
|
|
796
|
+
const pred = this._searchPredicate();
|
|
797
|
+
return pred ? pred(item) : true;
|
|
798
|
+
}
|
|
799
|
+
const itemValue = this._resolveItemValue(item);
|
|
800
|
+
const display = this._resolveItemDisplay(item).toLowerCase();
|
|
801
|
+
const valueStr = itemValue == null ? "" : String(itemValue).toLowerCase();
|
|
802
|
+
const desc = typeof item === "object" && item && typeof item.description === "string" ? item.description.toLowerCase() : "";
|
|
803
|
+
const pred = this._searchPredicate();
|
|
804
|
+
return display.includes(query) || valueStr.includes(query) || desc.includes(query) || (pred ? pred(item) : false);
|
|
805
|
+
}
|
|
806
|
+
/**
|
|
807
|
+
* Grouping is active when `display-group` names at least one level — OR when the
|
|
808
|
+
* source already loaded PRE-GROUPED `{ key, items }` nodes.
|
|
809
|
+
*
|
|
810
|
+
* The second half is what makes "feed pre-grouped data directly" actually work.
|
|
811
|
+
* Without it, a devextreme DataSource carrying `group:` loaded its group nodes and,
|
|
812
|
+
* because `displayGroup` was empty, they were treated as ordinary OPTIONS: the
|
|
813
|
+
* headers became rows, `keyValue` was absent on them so they resolved to
|
|
814
|
+
* `undefined`, and selecting one wrote `undefined` into the value.
|
|
815
|
+
*
|
|
816
|
+
* `group` mode is excluded: there the source is deliberately FLAT and
|
|
817
|
+
* `display-group` is what buckets it client-side.
|
|
818
|
+
*/
|
|
819
|
+
get _grouped() {
|
|
820
|
+
if (Array.isArray(this.displayGroup) && this.displayGroup.length > 0) return true;
|
|
821
|
+
if (this.group) return false;
|
|
822
|
+
const src = this._ds.sourceItems ?? [];
|
|
823
|
+
return src.length > 0 && src.some((n) => this._isGroupNode(n));
|
|
824
|
+
}
|
|
825
|
+
/** A node is a group when its `groupItems` field holds an array. */
|
|
826
|
+
_isGroupNode(x) {
|
|
827
|
+
return !!x && typeof x === "object" && Array.isArray(x[this.groupItems]);
|
|
828
|
+
}
|
|
829
|
+
/** Descend `groupItems[0]` to the first leaf row — the group's representative. */
|
|
830
|
+
_firstLeaf(node) {
|
|
831
|
+
let cur = node;
|
|
832
|
+
let guard = 0;
|
|
833
|
+
while (this._isGroupNode(cur) && guard++ < 50) cur = cur[this.groupItems]?.[0];
|
|
834
|
+
return cur ?? void 0;
|
|
835
|
+
}
|
|
836
|
+
/** Resolve a group header's label from `displayGroup[level]` over a leaf row. */
|
|
837
|
+
_resolveGroupLabel(node, level) {
|
|
838
|
+
const accessor = this.displayGroup[level];
|
|
839
|
+
const leaf = this._firstLeaf(node);
|
|
840
|
+
if (typeof accessor === "function") return String(accessor(leaf ?? {}) ?? "");
|
|
841
|
+
if (typeof accessor === "string" && leaf && accessor in leaf) return String(leaf[accessor] ?? "");
|
|
842
|
+
const key = node[this.groupKey];
|
|
843
|
+
return key == null ? "" : String(key);
|
|
844
|
+
}
|
|
845
|
+
/** The string `display-group` entries — usable as server group/sort fields. */
|
|
846
|
+
_groupSortFields() {
|
|
847
|
+
return (this.displayGroup ?? []).filter((a) => typeof a === "string");
|
|
848
|
+
}
|
|
849
|
+
/** A `display-group` level's key for a row (string → field, function → call). */
|
|
850
|
+
_groupKeyOf(row, level) {
|
|
851
|
+
const accessor = this.displayGroup[level];
|
|
852
|
+
if (typeof accessor === "function") return accessor(row);
|
|
853
|
+
if (typeof accessor === "string") return row[accessor];
|
|
854
|
+
}
|
|
855
|
+
/** `group` mode: bucket flat rows into `{ [groupKey], [groupItems] }` by level. */
|
|
856
|
+
_buildClientTree(rows) {
|
|
857
|
+
const build = (items, level) => {
|
|
858
|
+
if (level >= this.displayGroup.length) return items;
|
|
859
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
860
|
+
for (const row of items) {
|
|
861
|
+
const key = this._groupKeyOf(row, level);
|
|
862
|
+
const ks = String(key);
|
|
863
|
+
let bucket = buckets.get(ks);
|
|
864
|
+
if (!bucket) buckets.set(ks, bucket = {
|
|
865
|
+
key,
|
|
866
|
+
rows: []
|
|
867
|
+
});
|
|
868
|
+
bucket.rows.push(row);
|
|
869
|
+
}
|
|
870
|
+
return [...buckets.values()].map((b) => ({
|
|
871
|
+
[this.groupKey]: b.key,
|
|
872
|
+
[this.groupItems]: build(b.rows, level + 1)
|
|
873
|
+
}));
|
|
874
|
+
};
|
|
875
|
+
return build(rows, 0);
|
|
876
|
+
}
|
|
877
|
+
/** Every leaf row (all loaded) — for chip-label / value lookup. */
|
|
878
|
+
get _leafItems() {
|
|
879
|
+
if (!this._grouped) return this._normalizedItems;
|
|
880
|
+
if (this.group) return this._normalizeItems(this._ds.sourceItems);
|
|
881
|
+
const out = [];
|
|
882
|
+
const walk = (nodes) => {
|
|
883
|
+
for (const n of nodes) if (this._isGroupNode(n)) walk(n[this.groupItems]);
|
|
884
|
+
else if (n != null) out.push(n);
|
|
885
|
+
};
|
|
886
|
+
walk(this._ds.sourceItems ?? []);
|
|
887
|
+
return out;
|
|
888
|
+
}
|
|
889
|
+
/** The nested group nodes to render — built client-side in `group` mode. */
|
|
890
|
+
_groupNodes() {
|
|
891
|
+
if (this.group) {
|
|
892
|
+
const leaves = this._visibleItems.filter((it) => this._searchMatches(it));
|
|
893
|
+
return this._buildClientTree(leaves);
|
|
894
|
+
}
|
|
895
|
+
return this._ds.visibleItems ?? [];
|
|
896
|
+
}
|
|
897
|
+
/**
|
|
898
|
+
* Flatten the visible group tree into ordered render rows (headers + items).
|
|
899
|
+
* `index` is the item's position among rendered leaves (drives `_activeIndex`
|
|
900
|
+
* and keyboard nav). Leaves are search-filtered; empty groups are dropped.
|
|
901
|
+
*/
|
|
902
|
+
_groupRows() {
|
|
903
|
+
const filterLeaves = !this.group;
|
|
904
|
+
const build = (nodes, level, parentKey) => {
|
|
905
|
+
const rows = [];
|
|
906
|
+
nodes.forEach((node, i) => {
|
|
907
|
+
if (!this._isGroupNode(node)) {
|
|
908
|
+
const item = node;
|
|
909
|
+
if (item == null) return;
|
|
910
|
+
if (filterLeaves && !this._searchMatches(item)) return;
|
|
911
|
+
rows.push({
|
|
912
|
+
kind: "item",
|
|
913
|
+
item,
|
|
914
|
+
index: -1,
|
|
915
|
+
level
|
|
916
|
+
});
|
|
917
|
+
return;
|
|
918
|
+
}
|
|
919
|
+
const rec = node;
|
|
920
|
+
const path = `${parentKey}/${String(rec[this.groupKey])}#${i}`;
|
|
921
|
+
const children = build(rec[this.groupItems] ?? [], level + 1, path);
|
|
922
|
+
if (!children.length) return;
|
|
923
|
+
rows.push({
|
|
924
|
+
kind: "group",
|
|
925
|
+
level,
|
|
926
|
+
label: this._resolveGroupLabel(rec, level),
|
|
927
|
+
key: `g:${level}:${path}`,
|
|
928
|
+
items: children.filter((r) => r.kind === "item").map((r) => r.item)
|
|
929
|
+
});
|
|
930
|
+
rows.push(...children);
|
|
931
|
+
});
|
|
932
|
+
return rows;
|
|
933
|
+
};
|
|
934
|
+
let idx = 0;
|
|
935
|
+
return build(this._groupNodes(), 0, "").map((r) => r.kind === "item" ? {
|
|
936
|
+
...r,
|
|
937
|
+
index: idx++
|
|
938
|
+
} : r);
|
|
939
|
+
}
|
|
940
|
+
/**
|
|
941
|
+
* Where the keyboard cursor goes when the list opens: the row holding the most
|
|
942
|
+
* recently picked tag, else the first row.
|
|
943
|
+
*
|
|
944
|
+
* "Most recent" is the TAIL of the value array — every add appends and nothing
|
|
945
|
+
* sorts, so removing and re-adding a tag correctly moves it to the end. The
|
|
946
|
+
* `Backspace` handler already leans on that same invariant.
|
|
947
|
+
*
|
|
948
|
+
* Selected rows stay in the suggestion list (see `_renderOption`), so this can
|
|
949
|
+
* actually find them; the predicate is the one that paints `.selected`, so the
|
|
950
|
+
* cursor lands on the row drawn as selected. `0` when the tag is not in the
|
|
951
|
+
* loaded page — the behaviour this component has always had.
|
|
952
|
+
*/
|
|
953
|
+
_initialActiveIndex() {
|
|
954
|
+
const items = this._filteredItems;
|
|
955
|
+
if (!items.length) return -1;
|
|
956
|
+
const values = this._selectedValues;
|
|
957
|
+
const last = values.length ? values[values.length - 1] : void 0;
|
|
958
|
+
if (last === void 0) return 0;
|
|
959
|
+
const index = items.findIndex((item) => this._isSameValue(this._resolveItemValue(item), last));
|
|
960
|
+
return index >= 0 ? index : 0;
|
|
961
|
+
}
|
|
962
|
+
get _filteredItems() {
|
|
963
|
+
if (this._grouped) return this._groupRows().filter((r) => r.kind === "item").map((r) => r.item);
|
|
964
|
+
return this._visibleItems.filter((item) => this._searchMatches(item));
|
|
965
|
+
}
|
|
966
|
+
/**
|
|
967
|
+
* The selection limits in force: `chip.max` / `chip.min` pin, the element's
|
|
968
|
+
* `max` / `min` are the fallback (the rule `chip.color` follows). Undefined =
|
|
969
|
+
* unlimited / no floor.
|
|
970
|
+
*/
|
|
971
|
+
get _selectionLimits() {
|
|
972
|
+
const chip = this._chipProps;
|
|
973
|
+
return {
|
|
974
|
+
max: resolveChipLimit(chip, "max", this.max),
|
|
975
|
+
min: resolveChipLimit(chip, "min", this.min)
|
|
976
|
+
};
|
|
977
|
+
}
|
|
978
|
+
/** Room left under `max`, or Infinity without one. */
|
|
979
|
+
get _room() {
|
|
980
|
+
const max = this._selectionLimits.max;
|
|
981
|
+
return max === void 0 ? Infinity : Math.max(0, max - this._selectedValues.length);
|
|
982
|
+
}
|
|
983
|
+
get _canAddMore() {
|
|
984
|
+
return this._room > 0;
|
|
985
|
+
}
|
|
986
|
+
/** The selection sits above its floor, so one more removal is allowed. */
|
|
987
|
+
get _canRemoveMore() {
|
|
988
|
+
const min = this._selectionLimits.min;
|
|
989
|
+
return min === void 0 || this._selectedValues.length > min;
|
|
990
|
+
}
|
|
991
|
+
/**
|
|
992
|
+
* A bulk deselect keeps the FIRST `min` values (selection order) — "remove
|
|
993
|
+
* these" then means "down to the floor", the most a user gesture may do.
|
|
994
|
+
*/
|
|
995
|
+
_keepFloor(next) {
|
|
996
|
+
const min = this._selectionLimits.min ?? 0;
|
|
997
|
+
if (next.length >= min) return next;
|
|
998
|
+
const kept = [...next];
|
|
999
|
+
for (const v of this._selectedValues) {
|
|
1000
|
+
if (kept.length >= min) break;
|
|
1001
|
+
if (!kept.some((k) => this._isSameValue(k, v))) kept.push(v);
|
|
1002
|
+
}
|
|
1003
|
+
return this._selectedValues.filter((v) => kept.some((k) => this._isSameValue(k, v)));
|
|
1004
|
+
}
|
|
1005
|
+
get _wrapperClasses() {
|
|
1006
|
+
return [
|
|
1007
|
+
"mono-tag-input",
|
|
1008
|
+
this.size,
|
|
1009
|
+
this.color,
|
|
1010
|
+
this.variant,
|
|
1011
|
+
this._open ? "open" : "",
|
|
1012
|
+
this._moreOpen ? "more-open" : "",
|
|
1013
|
+
this.disabled ? "disabled" : "",
|
|
1014
|
+
this.readonly ? "readonly" : "",
|
|
1015
|
+
this._resolvedValidationState !== "default" ? `is-${this._resolvedValidationState}` : "",
|
|
1016
|
+
this._hasValue ? "has-value" : "",
|
|
1017
|
+
this.checkable ? "checkable" : "",
|
|
1018
|
+
this.cssClassName,
|
|
1019
|
+
this.cssClass?.root
|
|
1020
|
+
].filter(Boolean).join(" ");
|
|
1021
|
+
}
|
|
1022
|
+
/**
|
|
1023
|
+
* Whether the clear button renders. A getter because BOTH the field class list
|
|
1024
|
+
* and `render()` need it: the button is pinned to the top-right corner, and the
|
|
1025
|
+
* gutter that keeps wrapped chips from running under it is reserved by
|
|
1026
|
+
* `.has-clear` on the field.
|
|
1027
|
+
*/
|
|
1028
|
+
get _showClear() {
|
|
1029
|
+
return this.clearable && this._hasValue && !this.disabled && !this.readonly && !((this._selectionLimits.min ?? 0) > 0);
|
|
1030
|
+
}
|
|
1031
|
+
get _fieldClasses() {
|
|
1032
|
+
return [
|
|
1033
|
+
this._cls("mono-tag-input-field", "field"),
|
|
1034
|
+
this.size,
|
|
1035
|
+
this.color,
|
|
1036
|
+
this.variant,
|
|
1037
|
+
this.disabled ? "disabled" : "",
|
|
1038
|
+
this.readonly ? "readonly" : "",
|
|
1039
|
+
this._showClear ? "has-clear" : "",
|
|
1040
|
+
"has-actions",
|
|
1041
|
+
this._chipBehaviour === "inline" ? "is-inline" : "",
|
|
1042
|
+
this._inputValue ? "is-typing" : ""
|
|
1043
|
+
].filter(Boolean).join(" ");
|
|
1044
|
+
}
|
|
1045
|
+
_cacheKey(value) {
|
|
1046
|
+
if (value == null || typeof value === "object") return void 0;
|
|
1047
|
+
return String(value);
|
|
1048
|
+
}
|
|
1049
|
+
/**
|
|
1050
|
+
* Remember the rows behind `values` while they are still loaded.
|
|
1051
|
+
*
|
|
1052
|
+
* Called from `_setValue`, i.e. at the moment of selection — the row is in the
|
|
1053
|
+
* list by definition right then, which is why this needs no request. Values
|
|
1054
|
+
* that cannot be resolved yet are skipped, not cached as misses, so a later
|
|
1055
|
+
* load can still fill them in.
|
|
1056
|
+
*/
|
|
1057
|
+
_rememberSelected(values) {
|
|
1058
|
+
if (!this.keyValue) return;
|
|
1059
|
+
for (const value of values) {
|
|
1060
|
+
const key = this._cacheKey(value);
|
|
1061
|
+
if (key === void 0 || this._selectedItemCache.has(key)) continue;
|
|
1062
|
+
const item = this._findLoadedItem(value);
|
|
1063
|
+
if (item !== void 0) this._selectedItemCache.set(key, item);
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
/** Look a value up in the currently loaded rows only. */
|
|
1067
|
+
_findLoadedItem(value) {
|
|
1068
|
+
return this._leafItems.find((item) => this._isSameValue(this._resolveItemValue(item), value));
|
|
1069
|
+
}
|
|
1070
|
+
_getItemByValue(value) {
|
|
1071
|
+
const loaded = this._findLoadedItem(value);
|
|
1072
|
+
if (loaded !== void 0) {
|
|
1073
|
+
const key = this._cacheKey(value);
|
|
1074
|
+
if (key !== void 0 && this.keyValue) this._selectedItemCache.set(key, loaded);
|
|
1075
|
+
return loaded;
|
|
1076
|
+
}
|
|
1077
|
+
const key = this._cacheKey(value);
|
|
1078
|
+
return key === void 0 ? void 0 : this._selectedItemCache.get(key);
|
|
1079
|
+
}
|
|
1080
|
+
/**
|
|
1081
|
+
* Whether this value still has no row behind it — the list has not loaded it (or
|
|
1082
|
+
* not loaded yet).
|
|
1083
|
+
*
|
|
1084
|
+
* Only meaningful when `keyValue` is set: that prop is the statement "values are
|
|
1085
|
+
* KEYS into the items", so an unmatched key has no label anyone would want to
|
|
1086
|
+
* read — showing the bare key renders a chip like `1` or `1|MKT`. Without
|
|
1087
|
+
* `keyValue` the value IS its own label (and `allow-custom` tags rely on that),
|
|
1088
|
+
* so nothing is ever hidden there.
|
|
1089
|
+
*/
|
|
1090
|
+
_isUnresolvedKey(value) {
|
|
1091
|
+
if (!this.keyValue) return false;
|
|
1092
|
+
if (value == null) return false;
|
|
1093
|
+
if (typeof value === "object") return false;
|
|
1094
|
+
return this._getItemByValue(value) === void 0;
|
|
1095
|
+
}
|
|
1096
|
+
_getLabelByValue(value) {
|
|
1097
|
+
const item = this._getItemByValue(value);
|
|
1098
|
+
if (item) return this._resolveItemDisplay(item);
|
|
1099
|
+
if (value == null) return "";
|
|
1100
|
+
if (typeof value === "object") return this._resolveItemDisplay(value);
|
|
1101
|
+
if (this._isUnresolvedKey(value)) return "";
|
|
1102
|
+
return String(value);
|
|
1103
|
+
}
|
|
1104
|
+
_createModelDetail(args) {
|
|
1105
|
+
return {
|
|
1106
|
+
modelValue: args.modelValue,
|
|
1107
|
+
currentValue: args.modelValue,
|
|
1108
|
+
oldValue: args.oldValue,
|
|
1109
|
+
value: args.modelValue,
|
|
1110
|
+
addedValue: args.addedValue,
|
|
1111
|
+
removedValue: args.removedValue,
|
|
1112
|
+
selectedItem: args.addedValue !== void 0 ? this._getItemByValue(args.addedValue) : void 0,
|
|
1113
|
+
sourceEvent: args.sourceEvent
|
|
1114
|
+
};
|
|
1115
|
+
}
|
|
1116
|
+
_emitChange(detail) {
|
|
1117
|
+
dispatchMonoEvent(this, "change", detail);
|
|
1118
|
+
}
|
|
1119
|
+
_emitAdd(detail) {
|
|
1120
|
+
dispatchMonoEvent(this, "add", detail);
|
|
1121
|
+
}
|
|
1122
|
+
_emitRemove(detail) {
|
|
1123
|
+
dispatchMonoEvent(this, "remove", detail);
|
|
1124
|
+
}
|
|
1125
|
+
_emitClear(detail) {
|
|
1126
|
+
dispatchMonoEvent(this, "clear", detail);
|
|
1127
|
+
}
|
|
1128
|
+
_setValue(nextValue, args = {}) {
|
|
1129
|
+
const oldValue = [...this._selectedValues];
|
|
1130
|
+
const normalized = [...nextValue];
|
|
1131
|
+
this._rememberSelected(normalized);
|
|
1132
|
+
this.value = normalized;
|
|
1133
|
+
this.modelValue = normalized;
|
|
1134
|
+
const detail = this._createModelDetail({
|
|
1135
|
+
modelValue: normalized,
|
|
1136
|
+
oldValue,
|
|
1137
|
+
addedValue: args.addedValue,
|
|
1138
|
+
removedValue: args.removedValue,
|
|
1139
|
+
sourceEvent: args.sourceEvent
|
|
1140
|
+
});
|
|
1141
|
+
this._emitChange(detail);
|
|
1142
|
+
if (args.emitAdd) this._emitAdd(detail);
|
|
1143
|
+
if (args.emitRemove) this._emitRemove(detail);
|
|
1144
|
+
if (args.emitClear) this._emitClear(detail);
|
|
1145
|
+
if (args.emitAdd && this._chipBehaviour === "inline") this.updateComplete.then(() => this._chipStrip.scrollToEnd());
|
|
1146
|
+
}
|
|
1147
|
+
_addValue(value, event) {
|
|
1148
|
+
if (this.disabled || this.readonly) return;
|
|
1149
|
+
if (!this._canAddMore) return this._resetSearch();
|
|
1150
|
+
if (!this.allowCustom && !this._getItemByValue(value)) return;
|
|
1151
|
+
if (!this._selectedValues.some((v) => this._isSameValue(v, value))) this._setValue([...this._selectedValues, value], {
|
|
1152
|
+
addedValue: value,
|
|
1153
|
+
sourceEvent: event,
|
|
1154
|
+
emitAdd: true
|
|
1155
|
+
});
|
|
1156
|
+
this._close();
|
|
1157
|
+
this._inputEl?.focus();
|
|
1158
|
+
}
|
|
1159
|
+
/**
|
|
1160
|
+
* Checkbox-mode toggle: add or remove a value while keeping the dropdown open
|
|
1161
|
+
* (and the typed filter intact), so the user can check several rows in a row.
|
|
1162
|
+
*/
|
|
1163
|
+
_toggleValue(value, event) {
|
|
1164
|
+
if (this.disabled || this.readonly) return;
|
|
1165
|
+
if (this._selectedValues.some((v) => this._isSameValue(v, value))) {
|
|
1166
|
+
if (!this._canRemoveMore) return;
|
|
1167
|
+
this._setValue(this._selectedValues.filter((v) => !this._isSameValue(v, value)), {
|
|
1168
|
+
removedValue: value,
|
|
1169
|
+
sourceEvent: event,
|
|
1170
|
+
emitRemove: true
|
|
1171
|
+
});
|
|
1172
|
+
} else {
|
|
1173
|
+
if (!this._canAddMore) return this._resetSearch();
|
|
1174
|
+
this._setValue([...this._selectedValues, value], {
|
|
1175
|
+
addedValue: value,
|
|
1176
|
+
sourceEvent: event,
|
|
1177
|
+
emitAdd: true
|
|
1178
|
+
});
|
|
1179
|
+
}
|
|
1180
|
+
if (!this.checkable) {
|
|
1181
|
+
this._close();
|
|
1182
|
+
this._inputEl?.focus();
|
|
1183
|
+
return;
|
|
1184
|
+
}
|
|
1185
|
+
this._open = true;
|
|
1186
|
+
this._inputEl?.focus();
|
|
1187
|
+
}
|
|
1188
|
+
/**
|
|
1189
|
+
* How much of `items` is selected — what paints a select-all box unchecked,
|
|
1190
|
+
* indeterminate or checked. Disabled options are ignored, so a group whose only
|
|
1191
|
+
* unselected row is disabled still reads as fully selected.
|
|
1192
|
+
*/
|
|
1193
|
+
_selectionStateOf(items) {
|
|
1194
|
+
const usable = items.filter((item) => this._isSelectable(item));
|
|
1195
|
+
if (!usable.length) return "none";
|
|
1196
|
+
let hit = 0;
|
|
1197
|
+
for (const item of usable) if (this._isSelected(item)) hit += 1;
|
|
1198
|
+
if (hit === 0) return "none";
|
|
1199
|
+
return hit === usable.length ? "all" : "some";
|
|
1200
|
+
}
|
|
1201
|
+
/**
|
|
1202
|
+
* Whether the "All" row reaches the SERVER rather than the loaded rows.
|
|
1203
|
+
*
|
|
1204
|
+
* Gated on a bound `DataSource` + `load-more`, which together mean "the list is
|
|
1205
|
+
* a window onto something bigger". A plain `items` array is static and already
|
|
1206
|
+
* wholly in memory, so it keeps the loaded-only behaviour.
|
|
1207
|
+
*/
|
|
1208
|
+
get _serverSelectAll() {
|
|
1209
|
+
return !!this.dataSource && !!this._loadMoreMode;
|
|
1210
|
+
}
|
|
1211
|
+
/** The source's own page size, when it pages; `0` otherwise. */
|
|
1212
|
+
_sourcePageSize() {
|
|
1213
|
+
const ds = this.dataSource;
|
|
1214
|
+
if (!ds || typeof ds.pageSize !== "function") return 0;
|
|
1215
|
+
if (typeof ds.paginate === "function" && !ds.paginate()) return 0;
|
|
1216
|
+
const n = Number(ds.pageSize());
|
|
1217
|
+
return Number.isFinite(n) && n > 0 ? n : 0;
|
|
1218
|
+
}
|
|
1219
|
+
/** The source's row count, when it knows one. */
|
|
1220
|
+
_serverTotal() {
|
|
1221
|
+
const n = Number(this.dataSource?.totalCount?.());
|
|
1222
|
+
return Number.isFinite(n) && n >= 0 ? n : void 0;
|
|
1223
|
+
}
|
|
1224
|
+
/**
|
|
1225
|
+
* The "All" box, judged against the SERVER total rather than the loaded rows.
|
|
1226
|
+
*
|
|
1227
|
+
* Without this the box reads `'all'` the moment the loaded page is selected —
|
|
1228
|
+
* and the next click would CLEAR, so the drain could never be reached. Every
|
|
1229
|
+
* state below `all` therefore has to mean "clicking me selects more".
|
|
1230
|
+
*
|
|
1231
|
+
* BOTH halves of the `'all'` test matter, and each rules out a way of being
|
|
1232
|
+
* wrong. `_selectionStateOf` alone says `'all'` after one page of 250. The count
|
|
1233
|
+
* alone says `'all'` whenever the selection is merely LARGER than the total,
|
|
1234
|
+
* which a search makes routine: hold 111 rows, narrow the query to 11, and a
|
|
1235
|
+
* bare `111 >= 11` paints a finished box over eleven rows none of which are
|
|
1236
|
+
* selected — and the next click would clear instead of selecting them.
|
|
1237
|
+
*
|
|
1238
|
+
* Falls back to the loaded-scope reading when the source cannot say how many
|
|
1239
|
+
* rows it has, which is the honest answer: nothing here can tell whether the
|
|
1240
|
+
* selection is complete.
|
|
1241
|
+
*/
|
|
1242
|
+
_selectAllState(usable) {
|
|
1243
|
+
const loaded = this._selectionStateOf(usable);
|
|
1244
|
+
if (!this._serverSelectAll) return loaded;
|
|
1245
|
+
const total = this._serverTotal();
|
|
1246
|
+
if (total === void 0) return loaded;
|
|
1247
|
+
if (loaded === "all" && total > 0 && this._selectedValues.length >= total) return "all";
|
|
1248
|
+
return this._selectedValues.length > 0 ? "some" : "none";
|
|
1249
|
+
}
|
|
1250
|
+
/**
|
|
1251
|
+
* Select every row the source returns for the CURRENT search — the tag-input's
|
|
1252
|
+
* counterpart to `<mono-table-checkbox type="all">`.
|
|
1253
|
+
*
|
|
1254
|
+
* `readAllRows` walks the store in chunks and rebuilds the source's live filter
|
|
1255
|
+
* plus its folded search (`searchFilterOf`), so this means "everything the user
|
|
1256
|
+
* is currently looking at", not the whole table. Deliberately NOT routed through
|
|
1257
|
+
* `_ds`: its `_onChanged` resets the accumulated pages whenever a `changed`
|
|
1258
|
+
* fires outside its own load, and `readAllRows` talks to the store directly.
|
|
1259
|
+
*/
|
|
1260
|
+
async _selectAllFromServer(event) {
|
|
1261
|
+
if (this._selectAllPending) return;
|
|
1262
|
+
if (this._searchTimer) {
|
|
1263
|
+
clearTimeout(this._searchTimer);
|
|
1264
|
+
this._searchTimer = void 0;
|
|
1265
|
+
await this._applySearch(this._inputValue);
|
|
1266
|
+
}
|
|
1267
|
+
this._selectAllPending = true;
|
|
1268
|
+
try {
|
|
1269
|
+
const rows = await readAllRows(this.dataSource, { chunkSize: Math.max(1, this._pageSize, this._sourcePageSize()) });
|
|
1270
|
+
const usable = this._normalizeItems(rows).filter((item) => this._isSelectable(item));
|
|
1271
|
+
const values = usable.map((item) => this._resolveItemValue(item));
|
|
1272
|
+
const seen = new Set(this._selectedValues.map((v) => this._cacheKey(v)).filter((k) => k !== void 0));
|
|
1273
|
+
const additions = [];
|
|
1274
|
+
for (let i = 0; i < values.length; i++) {
|
|
1275
|
+
const key = this._cacheKey(values[i]);
|
|
1276
|
+
if (key !== void 0 && seen.has(key)) continue;
|
|
1277
|
+
if (key !== void 0) seen.add(key);
|
|
1278
|
+
additions.push(values[i]);
|
|
1279
|
+
if (key !== void 0 && this.keyValue) this._selectedItemCache.set(key, usable[i]);
|
|
1280
|
+
}
|
|
1281
|
+
if (!additions.length) return;
|
|
1282
|
+
const room = this._room;
|
|
1283
|
+
if (!room) return;
|
|
1284
|
+
this._setValue([...this._selectedValues, ...additions.slice(0, room)], {
|
|
1285
|
+
sourceEvent: event,
|
|
1286
|
+
emitAdd: true
|
|
1287
|
+
});
|
|
1288
|
+
} finally {
|
|
1289
|
+
this._selectAllPending = false;
|
|
1290
|
+
this._open = true;
|
|
1291
|
+
this._inputEl?.focus();
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
/**
|
|
1295
|
+
* Where the "All" row's click goes.
|
|
1296
|
+
*
|
|
1297
|
+
* Only a state BELOW `all` drains; once `_selectAllState` says everything on the
|
|
1298
|
+
* server is held, the row goes back to being a clear button. `_toggleMany` still
|
|
1299
|
+
* owns both directions for a plain `items` array.
|
|
1300
|
+
*
|
|
1301
|
+
* A drain is for the rows NOT yet here. Once the controller has walked the source
|
|
1302
|
+
* to its last page — `load-more` scrolled to the end, or a source whose whole
|
|
1303
|
+
* result fit its first page — every row the query matches is already in
|
|
1304
|
+
* memory, and `items` (the visible, server-filtered set) IS the answer: select
|
|
1305
|
+
* it as a plain array would, with no request. A query still inside its debounce
|
|
1306
|
+
* disqualifies that shortcut, because the loaded rows belong to the PREVIOUS
|
|
1307
|
+
* search; the drain path flushes it first.
|
|
1308
|
+
*/
|
|
1309
|
+
_onSelectAllClick(items, state, event) {
|
|
1310
|
+
if (this._selectAllPending) return;
|
|
1311
|
+
if (!this._serverSelectAll) {
|
|
1312
|
+
this._toggleMany(items, event);
|
|
1313
|
+
return;
|
|
1314
|
+
}
|
|
1315
|
+
if (state !== "all") {
|
|
1316
|
+
if (this._ds.atLastPage && !this._searchTimer) {
|
|
1317
|
+
this._toggleMany(items, event);
|
|
1318
|
+
return;
|
|
1319
|
+
}
|
|
1320
|
+
this._selectAllFromServer(event);
|
|
1321
|
+
return;
|
|
1322
|
+
}
|
|
1323
|
+
this._clearAllFromServer(event);
|
|
1324
|
+
}
|
|
1325
|
+
/**
|
|
1326
|
+
* Untick "All" after a drain.
|
|
1327
|
+
*
|
|
1328
|
+
* NOT `_toggleMany`: that only removes the values present in `items`, which on a
|
|
1329
|
+
* paged source is one page — so clearing 1,085 drained rows would drop ten of
|
|
1330
|
+
* them and leave the box reading `'some'`. `'all'` here means the selection is
|
|
1331
|
+
* the drain, so the inverse is emptying it, the same reading
|
|
1332
|
+
* `<mono-table-checkbox>` gives its own clear.
|
|
1333
|
+
*/
|
|
1334
|
+
_clearAllFromServer(event) {
|
|
1335
|
+
if (this.disabled || this.readonly) return;
|
|
1336
|
+
if (!this._selectedValues.length) return;
|
|
1337
|
+
this._setValue([], {
|
|
1338
|
+
sourceEvent: event,
|
|
1339
|
+
emitRemove: true
|
|
1340
|
+
});
|
|
1341
|
+
this._open = true;
|
|
1342
|
+
this._inputEl?.focus();
|
|
1343
|
+
}
|
|
1344
|
+
/**
|
|
1345
|
+
* Select every one of `items`, or clear them all if they are already selected —
|
|
1346
|
+
* the "All" row and every group header run through here.
|
|
1347
|
+
*
|
|
1348
|
+
* ONE `_setValue` call, so a bulk toggle is a single `mno-change` carrying the
|
|
1349
|
+
* whole next array rather than N events a consumer would have to coalesce.
|
|
1350
|
+
* `addedValue` / `removedValue` are deliberately left undefined for the same
|
|
1351
|
+
* reason: there is no single value to name, and guessing one would be worse than
|
|
1352
|
+
* saying nothing (`modelValue` and `oldValue` carry the full before/after).
|
|
1353
|
+
*/
|
|
1354
|
+
_toggleMany(items, event) {
|
|
1355
|
+
if (this.disabled || this.readonly) return;
|
|
1356
|
+
const usable = items.filter((item) => this._isSelectable(item));
|
|
1357
|
+
if (!usable.length) return;
|
|
1358
|
+
const values = usable.map((item) => this._resolveItemValue(item));
|
|
1359
|
+
const current = this._selectedValues;
|
|
1360
|
+
const isOn = (v) => current.some((c) => this._isSameValue(c, v));
|
|
1361
|
+
if (values.every(isOn)) this._setValue(this._keepFloor(current.filter((c) => !values.some((v) => this._isSameValue(c, v)))), {
|
|
1362
|
+
sourceEvent: event,
|
|
1363
|
+
emitRemove: true
|
|
1364
|
+
});
|
|
1365
|
+
else {
|
|
1366
|
+
const missing = values.filter((v) => !isOn(v));
|
|
1367
|
+
const room = Math.min(missing.length, this._room);
|
|
1368
|
+
if (!room) return;
|
|
1369
|
+
this._setValue([...current, ...missing.slice(0, room)], {
|
|
1370
|
+
sourceEvent: event,
|
|
1371
|
+
emitAdd: true
|
|
1372
|
+
});
|
|
1373
|
+
}
|
|
1374
|
+
this._open = true;
|
|
1375
|
+
this._inputEl?.focus();
|
|
1376
|
+
}
|
|
1377
|
+
_removeValue(value, event) {
|
|
1378
|
+
event?.stopPropagation();
|
|
1379
|
+
if (this.disabled || this.readonly) return;
|
|
1380
|
+
if (!this._canRemoveMore) return;
|
|
1381
|
+
this._setValue(this._selectedValues.filter((item) => !this._isSameValue(item, value)), {
|
|
1382
|
+
removedValue: value,
|
|
1383
|
+
sourceEvent: event,
|
|
1384
|
+
emitRemove: true
|
|
1385
|
+
});
|
|
1386
|
+
this._inputEl?.focus();
|
|
1387
|
+
}
|
|
1388
|
+
_clear(event) {
|
|
1389
|
+
event.stopPropagation();
|
|
1390
|
+
if (this.disabled || this.readonly) return;
|
|
1391
|
+
this._setValue(this._keepFloor([]), {
|
|
1392
|
+
sourceEvent: event,
|
|
1393
|
+
emitClear: true
|
|
1394
|
+
});
|
|
1395
|
+
this._close();
|
|
1396
|
+
this._inputEl?.focus();
|
|
1397
|
+
}
|
|
1398
|
+
_handleInput(event) {
|
|
1399
|
+
if (this.disabled || this.readonly) return;
|
|
1400
|
+
const input = event.currentTarget;
|
|
1401
|
+
if (!this.searchable) {
|
|
1402
|
+
input.value = "";
|
|
1403
|
+
return;
|
|
1404
|
+
}
|
|
1405
|
+
this._inputValue = input.value;
|
|
1406
|
+
this._open = true;
|
|
1407
|
+
this._activeIndex = this._filteredItems.length ? 0 : -1;
|
|
1408
|
+
this._cursorPending = false;
|
|
1409
|
+
this._scheduleSearch();
|
|
1410
|
+
}
|
|
1411
|
+
/**
|
|
1412
|
+
* Focus alone opens nothing: a Tab into the field is not a request to see the
|
|
1413
|
+
* list — typing, ↓, a click in a searchable field or the chevron are. (It used
|
|
1414
|
+
* to open, which also meant every chip-remove's refocus popped the list.)
|
|
1415
|
+
*/
|
|
1416
|
+
_handleFocus() {}
|
|
1417
|
+
/**
|
|
1418
|
+
* A click in the field focuses the input and, when the field is searchable,
|
|
1419
|
+
* OPENS the list — the input is the point there, and clicking into it is how
|
|
1420
|
+
* you start typing; it never closes, because a click in a text input while
|
|
1421
|
+
* the list is open is caret placement, not a toggle (the chevron, Escape and
|
|
1422
|
+
* an outside click close). A non-searchable field has nothing to type into,
|
|
1423
|
+
* so there the click TOGGLES: a second click on the field closes the list.
|
|
1424
|
+
*/
|
|
1425
|
+
_handleFieldClick() {
|
|
1426
|
+
if (this.disabled || this.readonly) return;
|
|
1427
|
+
this._inputEl?.focus();
|
|
1428
|
+
this._moreOpen = false;
|
|
1429
|
+
if (this.searchable) this._open = true;
|
|
1430
|
+
else if (this._open) this._close();
|
|
1431
|
+
else this._open = true;
|
|
1432
|
+
}
|
|
1433
|
+
/** The chevron: the one mouse gesture that both opens and closes. */
|
|
1434
|
+
_toggleFromCaret(event) {
|
|
1435
|
+
event.stopPropagation();
|
|
1436
|
+
if (this.disabled || this.readonly) return;
|
|
1437
|
+
this._moreOpen = false;
|
|
1438
|
+
if (this._open) this._close();
|
|
1439
|
+
else {
|
|
1440
|
+
this._open = true;
|
|
1441
|
+
this._inputEl?.focus();
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
_handleKeydown(event) {
|
|
1445
|
+
if (this.disabled || this.readonly) return;
|
|
1446
|
+
const items = this._filteredItems;
|
|
1447
|
+
if (event.key === "ArrowDown") {
|
|
1448
|
+
event.preventDefault();
|
|
1449
|
+
this._open = true;
|
|
1450
|
+
this._activeIndex = items.length ? Math.min(this._activeIndex + 1, items.length - 1) : -1;
|
|
1451
|
+
return;
|
|
1452
|
+
}
|
|
1453
|
+
if (event.key === "ArrowUp") {
|
|
1454
|
+
event.preventDefault();
|
|
1455
|
+
this._activeIndex = items.length ? Math.max(this._activeIndex - 1, 0) : -1;
|
|
1456
|
+
return;
|
|
1457
|
+
}
|
|
1458
|
+
if (event.key === "Enter") {
|
|
1459
|
+
event.preventDefault();
|
|
1460
|
+
const activeItem = this._activeIndex >= 0 ? items[this._activeIndex] : void 0;
|
|
1461
|
+
if (activeItem && !activeItem.disabled) {
|
|
1462
|
+
this._toggleValue(this._resolveItemValue(activeItem), event);
|
|
1463
|
+
return;
|
|
1464
|
+
}
|
|
1465
|
+
const customValue = this._inputValue.trim();
|
|
1466
|
+
if (customValue && this.allowCustom) this._addValue(customValue, event);
|
|
1467
|
+
return;
|
|
1468
|
+
}
|
|
1469
|
+
if (event.key === "," || event.key === "Tab") {
|
|
1470
|
+
const customValue = this._inputValue.trim();
|
|
1471
|
+
if (customValue && this.allowCustom) {
|
|
1472
|
+
event.preventDefault();
|
|
1473
|
+
this._addValue(customValue, event);
|
|
1474
|
+
}
|
|
1475
|
+
return;
|
|
1476
|
+
}
|
|
1477
|
+
if (event.key === "Backspace" && !this._inputValue && this._selectedValues.length) {
|
|
1478
|
+
event.preventDefault();
|
|
1479
|
+
const lastValue = this._selectedValues[this._selectedValues.length - 1];
|
|
1480
|
+
this._removeValue(lastValue, event);
|
|
1481
|
+
return;
|
|
1482
|
+
}
|
|
1483
|
+
if (event.key === "Escape") {
|
|
1484
|
+
event.preventDefault();
|
|
1485
|
+
this._close();
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
_renderLabel() {
|
|
1489
|
+
const hasContent = !!this.label || this._hasLabelSlotState;
|
|
1490
|
+
if (!hasContent && !this._slotsAlwaysRender) return nothing;
|
|
1491
|
+
return html`
|
|
1492
|
+
<label
|
|
1493
|
+
class=${this._cls("mono-tag-input-label", "label")}
|
|
1494
|
+
mono-label
|
|
1495
|
+
for=${this._inputId}
|
|
1496
|
+
?mono-empty=${!hasContent}
|
|
1497
|
+
>
|
|
1498
|
+
${this._slotOutlet("label", this.label)}
|
|
1499
|
+
|
|
1500
|
+
${this.required ? html`
|
|
1501
|
+
<span class=${this._cls("mono-tag-input-required", "required")} mono-required-mark>
|
|
1502
|
+
*
|
|
1503
|
+
</span>
|
|
1504
|
+
` : nothing}
|
|
1505
|
+
</label>
|
|
1506
|
+
`;
|
|
1507
|
+
}
|
|
1508
|
+
/**
|
|
1509
|
+
* How many chips to draw before the rest collapse into "+N more" — Infinity
|
|
1510
|
+
* when uncapped or while the total sits under the collapse floor
|
|
1511
|
+
* (`visibleChipCap`). `chip.maxVisible` / `chip.minVisible` pin, the element
|
|
1512
|
+
* props are the fallback. Applies to `inline` as well: the "+N more" chip
|
|
1513
|
+
* then sits in the strip after the visible ones, and its panel lists the rest
|
|
1514
|
+
* exactly as in `flex`. Every downstream consumer (`_overflowChips`,
|
|
1515
|
+
* `_renderChips`, the more panel) reads this, so the rule lives in one place.
|
|
1516
|
+
*/
|
|
1517
|
+
get _maxChips() {
|
|
1518
|
+
const chip = this._chipProps;
|
|
1519
|
+
return visibleChipCap(this._resolvedValues.length, resolveChipLimit(chip, "maxVisible", this.maxVisible), resolveChipLimit(chip, "minVisible", this.minVisible));
|
|
1520
|
+
}
|
|
1521
|
+
/** Selected values that have a row behind them — what the chips actually draw. */
|
|
1522
|
+
get _resolvedValues() {
|
|
1523
|
+
return this._selectedValues.filter((v) => !this._isUnresolvedKey(v));
|
|
1524
|
+
}
|
|
1525
|
+
get _overflowChips() {
|
|
1526
|
+
const max = this._maxChips;
|
|
1527
|
+
return max === Infinity ? [] : this._resolvedValues.slice(max);
|
|
1528
|
+
}
|
|
1529
|
+
_closeSvg() {
|
|
1530
|
+
return this.renderIcon("close");
|
|
1531
|
+
}
|
|
1532
|
+
/** The `chip` prop, always an object (it can be assigned null from a binding). */
|
|
1533
|
+
get _chipProps() {
|
|
1534
|
+
return this.chip ?? {};
|
|
1535
|
+
}
|
|
1536
|
+
/** Chip layout: `inline` = one scrolling line, anything else = today's wrap. */
|
|
1537
|
+
get _chipBehaviour() {
|
|
1538
|
+
return this._chipProps.behaviour === "inline" ? "inline" : "flex";
|
|
1539
|
+
}
|
|
1540
|
+
/**
|
|
1541
|
+
* Chip skin matching the field skin: a `filled` field already tints its own
|
|
1542
|
+
* surface, so a soft chip would vanish into it — go solid; `underlined` is
|
|
1543
|
+
* minimal, so the chip stays outline. `chip.variant` pins one instead.
|
|
1544
|
+
*/
|
|
1545
|
+
get _chipVariantClass() {
|
|
1546
|
+
const pinned = this._chipProps.variant;
|
|
1547
|
+
if (pinned) return pinned;
|
|
1548
|
+
if (this.variant === "filled") return "solid";
|
|
1549
|
+
if (this.variant === "underlined") return "outline";
|
|
1550
|
+
return "soft";
|
|
1551
|
+
}
|
|
1552
|
+
/** Chips wear the control's color unless `chip.color` pins another. */
|
|
1553
|
+
get _chipColorClass() {
|
|
1554
|
+
return this._chipProps.color ?? this.color;
|
|
1555
|
+
}
|
|
1556
|
+
/**
|
|
1557
|
+
* Classes shared by the tag chips and the "+N more" chip, in `mono-chip`'s own
|
|
1558
|
+
* order (`mono-chip <size> <variant>-<color> <shape>`), so chip.css paints them
|
|
1559
|
+
* exactly as it paints a real `<mono-chip>`.
|
|
1560
|
+
*
|
|
1561
|
+
* `mono-tag-input-chip` is a marker only — it scopes the `--mono-chip-*` bridge
|
|
1562
|
+
* in tag-input.css so the bridge never reaches a `<mono-chip>` a consumer slots
|
|
1563
|
+
* into the field. `chip.color` deliberately picks a hue OTHER than the control
|
|
1564
|
+
* accent, so it adds the `-pinned` marker that switches the bridge back off.
|
|
1565
|
+
*/
|
|
1566
|
+
get _chipBaseClasses() {
|
|
1567
|
+
const chip = this._chipProps;
|
|
1568
|
+
return [
|
|
1569
|
+
"mono-tag-input-chip",
|
|
1570
|
+
chip.color ? "mono-tag-input-chip-pinned" : "",
|
|
1571
|
+
chip.size ?? (this.size === "xs" || this.size === "sm" ? "xs" : "sm"),
|
|
1572
|
+
`${this._chipVariantClass}-${this._chipColorClass}`,
|
|
1573
|
+
"",
|
|
1574
|
+
chip.dot ? "has-dot" : ""
|
|
1575
|
+
].filter(Boolean).join(" ");
|
|
1576
|
+
}
|
|
1577
|
+
/**
|
|
1578
|
+
* Class for one chip part. Both class APIs append: the tag-input-level key
|
|
1579
|
+
* (`cssClass.chip` / `.chipLabel` / `.chipRemove`, the established surface) and
|
|
1580
|
+
* the chip-level one (`chip.cssClass.*`, which additionally reaches the parts
|
|
1581
|
+
* tag-input has no key for — `main`, `content`, `dot`).
|
|
1582
|
+
*/
|
|
1583
|
+
_chipCls(base, chipKey, key) {
|
|
1584
|
+
return [
|
|
1585
|
+
base,
|
|
1586
|
+
key ? this.cssClass?.[key] : void 0,
|
|
1587
|
+
this._chipProps.cssClass?.[chipKey]
|
|
1588
|
+
].filter(Boolean).join(" ");
|
|
1589
|
+
}
|
|
1590
|
+
/** Render one chip with shared mono-chip markup/classes. */
|
|
1591
|
+
_renderChip(value, removable) {
|
|
1592
|
+
const chip = this._chipProps;
|
|
1593
|
+
const label = this._getLabelByValue(value);
|
|
1594
|
+
const canRemove = removable && !this.disabled && !this.readonly && this._canRemoveMore;
|
|
1595
|
+
return html`
|
|
1596
|
+
<div
|
|
1597
|
+
class=${this._chipCls(`${this._chipBaseClasses}${canRemove ? " removable" : ""}`, "root", "chip")}
|
|
1598
|
+
mono-chip
|
|
1599
|
+
?mono-removable=${canRemove}
|
|
1600
|
+
mono-chip-color=${chip.color ?? nothing}
|
|
1601
|
+
>
|
|
1602
|
+
<span class=${ifDefined(chip.cssClass?.main)} mono-chip-main>
|
|
1603
|
+
<span class=${this._chipCls("chip-content", "content")} mono-chip-content>
|
|
1604
|
+
${chip.dot ? html`<span
|
|
1605
|
+
class=${this._chipCls("chip-dot", "dot")}
|
|
1606
|
+
mono-chip-dot
|
|
1607
|
+
aria-hidden="true"
|
|
1608
|
+
></span>` : nothing}
|
|
1609
|
+
<span class=${this._chipCls("chip-label", "label", "chipLabel")} mono-chip-label>${label}</span>
|
|
1610
|
+
${canRemove ? html`
|
|
1611
|
+
<button
|
|
1612
|
+
type="button"
|
|
1613
|
+
class=${this._chipCls("chip-close", "close", "chipRemove")}
|
|
1614
|
+
mono-chip-close
|
|
1615
|
+
aria-label=${chip.closeLabel ?? `Remove ${label}`}
|
|
1616
|
+
@click=${(event) => this._removeValue(value, event)}
|
|
1617
|
+
>
|
|
1618
|
+
${this._closeSvg()}
|
|
1619
|
+
</button>
|
|
1620
|
+
` : nothing}
|
|
1621
|
+
</span>
|
|
1622
|
+
</span>
|
|
1623
|
+
</div>
|
|
1624
|
+
`;
|
|
1625
|
+
}
|
|
1626
|
+
/**
|
|
1627
|
+
* The chip region. `flex` returns the chips as bare siblings of the input, so
|
|
1628
|
+
* they wrap with it — the historical markup, unchanged. `inline` nests them in
|
|
1629
|
+
* one `overflow-x: hidden` strip instead, which is what makes the row scroll
|
|
1630
|
+
* as a unit while the input keeps its own space beside it.
|
|
1631
|
+
*/
|
|
1632
|
+
_renderChipRegion() {
|
|
1633
|
+
const chips = this._renderChips();
|
|
1634
|
+
if (this._chipBehaviour !== "inline") return chips;
|
|
1635
|
+
return html`
|
|
1636
|
+
<div class=${this._cls("mono-tag-input-chip-strip", "chipStrip")} mono-chip-strip>${chips}</div>
|
|
1637
|
+
`;
|
|
1638
|
+
}
|
|
1639
|
+
_renderChips() {
|
|
1640
|
+
const max = this._maxChips;
|
|
1641
|
+
const visible = max === Infinity ? this._resolvedValues : this._resolvedValues.slice(0, max);
|
|
1642
|
+
this._renderedChipCount = visible.length;
|
|
1643
|
+
const chips = visible.map((value) => this._renderChip(value, true));
|
|
1644
|
+
const overflow = this._overflowChips;
|
|
1645
|
+
if (overflow.length) chips.push(html`
|
|
1646
|
+
<div
|
|
1647
|
+
class=${this._cls(`${this._chipBaseClasses.replace(" has-dot", "")} clickable mono-tag-input-more`, "moreChip")}
|
|
1648
|
+
mono-chip
|
|
1649
|
+
mono-more
|
|
1650
|
+
mono-chip-color=${this._chipProps.color ?? nothing}
|
|
1651
|
+
>
|
|
1652
|
+
<span
|
|
1653
|
+
class=${ifDefined(this._chipProps.cssClass?.main)}
|
|
1654
|
+
mono-chip-main
|
|
1655
|
+
role="button"
|
|
1656
|
+
tabindex="0"
|
|
1657
|
+
@mousedown=${(event) => event.preventDefault()}
|
|
1658
|
+
@click=${(event) => {
|
|
1659
|
+
event.stopPropagation();
|
|
1660
|
+
this._moreOpen = !this._moreOpen;
|
|
1661
|
+
if (this._moreOpen) this._close();
|
|
1662
|
+
}}
|
|
1663
|
+
>
|
|
1664
|
+
<span class=${this._chipCls("chip-content", "content")} mono-chip-content>
|
|
1665
|
+
<span class=${this._chipCls("chip-label", "label")} mono-chip-label>+${overflow.length} more</span>
|
|
1666
|
+
</span>
|
|
1667
|
+
</span>
|
|
1668
|
+
</div>
|
|
1669
|
+
`);
|
|
1670
|
+
return chips;
|
|
1671
|
+
}
|
|
1672
|
+
/**
|
|
1673
|
+
* The trailing control row: `‹ › ✕` or `‹ › ⌄`.
|
|
1674
|
+
*
|
|
1675
|
+
* The scroll buttons only exist in `inline` mode, and each only while there is
|
|
1676
|
+
* something to scroll toward — so a strip that fits shows neither, and a strip
|
|
1677
|
+
* parked at its start shows only `›`.
|
|
1678
|
+
*
|
|
1679
|
+
* Clear and caret are MUTUALLY EXCLUSIVE, in both layouts: whenever the clear
|
|
1680
|
+
* button is available the field has a value and clearing is the useful action,
|
|
1681
|
+
* and whenever it is not (empty field, or `clearable`/`disabled`/`readonly`
|
|
1682
|
+
* ruling it out) the caret advertises the dropdown instead. That keeps the row
|
|
1683
|
+
* one glyph wide, which is what lets `flex` mode go on reserving a single-icon
|
|
1684
|
+
* gutter.
|
|
1685
|
+
*
|
|
1686
|
+
* The scroll buttons suppress `mousedown` and stay out of the tab order: they
|
|
1687
|
+
* are a view control, so paging must not blur the input (which would close the
|
|
1688
|
+
* dropdown mid-interaction) or move focus off the field. The clear button
|
|
1689
|
+
* keeps its existing focus behaviour.
|
|
1690
|
+
*/
|
|
1691
|
+
/**
|
|
1692
|
+
* One scroll button. `active` false keeps the box — and therefore the row's
|
|
1693
|
+
* width — but hides it (`is-idle` → `visibility: hidden`), so reaching an end
|
|
1694
|
+
* of the strip costs no layout. `disabled` and `aria-hidden` keep the hidden
|
|
1695
|
+
* one out of reach of the pointer and of assistive tech.
|
|
1696
|
+
*/
|
|
1697
|
+
_renderScrollButton(dir, active) {
|
|
1698
|
+
const back = dir === -1;
|
|
1699
|
+
const base = `mono-tag-input-scroll mono-tag-input-scroll-${back ? "prev" : "next"}${active ? "" : " is-idle"}`;
|
|
1700
|
+
return html`
|
|
1701
|
+
<button
|
|
1702
|
+
type="button"
|
|
1703
|
+
class=${this._cls(base, back ? "scrollPrev" : "scrollNext")}
|
|
1704
|
+
mono-scroll=${back ? "prev" : "next"}
|
|
1705
|
+
?mono-idle=${!active}
|
|
1706
|
+
aria-label=${back ? "Scroll tags backward" : "Scroll tags forward"}
|
|
1707
|
+
aria-hidden=${active ? "false" : "true"}
|
|
1708
|
+
?disabled=${!active}
|
|
1709
|
+
tabindex="-1"
|
|
1710
|
+
@mousedown=${(event) => event.preventDefault()}
|
|
1711
|
+
@click=${(event) => {
|
|
1712
|
+
event.stopPropagation();
|
|
1713
|
+
this._chipStrip.page(dir);
|
|
1714
|
+
}}
|
|
1715
|
+
>
|
|
1716
|
+
${chevronIcon(dir)}
|
|
1717
|
+
</button>
|
|
1718
|
+
`;
|
|
1719
|
+
}
|
|
1720
|
+
_renderActions() {
|
|
1721
|
+
const showScroll = this._chipBehaviour === "inline" && this._chipStrip.overflowing;
|
|
1722
|
+
const showArrow = !this._showClear && !this.disabled && !this.readonly;
|
|
1723
|
+
return html`
|
|
1724
|
+
<div class=${this._cls("mono-tag-input-actions", "actions")} mono-actions>
|
|
1725
|
+
${showScroll ? html`
|
|
1726
|
+
${this._renderScrollButton(-1, this._chipStrip.canScrollStart)}
|
|
1727
|
+
${this._renderScrollButton(1, this._chipStrip.canScrollEnd)}
|
|
1728
|
+
` : nothing}
|
|
1729
|
+
${this._showClear ? html`
|
|
1730
|
+
<button
|
|
1731
|
+
type="button"
|
|
1732
|
+
class=${this._cls("mono-tag-input-clear", "clear")}
|
|
1733
|
+
mono-clear
|
|
1734
|
+
aria-label="Clear tags"
|
|
1735
|
+
@click=${this._clear}
|
|
1736
|
+
>
|
|
1737
|
+
${this.renderIcon("close")}
|
|
1738
|
+
</button>
|
|
1739
|
+
` : nothing}
|
|
1740
|
+
${showArrow ? html`
|
|
1741
|
+
<span
|
|
1742
|
+
role="button"
|
|
1743
|
+
tabindex="-1"
|
|
1744
|
+
class=${this._cls("mono-tag-input-arrow", "arrow")}
|
|
1745
|
+
mono-arrow
|
|
1746
|
+
aria-label="Toggle suggestions"
|
|
1747
|
+
aria-expanded=${this._open ? "true" : "false"}
|
|
1748
|
+
@mousedown=${(event) => event.preventDefault()}
|
|
1749
|
+
@click=${this._toggleFromCaret}
|
|
1750
|
+
>
|
|
1751
|
+
${caretIcon()}
|
|
1752
|
+
</span>
|
|
1753
|
+
` : nothing}
|
|
1754
|
+
</div>
|
|
1755
|
+
`;
|
|
1756
|
+
}
|
|
1757
|
+
/**
|
|
1758
|
+
* Always rendered, shown by the root's `more-open` class: the panel lives in a
|
|
1759
|
+
* body portal while open and a portaled node cannot be removed by a
|
|
1760
|
+
* conditional render (Lit's ChildPart no longer contains it).
|
|
1761
|
+
*/
|
|
1762
|
+
_renderMorePanel() {
|
|
1763
|
+
const overflow = this._moreOpen ? this._overflowChips : [];
|
|
1764
|
+
return html`
|
|
1765
|
+
<div class=${this._cls("mono-tag-input-more-panel", "morePanel")} mono-more-panel>
|
|
1766
|
+
${overflow.map((value) => this._renderChip(value, true))}
|
|
1767
|
+
</div>
|
|
1768
|
+
`;
|
|
1769
|
+
}
|
|
1770
|
+
_toCssLength(value) {
|
|
1771
|
+
if (value == null || value === "") return void 0;
|
|
1772
|
+
if (typeof value === "number") return `${value}px`;
|
|
1773
|
+
const trimmed = String(value).trim();
|
|
1774
|
+
if (!trimmed) return void 0;
|
|
1775
|
+
return /^-?\d+(?:\.\d+)?$/.test(trimmed) ? `${trimmed}px` : trimmed;
|
|
1776
|
+
}
|
|
1777
|
+
/**
|
|
1778
|
+
* The author's cap goes out as the custom property `--_mono-tag-input-panel-max-h`
|
|
1779
|
+
* rather than a direct `max-height`: the popup controller also constrains this
|
|
1780
|
+
* same element (via `--mono-popup-avail-h`) to keep it inside the viewport, and
|
|
1781
|
+
* two writers on one declaration would clobber each other. The CSS `min()`s them.
|
|
1782
|
+
*/
|
|
1783
|
+
get _dropdownStyle() {
|
|
1784
|
+
const style = {};
|
|
1785
|
+
const panel = this.dropdown;
|
|
1786
|
+
const width = toCssSize(panel?.width);
|
|
1787
|
+
if (width) style.width = width;
|
|
1788
|
+
const minWidth = toCssSize(panel?.minWidth);
|
|
1789
|
+
if (minWidth) style["min-width"] = minWidth;
|
|
1790
|
+
const maxWidth = toCssSize(panel?.maxWidth);
|
|
1791
|
+
if (maxWidth) style["max-width"] = maxWidth;
|
|
1792
|
+
const minHeight = toCssSize(panel?.minHeight);
|
|
1793
|
+
if (minHeight) style["min-height"] = minHeight;
|
|
1794
|
+
const height = toCssSize(panel?.height) ?? this._toCssLength(this.dropdownHeight);
|
|
1795
|
+
if (height) style.height = height;
|
|
1796
|
+
const maxHeight = toCssSize(panel?.maxHeight) ?? this._toCssLength(this.dropdownMaxHeight);
|
|
1797
|
+
if (maxHeight) style["--_mono-tag-input-panel-max-h"] = maxHeight;
|
|
1798
|
+
else if (height) style["--_mono-tag-input-panel-max-h"] = height;
|
|
1799
|
+
else if (this._scrollAutoMaxHeight) style["--_mono-tag-input-panel-max-h"] = this._scrollAutoMaxHeight;
|
|
1800
|
+
return style;
|
|
1801
|
+
}
|
|
1802
|
+
/**
|
|
1803
|
+
* Scroll-mode ergonomics (see mono-select): cap the list height to the loaded
|
|
1804
|
+
* rows minus a sliver so a short page is still scrollable, instead of eagerly
|
|
1805
|
+
* fetching another page on open.
|
|
1806
|
+
*/
|
|
1807
|
+
_updateScrollAutoHeight() {
|
|
1808
|
+
const userSetHeight = this._toCssLength(this.dropdownHeight) != null || this._toCssLength(this.dropdownMaxHeight) != null || toCssSize(this.dropdown?.height) != null || toCssSize(this.dropdown?.maxHeight) != null;
|
|
1809
|
+
const rowsShown = this._filteredItems.length;
|
|
1810
|
+
if (!(this._loadMoreMode === "scroll" && this._open && !this._ds.atLastPage && !userSetHeight && rowsShown > 0)) {
|
|
1811
|
+
this._setScrollAutoMaxHeight("");
|
|
1812
|
+
return;
|
|
1813
|
+
}
|
|
1814
|
+
const el = this._dropdownEl;
|
|
1815
|
+
const rowH = (el?.querySelector(".mono-tag-input-item"))?.offsetHeight ?? 0;
|
|
1816
|
+
if (!el || !rowH) return;
|
|
1817
|
+
const CAP_ROWS = 7;
|
|
1818
|
+
let visible = Math.min(rowsShown, CAP_ROWS);
|
|
1819
|
+
if (rowsShown <= CAP_ROWS) visible -= .5;
|
|
1820
|
+
this._setScrollAutoMaxHeight(`${Math.round(visible * rowH)}px`);
|
|
1821
|
+
}
|
|
1822
|
+
_setScrollAutoMaxHeight(value) {
|
|
1823
|
+
if (value === this._scrollAutoMaxHeight) return;
|
|
1824
|
+
queueMicrotask(() => {
|
|
1825
|
+
this._scrollAutoMaxHeight = value;
|
|
1826
|
+
});
|
|
1827
|
+
}
|
|
1828
|
+
_renderLoadMore() {
|
|
1829
|
+
if (!this._loadMoreMode) return nothing;
|
|
1830
|
+
if (!this._visibleItems.length || this._ds.atLastPage) return nothing;
|
|
1831
|
+
if (this._ds.loadingMore) return html`
|
|
1832
|
+
<div class=${`${this._cls("mono-tag-input-load-more", "loadMore")} loading`} mono-load-more mono-loading>
|
|
1833
|
+
Loading…
|
|
1834
|
+
</div>
|
|
1835
|
+
`;
|
|
1836
|
+
if (this._loadMoreMode !== "button") return nothing;
|
|
1837
|
+
return html`
|
|
1838
|
+
<button
|
|
1839
|
+
type="button"
|
|
1840
|
+
class=${this._cls("mono-tag-input-load-more", "loadMore")}
|
|
1841
|
+
mono-load-more
|
|
1842
|
+
@mousedown=${(event) => event.preventDefault()}
|
|
1843
|
+
@click=${(event) => {
|
|
1844
|
+
event.preventDefault();
|
|
1845
|
+
event.stopPropagation();
|
|
1846
|
+
this._ds.loadMore();
|
|
1847
|
+
}}
|
|
1848
|
+
>
|
|
1849
|
+
Load more
|
|
1850
|
+
</button>
|
|
1851
|
+
`;
|
|
1852
|
+
}
|
|
1853
|
+
/**
|
|
1854
|
+
* The reused `.mono-checkbox` box. Tri-state: `'some'` paints the indeterminate
|
|
1855
|
+
* dash, which is what tells a user a group is PARTLY selected — the one thing a
|
|
1856
|
+
* two-state box could not say.
|
|
1857
|
+
*/
|
|
1858
|
+
_renderCheckBox(state, loading = false) {
|
|
1859
|
+
const cls = [
|
|
1860
|
+
this._cls("mono-checkbox", "check"),
|
|
1861
|
+
this.color,
|
|
1862
|
+
state === "all" ? "mono-checkbox-checked" : "",
|
|
1863
|
+
state === "some" ? "mono-checkbox-indeterminate" : "",
|
|
1864
|
+
loading ? "is-loading" : ""
|
|
1865
|
+
].filter(Boolean).join(" ");
|
|
1866
|
+
const boxCls = [
|
|
1867
|
+
"mono-checkbox-box",
|
|
1868
|
+
"sm",
|
|
1869
|
+
loading ? "has-custom-icon has-custom-indeterminate-icon" : ""
|
|
1870
|
+
].filter(Boolean).join(" ");
|
|
1871
|
+
return html`
|
|
1872
|
+
<span
|
|
1873
|
+
class=${cls}
|
|
1874
|
+
mono-check-box
|
|
1875
|
+
mono-checkbox
|
|
1876
|
+
mono-size="sm"
|
|
1877
|
+
mono-color=${this.color === "primary" ? nothing : this.color}
|
|
1878
|
+
?mono-checked=${state === "all"}
|
|
1879
|
+
?mono-indeterminate=${state === "some"}
|
|
1880
|
+
?mono-loading=${loading}
|
|
1881
|
+
aria-hidden="true"
|
|
1882
|
+
>
|
|
1883
|
+
<span class=${boxCls} mono-box ?mono-custom-icon=${loading} ?mono-custom-indeterminate-icon=${loading}>${loading ? this._renderCheckSpinner() : nothing}</span>
|
|
1884
|
+
</span>
|
|
1885
|
+
`;
|
|
1886
|
+
}
|
|
1887
|
+
/**
|
|
1888
|
+
* The drain spinner. Inline SVG rather than the `i-mdi-loading` UnoCSS class
|
|
1889
|
+
* because a page stylesheet cannot reach the shadow build's root — one template
|
|
1890
|
+
* serves both, the same reason `composables/field-icons` exists.
|
|
1891
|
+
*
|
|
1892
|
+
* `.mono-checkbox-spinner` carries the sizing and the keyframes; checkbox.css is
|
|
1893
|
+
* already on the page for the light build and adopted into the shadow root for
|
|
1894
|
+
* the other, which is what the box itself depends on too.
|
|
1895
|
+
*/
|
|
1896
|
+
_renderCheckSpinner() {
|
|
1897
|
+
return html`<svg
|
|
1898
|
+
class="mono-checkbox-spinner"
|
|
1899
|
+
mono-spinner
|
|
1900
|
+
viewBox="0 0 24 24"
|
|
1901
|
+
fill="none"
|
|
1902
|
+
stroke="currentColor"
|
|
1903
|
+
stroke-width="3"
|
|
1904
|
+
stroke-linecap="round"
|
|
1905
|
+
aria-hidden="true"
|
|
1906
|
+
>
|
|
1907
|
+
<path d="M12 3a9 9 0 1 0 9 9" />
|
|
1908
|
+
</svg>`;
|
|
1909
|
+
}
|
|
1910
|
+
/**
|
|
1911
|
+
* The leading "All" row. Scoped to the rows the current search leaves visible,
|
|
1912
|
+
* which is what `items` already is at every call site.
|
|
1913
|
+
*
|
|
1914
|
+
* `role="option"` because that is what it behaves like — an option meaning "every
|
|
1915
|
+
* one of these" — so a screen reader announces it inside the same listbox as the
|
|
1916
|
+
* rows it toggles.
|
|
1917
|
+
*/
|
|
1918
|
+
_renderSelectAll(items) {
|
|
1919
|
+
if (!this.selectAll || this.disabled || this.readonly) return nothing;
|
|
1920
|
+
const usable = items.filter((item) => this._isSelectable(item));
|
|
1921
|
+
if (!usable.length) return nothing;
|
|
1922
|
+
const state = this._selectAllState(usable);
|
|
1923
|
+
const pending = this._selectAllPending;
|
|
1924
|
+
return html`
|
|
1925
|
+
<button
|
|
1926
|
+
type="button"
|
|
1927
|
+
role="option"
|
|
1928
|
+
class=${[
|
|
1929
|
+
this._cls("mono-tag-input-item", "item"),
|
|
1930
|
+
this._cls("mono-tag-input-select-all", "selectAll"),
|
|
1931
|
+
"has-check",
|
|
1932
|
+
state !== "none" ? "selected" : "",
|
|
1933
|
+
pending ? "is-loading" : ""
|
|
1934
|
+
].filter(Boolean).join(" ")}
|
|
1935
|
+
mono-item
|
|
1936
|
+
mono-select-all
|
|
1937
|
+
mono-check
|
|
1938
|
+
?mono-selected=${state !== "none"}
|
|
1939
|
+
?mono-loading=${pending}
|
|
1940
|
+
aria-selected=${state === "all" ? "true" : "false"}
|
|
1941
|
+
aria-busy=${pending ? "true" : "false"}
|
|
1942
|
+
?disabled=${pending}
|
|
1943
|
+
@mousedown=${(event) => event.preventDefault()}
|
|
1944
|
+
@click=${(event) => this._onSelectAllClick(usable, state, event)}
|
|
1945
|
+
>
|
|
1946
|
+
${this._renderCheckBox(state, pending)}
|
|
1947
|
+
<div class=${this._cls("mono-tag-input-item-text", "itemText")} mono-item-text>
|
|
1948
|
+
<div class=${this._cls("mono-tag-input-item-title", "itemTitle")} mono-item-title>
|
|
1949
|
+
${this.selectAllLabel}
|
|
1950
|
+
</div>
|
|
1951
|
+
</div>
|
|
1952
|
+
</button>
|
|
1953
|
+
`;
|
|
1954
|
+
}
|
|
1955
|
+
/**
|
|
1956
|
+
* A group header — a plain label, or its own select-all when `groupSelectAll` is
|
|
1957
|
+
* on and the group has rows to toggle. It stays a header either way: same class,
|
|
1958
|
+
* same sticky behaviour, same indent, so a grouped list does not reflow when the
|
|
1959
|
+
* feature is switched off.
|
|
1960
|
+
*/
|
|
1961
|
+
_renderGroupHeader(row) {
|
|
1962
|
+
const base = `${this._cls("mono-tag-input-group", "group")}${this.groupSticky ? " sticky" : ""}`;
|
|
1963
|
+
const usable = row.items.filter((item) => this._isSelectable(item));
|
|
1964
|
+
if (!this.groupSelectAll || this.disabled || this.readonly || !usable.length) return html`<div class=${base} mono-group mono-level=${row.level} ?mono-sticky=${this.groupSticky} data-level=${row.level} role="presentation">
|
|
1965
|
+
${row.label}
|
|
1966
|
+
</div>`;
|
|
1967
|
+
const state = this._selectionStateOf(usable);
|
|
1968
|
+
return html`
|
|
1969
|
+
<button
|
|
1970
|
+
type="button"
|
|
1971
|
+
class=${`${base} is-toggle${state !== "none" ? " selected" : ""}`}
|
|
1972
|
+
mono-group
|
|
1973
|
+
mono-toggle
|
|
1974
|
+
mono-level=${row.level}
|
|
1975
|
+
?mono-sticky=${this.groupSticky}
|
|
1976
|
+
?mono-selected=${state !== "none"}
|
|
1977
|
+
data-level=${row.level}
|
|
1978
|
+
aria-pressed=${state === "all" ? "true" : "false"}
|
|
1979
|
+
@mousedown=${(event) => event.preventDefault()}
|
|
1980
|
+
@click=${(event) => this._toggleMany(usable, event)}
|
|
1981
|
+
>
|
|
1982
|
+
${this._renderCheckBox(state)}
|
|
1983
|
+
<span class=${this._cls("mono-tag-input-group-label", "groupLabel")} mono-group-label>
|
|
1984
|
+
${row.label}
|
|
1985
|
+
</span>
|
|
1986
|
+
</button>
|
|
1987
|
+
`;
|
|
1988
|
+
}
|
|
1989
|
+
/**
|
|
1990
|
+
* The flat entry list published to `form.items()[key].list`.
|
|
1991
|
+
*
|
|
1992
|
+
* The SAME sequence the component renders — group headers interleaved with their leaves — so a
|
|
1993
|
+
* consumer looping it produces one node per row, in order, and the two stay paired by position
|
|
1994
|
+
* with nothing to key by hand. `_groupRows()` already computes exactly this for the grouped case.
|
|
1995
|
+
*
|
|
1996
|
+
* `key` is `item[keyValue]` via `_resolveItemValue`, the same value selection is keyed by, so the
|
|
1997
|
+
* feature introduces no second notion of a key.
|
|
1998
|
+
*/
|
|
1999
|
+
_listEntries() {
|
|
2000
|
+
const rowEntry = (item, level, index) => ({
|
|
2001
|
+
type: "row",
|
|
2002
|
+
key: String(this._resolveItemValue(item) ?? ""),
|
|
2003
|
+
item,
|
|
2004
|
+
level,
|
|
2005
|
+
selected: this._isSelected(item),
|
|
2006
|
+
active: index >= 0 && index === this._activeIndex
|
|
2007
|
+
});
|
|
2008
|
+
if (this._grouped) return this._groupRows().map((row) => row.kind === "group" ? {
|
|
2009
|
+
type: "group",
|
|
2010
|
+
key: row.key,
|
|
2011
|
+
label: row.label,
|
|
2012
|
+
level: row.level,
|
|
2013
|
+
items: row.items
|
|
2014
|
+
} : rowEntry(row.item, row.level, row.index));
|
|
2015
|
+
return this._filteredItems.map((item, index) => rowEntry(item, 0, index));
|
|
2016
|
+
}
|
|
2017
|
+
/**
|
|
2018
|
+
* Hand the form the current entries — but only a NEW array when they actually moved.
|
|
2019
|
+
*
|
|
2020
|
+
* This runs from `updated()`, so it fires on every render; the controller notifies on a changed
|
|
2021
|
+
* list, and that notify re-renders this control. Returning the same array reference is what keeps
|
|
2022
|
+
* that from looping forever. Identity of `item` counts as a change: a reloaded DataSource hands
|
|
2023
|
+
* back fresh row objects under the same keys, and a consumer reading `e.item.Nama` must see them.
|
|
2024
|
+
*/
|
|
2025
|
+
_syncListEntries() {
|
|
2026
|
+
const next = this._listEntries();
|
|
2027
|
+
const prev = this._publishedEntries;
|
|
2028
|
+
let same = prev.length === next.length;
|
|
2029
|
+
if (same) for (let i = 0; i < next.length; i++) {
|
|
2030
|
+
const a = prev[i];
|
|
2031
|
+
const b = next[i];
|
|
2032
|
+
if (a.type !== b.type || a.key !== b.key || a.item !== b.item || a.selected !== b.selected || a.active !== b.active) {
|
|
2033
|
+
same = false;
|
|
2034
|
+
break;
|
|
2035
|
+
}
|
|
2036
|
+
}
|
|
2037
|
+
if (same) return;
|
|
2038
|
+
this._publishedEntries = next;
|
|
2039
|
+
this._publishList(next);
|
|
2040
|
+
}
|
|
2041
|
+
_renderOption(item, index, level = 0) {
|
|
2042
|
+
const active = index === this._activeIndex;
|
|
2043
|
+
const checked = this._isSelected(item);
|
|
2044
|
+
const itemClass = [
|
|
2045
|
+
this._cls("mono-tag-input-item", "item"),
|
|
2046
|
+
this.checkable ? "has-check" : "",
|
|
2047
|
+
active ? `active ${this.cssClass?.itemActive ?? ""}` : "",
|
|
2048
|
+
checked ? `selected ${this.cssClass?.itemSelected ?? ""}` : "",
|
|
2049
|
+
item.disabled ? `disabled ${this.cssClass?.itemDisabled ?? ""}` : ""
|
|
2050
|
+
].filter(Boolean).join(" ");
|
|
2051
|
+
const itemValue = this._resolveItemValue(item);
|
|
2052
|
+
return html`
|
|
2053
|
+
<button
|
|
2054
|
+
type="button"
|
|
2055
|
+
role="option"
|
|
2056
|
+
class=${itemClass}
|
|
2057
|
+
mono-item
|
|
2058
|
+
?mono-check=${this.checkable}
|
|
2059
|
+
?mono-active=${active}
|
|
2060
|
+
?mono-selected=${checked}
|
|
2061
|
+
?mono-disabled=${!!item.disabled}
|
|
2062
|
+
mono-level=${level}
|
|
2063
|
+
data-level=${level}
|
|
2064
|
+
aria-selected=${checked ? "true" : "false"}
|
|
2065
|
+
?disabled=${item.disabled}
|
|
2066
|
+
@mousedown=${(event) => event.preventDefault()}
|
|
2067
|
+
@click=${(event) => itemValue === void 0 ? void 0 : this._toggleValue(itemValue, event)}
|
|
2068
|
+
>
|
|
2069
|
+
${this.checkable ? this._renderCheckBox(checked ? "all" : "none") : nothing}
|
|
2070
|
+
|
|
2071
|
+
<div class=${this._cls("mono-tag-input-item-text", "itemText")} mono-item-text>
|
|
2072
|
+
<div class=${this._cls("mono-tag-input-item-title", "itemTitle")} mono-item-title>
|
|
2073
|
+
${this._resolveItemDisplay(item)}
|
|
2074
|
+
</div>
|
|
2075
|
+
|
|
2076
|
+
${item.description ? html`
|
|
2077
|
+
<div class=${this._cls("mono-tag-input-item-sub", "itemSub")} mono-item-sub>
|
|
2078
|
+
${item.description}
|
|
2079
|
+
</div>
|
|
2080
|
+
` : nothing}
|
|
2081
|
+
</div>
|
|
2082
|
+
</button>
|
|
2083
|
+
`;
|
|
2084
|
+
}
|
|
2085
|
+
_renderEmpty() {
|
|
2086
|
+
const text = this.dataSource && this._ds.loading ? "Loading…" : "No items";
|
|
2087
|
+
return html`<div class=${this._cls("mono-tag-input-empty", "empty")} mono-empty-row>${text}</div>`;
|
|
2088
|
+
}
|
|
2089
|
+
_renderItems() {
|
|
2090
|
+
const visible = this._filteredItems;
|
|
2091
|
+
const empty = !visible.length;
|
|
2092
|
+
if (this._hasListSlotState) return html`
|
|
2093
|
+
${empty ? this._renderEmpty() : this._renderSelectAll(visible)}
|
|
2094
|
+
${this.renderListSlot()}
|
|
2095
|
+
`;
|
|
2096
|
+
if (empty) return this._renderEmpty();
|
|
2097
|
+
if (this._grouped) return html`
|
|
2098
|
+
${this._renderSelectAll(visible)}
|
|
2099
|
+
${this._groupRows().map((row) => row.kind === "group" ? this._renderGroupHeader(row) : this._renderOption(row.item, row.index, row.level))}
|
|
2100
|
+
`;
|
|
2101
|
+
return html`
|
|
2102
|
+
${this._renderSelectAll(visible)}
|
|
2103
|
+
${visible.map((item, index) => this._renderOption(item, index))}
|
|
2104
|
+
`;
|
|
2105
|
+
}
|
|
2106
|
+
/**
|
|
2107
|
+
* Where the consumer's `slot="list"` content goes — overridden per build.
|
|
2108
|
+
*
|
|
2109
|
+
* mono places that content as ONE block and never reaches inside it. Moving a `v-for`'s children
|
|
2110
|
+
* is not survivable: Vue inserts a new row with `parent.insertBefore(node, anchor)` where the
|
|
2111
|
+
* anchor is the existing node at that position, so relocating one makes the consumer's next
|
|
2112
|
+
* insert throw `NotFoundError`. Hence one block, and hence `data-mono-item-key` — with the rows
|
|
2113
|
+
* out of reach, a delegated click is the only way back to the item.
|
|
2114
|
+
*/
|
|
2115
|
+
renderListSlot() {
|
|
2116
|
+
return html``;
|
|
2117
|
+
}
|
|
2118
|
+
/**
|
|
2119
|
+
* The entry a click landed on — by POSITION, so a consumer writes a plain `v-for` and nothing else.
|
|
2120
|
+
*
|
|
2121
|
+
* mono cannot read a node's item off the node: it published the list, but the DOM was built by
|
|
2122
|
+
* someone else. What it CAN do is count. The wrapper's Nth element child is the Nth published
|
|
2123
|
+
* entry, because that is the contract the slot already states — one flat loop, one node per entry,
|
|
2124
|
+
* in order — and here that contract is CHECKED rather than assumed: if the two lengths disagree,
|
|
2125
|
+
* this refuses the click instead of picking the wrong row.
|
|
2126
|
+
*
|
|
2127
|
+
* Position is resolved at CLICK time, never cached. That is what makes it safe with no observer
|
|
2128
|
+
* and no re-stamping: by the time a human clicks, the framework has long finished patching, so
|
|
2129
|
+
* there is no window where a stale pairing could be consulted.
|
|
2130
|
+
*
|
|
2131
|
+
* `data-mono-item-key` still wins when present — the escape hatch for a wrapper that cannot emit
|
|
2132
|
+
* exactly one element per entry (a sticky header of your own, a row that renders as a fragment).
|
|
2133
|
+
*/
|
|
2134
|
+
/**
|
|
2135
|
+
* The consumer's `slot="list"` wrapper, wherever the build keeps it.
|
|
2136
|
+
*
|
|
2137
|
+
* The shadow build never moves it — it stays a light child of the host and is PROJECTED — so
|
|
2138
|
+
* that is the default. The light build moves it into the panel and overrides this with the node
|
|
2139
|
+
* it captured, which is also findable while the panel is closed and the wrapper parked.
|
|
2140
|
+
*/
|
|
2141
|
+
get _listSlotWrapper() {
|
|
2142
|
+
return this._lateListSlot.find();
|
|
2143
|
+
}
|
|
2144
|
+
/**
|
|
2145
|
+
* Re-decorate whenever the consumer re-renders their rows.
|
|
2146
|
+
*
|
|
2147
|
+
* `_syncListChrome()` runs from `updated()`, but a framework patches the wrapper on ITS next
|
|
2148
|
+
* tick — so a row the search box just revealed would be born undecorated and stay that way until
|
|
2149
|
+
* something else made mono render. This closes that gap.
|
|
2150
|
+
*
|
|
2151
|
+
* `childList` on the WRAPPER, which is exactly the churn {@link LateSlotWatcher} refuses on the
|
|
2152
|
+
* host: there the consumer's row traffic is noise, here it IS the signal. No `subtree`, so
|
|
2153
|
+
* mono's own writes — attributes, and a checkbox appended INSIDE a row — cannot re-trigger it.
|
|
2154
|
+
*/
|
|
2155
|
+
_watchListChrome() {
|
|
2156
|
+
if (typeof MutationObserver === "undefined") return;
|
|
2157
|
+
const wrapper = this._listSlotWrapper;
|
|
2158
|
+
if (!wrapper || wrapper === this._observedListWrapper) return;
|
|
2159
|
+
this._listChromeObserver?.disconnect();
|
|
2160
|
+
this._observedListWrapper = wrapper;
|
|
2161
|
+
this._listChromeObserver = new MutationObserver(() => this._syncListChrome());
|
|
2162
|
+
this._listChromeObserver.observe(wrapper, { childList: true });
|
|
2163
|
+
}
|
|
2164
|
+
_stopWatchingListChrome() {
|
|
2165
|
+
this._listChromeObserver?.disconnect();
|
|
2166
|
+
this._listChromeObserver = void 0;
|
|
2167
|
+
this._observedListWrapper = void 0;
|
|
2168
|
+
}
|
|
2169
|
+
/**
|
|
2170
|
+
* Decorate the lines the consumer rendered — the half of this feature that keeps the SLOT about
|
|
2171
|
+
* markup and mono about behaviour.
|
|
2172
|
+
*
|
|
2173
|
+
* Your template says what a line LOOKS like. Everything that carries state or acts on the value
|
|
2174
|
+
* stays here: mono walks the lines it just published and stamps the state as `data-*`
|
|
2175
|
+
* attributes, then puts its own checkbox in — the same markup `_renderCheckBox` produces for
|
|
2176
|
+
* mono's own rows, so it inherits the same CSS and the same colour prop.
|
|
2177
|
+
*
|
|
2178
|
+
* Three rules keep this safe beside a framework:
|
|
2179
|
+
* · children are ANNOTATED and APPENDED TO, never moved, reordered or removed — every
|
|
2180
|
+
* `insertBefore` anchor a `v-for` patches against stays valid;
|
|
2181
|
+
* · `data-*` only, never `class` — `class` is the consumer's binding and would be clobbered;
|
|
2182
|
+
* · the injected node is marked `data-mono-chrome`, so it is never mistaken for content and is
|
|
2183
|
+
* updated in place instead of recreated.
|
|
2184
|
+
*/
|
|
2185
|
+
_syncListChrome() {
|
|
2186
|
+
if (!this._hasListSlotState) return;
|
|
2187
|
+
const wrapper = this._listSlotWrapper;
|
|
2188
|
+
if (!wrapper) return;
|
|
2189
|
+
const children = Array.from(wrapper.children);
|
|
2190
|
+
const entries = this._publishedEntries;
|
|
2191
|
+
if (children.length !== entries.length) return;
|
|
2192
|
+
for (let i = 0; i < children.length; i++) {
|
|
2193
|
+
const node = children[i];
|
|
2194
|
+
const entry = entries[i];
|
|
2195
|
+
node.setAttribute("data-mono-type", entry.type);
|
|
2196
|
+
node.setAttribute("data-mono-level", String(entry.level ?? 0));
|
|
2197
|
+
node.setAttribute("data-mono-key", entry.key);
|
|
2198
|
+
if (entry.type === "group") {
|
|
2199
|
+
const usable = (entry.items ?? []).filter((item) => this._isSelectable(item));
|
|
2200
|
+
const state = this._selectionStateOf(usable);
|
|
2201
|
+
node.setAttribute("data-mono-state", state);
|
|
2202
|
+
node.toggleAttribute("data-mono-selected", state === "all");
|
|
2203
|
+
this._syncListCheckBox(node, this.checkable && this.groupSelectAll && !this.disabled && !this.readonly && usable.length > 0, state);
|
|
2204
|
+
continue;
|
|
2205
|
+
}
|
|
2206
|
+
node.toggleAttribute("data-mono-selected", !!entry.selected);
|
|
2207
|
+
node.toggleAttribute("data-mono-active", !!entry.active);
|
|
2208
|
+
this._syncListCheckBox(node, this.checkable, entry.selected ? "all" : "none");
|
|
2209
|
+
}
|
|
2210
|
+
}
|
|
2211
|
+
/**
|
|
2212
|
+
* mono's own checkbox, inside a line mono does not own.
|
|
2213
|
+
*
|
|
2214
|
+
* Same markup as `_renderCheckBox`, built by hand because Lit cannot render into a subtree it
|
|
2215
|
+
* does not control. It is created once and then only re-classed, so the consumer's framework
|
|
2216
|
+
* never sees a node appear and disappear under it.
|
|
2217
|
+
*/
|
|
2218
|
+
_syncListCheckBox(row, wanted, state) {
|
|
2219
|
+
let box = row.querySelector("[data-mono-chrome]");
|
|
2220
|
+
if (!wanted) {
|
|
2221
|
+
box?.remove();
|
|
2222
|
+
return;
|
|
2223
|
+
}
|
|
2224
|
+
if (!box) {
|
|
2225
|
+
box = document.createElement("span");
|
|
2226
|
+
box.setAttribute("data-mono-chrome", "");
|
|
2227
|
+
box.setAttribute("aria-hidden", "true");
|
|
2228
|
+
const inner = document.createElement("span");
|
|
2229
|
+
inner.className = "mono-checkbox-box sm";
|
|
2230
|
+
inner.setAttribute("mono-box", "");
|
|
2231
|
+
box.setAttribute("mono-check-box", "");
|
|
2232
|
+
box.setAttribute("mono-checkbox", "");
|
|
2233
|
+
box.setAttribute("mono-size", "sm");
|
|
2234
|
+
box.appendChild(inner);
|
|
2235
|
+
const anchor = row.querySelector("[data-mono-check]");
|
|
2236
|
+
if (anchor) anchor.appendChild(box);
|
|
2237
|
+
else row.insertBefore(box, row.firstChild);
|
|
2238
|
+
}
|
|
2239
|
+
box.className = [
|
|
2240
|
+
this._cls("mono-checkbox", "check"),
|
|
2241
|
+
this.color,
|
|
2242
|
+
state === "all" ? "mono-checkbox-checked" : "",
|
|
2243
|
+
state === "some" ? "mono-checkbox-indeterminate" : ""
|
|
2244
|
+
].filter(Boolean).join(" ");
|
|
2245
|
+
if (this.color === "primary") box.removeAttribute("mono-color");
|
|
2246
|
+
else box.setAttribute("mono-color", this.color);
|
|
2247
|
+
box.toggleAttribute("mono-checked", state === "all");
|
|
2248
|
+
box.toggleAttribute("mono-indeterminate", state === "some");
|
|
2249
|
+
}
|
|
2250
|
+
_entryFromNode(node) {
|
|
2251
|
+
const keyed = node.closest?.("[data-mono-item-key]");
|
|
2252
|
+
if (keyed) {
|
|
2253
|
+
const key = keyed.getAttribute("data-mono-item-key");
|
|
2254
|
+
return this._publishedEntries.find((e) => e.key === key);
|
|
2255
|
+
}
|
|
2256
|
+
const wrapper = node.closest?.("[slot=\"list\"]");
|
|
2257
|
+
if (!wrapper) return void 0;
|
|
2258
|
+
let row = node;
|
|
2259
|
+
while (row && row.parentElement !== wrapper) row = row.parentElement;
|
|
2260
|
+
if (!row) return void 0;
|
|
2261
|
+
const children = Array.from(wrapper.children);
|
|
2262
|
+
if (children.length !== this._publishedEntries.length) {
|
|
2263
|
+
console.warn(`[mono-tag-input] 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.`);
|
|
2264
|
+
return;
|
|
2265
|
+
}
|
|
2266
|
+
return this._publishedEntries[children.indexOf(row)];
|
|
2267
|
+
}
|
|
2268
|
+
_renderHelper() {
|
|
2269
|
+
const base = this._cls("mono-tag-input-message", "message");
|
|
2270
|
+
if (this.validationMessage) {
|
|
2271
|
+
const state = this._resolvedValidationState;
|
|
2272
|
+
return html`
|
|
2273
|
+
<div class=${`${base} ${state}`} mono-message=${state} role=${state === "invalid" ? "alert" : nothing}>
|
|
2274
|
+
${this.validationMessage}
|
|
2275
|
+
</div>
|
|
2276
|
+
`;
|
|
2277
|
+
}
|
|
2278
|
+
if (this.errorMessage) return html`
|
|
2279
|
+
<div class=${`${base} invalid`} mono-message="invalid" role="alert">
|
|
2280
|
+
${this.errorMessage}
|
|
2281
|
+
</div>
|
|
2282
|
+
`;
|
|
2283
|
+
if (this.successMessage) return html`
|
|
2284
|
+
<div class=${`${base} valid`} mono-message="valid">
|
|
2285
|
+
${this.successMessage}
|
|
2286
|
+
</div>
|
|
2287
|
+
`;
|
|
2288
|
+
if (this.helperText || this._hasHelperSlot || this._slotsAlwaysRender) return html`
|
|
2289
|
+
<div
|
|
2290
|
+
class=${`${base} helper`}
|
|
2291
|
+
mono-message="helper"
|
|
2292
|
+
?mono-empty=${!this.helperText && !this._hasHelperSlot}
|
|
2293
|
+
>
|
|
2294
|
+
${this._slotOutlet("helper", this.helperText)}
|
|
2295
|
+
</div>
|
|
2296
|
+
`;
|
|
2297
|
+
return nothing;
|
|
2298
|
+
}
|
|
2299
|
+
/** Inline sizing applied to the root wrapper. */
|
|
2300
|
+
_sizeStyle() {
|
|
2301
|
+
return buildSizeStyle(this);
|
|
2302
|
+
}
|
|
2303
|
+
render() {
|
|
2304
|
+
const describedBy = this.validationMessage || this.errorMessage || this.successMessage || this.helperText || this._hasHelperSlot ? this._messageId : void 0;
|
|
2305
|
+
const ariaLabel = this.ariaLabelText || this.label || this.placeholder || void 0;
|
|
2306
|
+
const state = this._resolvedValidationState;
|
|
2307
|
+
return html`
|
|
2308
|
+
<div
|
|
2309
|
+
class=${this._wrapperClasses}
|
|
2310
|
+
style=${styleMap(this._sizeStyle())}
|
|
2311
|
+
mono-tag-input
|
|
2312
|
+
mono-size=${this.size === "md" ? nothing : this.size}
|
|
2313
|
+
mono-color=${this.color === "primary" ? nothing : this.color}
|
|
2314
|
+
mono-variant=${this.variant === "outlined" ? nothing : this.variant}
|
|
2315
|
+
mono-validation-state=${state === "default" ? nothing : state}
|
|
2316
|
+
?mono-open=${this._open}
|
|
2317
|
+
?mono-more-open=${this._moreOpen}
|
|
2318
|
+
?mono-disabled=${this.disabled}
|
|
2319
|
+
?mono-readonly=${this.readonly}
|
|
2320
|
+
?mono-required=${this.required}
|
|
2321
|
+
?mono-clearable=${this.clearable}
|
|
2322
|
+
?mono-checkable=${this.checkable}
|
|
2323
|
+
?mono-searchable=${this.searchable}
|
|
2324
|
+
>
|
|
2325
|
+
${this._renderLabel()}
|
|
2326
|
+
|
|
2327
|
+
<div
|
|
2328
|
+
class=${this._fieldClasses}
|
|
2329
|
+
mono-field
|
|
2330
|
+
?mono-inline=${this._chipBehaviour === "inline"}
|
|
2331
|
+
?mono-typing=${!!this._inputValue}
|
|
2332
|
+
@click=${this._handleFieldClick}
|
|
2333
|
+
>
|
|
2334
|
+
${this._renderChipRegion()}
|
|
2335
|
+
|
|
2336
|
+
<input
|
|
2337
|
+
id=${this._inputId}
|
|
2338
|
+
class=${this._cls("mono-tag-input-native", "native")}
|
|
2339
|
+
mono-native
|
|
2340
|
+
type="text"
|
|
2341
|
+
.value=${this._inputValue}
|
|
2342
|
+
name=${ifDefined(this.name || void 0)}
|
|
2343
|
+
placeholder=${ifDefined(this._hasValue ? void 0 : this.placeholder)}
|
|
2344
|
+
?disabled=${this.disabled}
|
|
2345
|
+
?readonly=${this.readonly || !this.searchable}
|
|
2346
|
+
?required=${this.required && !this._hasValue}
|
|
2347
|
+
aria-label=${ifDefined(ariaLabel)}
|
|
2348
|
+
aria-invalid=${this._resolvedValidationState === "invalid" ? "true" : "false"}
|
|
2349
|
+
aria-describedby=${ifDefined(describedBy)}
|
|
2350
|
+
aria-controls=${this._listboxId}
|
|
2351
|
+
aria-expanded=${this._open ? "true" : "false"}
|
|
2352
|
+
autocomplete="off"
|
|
2353
|
+
@input=${this._handleInput}
|
|
2354
|
+
@focus=${this._handleFocus}
|
|
2355
|
+
@keydown=${this._handleKeydown}
|
|
2356
|
+
/>
|
|
2357
|
+
|
|
2358
|
+
${this._renderActions()}
|
|
2359
|
+
</div>
|
|
2360
|
+
|
|
2361
|
+
${this._renderMorePanel()}
|
|
2362
|
+
|
|
2363
|
+
<div
|
|
2364
|
+
id=${this._listboxId}
|
|
2365
|
+
role="listbox"
|
|
2366
|
+
class=${this._cls("mono-tag-input-dropdown", "dropdown")}
|
|
2367
|
+
mono-dropdown
|
|
2368
|
+
style=${styleMap(this._dropdownStyle)}
|
|
2369
|
+
@scroll=${this._handleDropdownScroll}
|
|
2370
|
+
>
|
|
2371
|
+
${this._renderItems()}
|
|
2372
|
+
${this._renderLoadMore()}
|
|
2373
|
+
</div>
|
|
2374
|
+
|
|
2375
|
+
<div id=${this._messageId} class=${this.cssClass?.messageWrap ?? ""} mono-message-wrap>
|
|
2376
|
+
${this._renderHelper()}
|
|
2377
|
+
</div>
|
|
2378
|
+
</div>
|
|
2379
|
+
`;
|
|
2380
|
+
}
|
|
2381
|
+
focus(options) {
|
|
2382
|
+
this._inputEl?.focus(options);
|
|
2383
|
+
}
|
|
2384
|
+
blur() {
|
|
2385
|
+
this._inputEl?.blur();
|
|
2386
|
+
}
|
|
2387
|
+
/**
|
|
2388
|
+
* Open / close the suggestion panel. Mirrors `mono-select`'s API so anything
|
|
2389
|
+
* driving an editor generically — e.g. the data grid opening the focused
|
|
2390
|
+
* inline editor on `Enter` — can treat the two the same.
|
|
2391
|
+
*/
|
|
2392
|
+
/** Whether the suggestion panel is currently open. */
|
|
2393
|
+
get isOpen() {
|
|
2394
|
+
return this._open;
|
|
2395
|
+
}
|
|
2396
|
+
open() {
|
|
2397
|
+
if (this.disabled || this.readonly) return;
|
|
2398
|
+
this._open = true;
|
|
2399
|
+
this._inputEl?.focus();
|
|
2400
|
+
}
|
|
2401
|
+
close() {
|
|
2402
|
+
this._close();
|
|
2403
|
+
}
|
|
2404
|
+
toggle() {
|
|
2405
|
+
if (this._open) this.close();
|
|
2406
|
+
else this.open();
|
|
2407
|
+
}
|
|
2408
|
+
clearTags() {
|
|
2409
|
+
if (this.disabled || this.readonly) return;
|
|
2410
|
+
this._setValue(this._keepFloor([]), { emitClear: true });
|
|
2411
|
+
this._resetSearch();
|
|
2412
|
+
}
|
|
2413
|
+
addTag(value) {
|
|
2414
|
+
this._addValue(value);
|
|
2415
|
+
}
|
|
2416
|
+
removeTag(value) {
|
|
2417
|
+
this._removeValue(value);
|
|
2418
|
+
}
|
|
2419
|
+
/** Whether the slot regions render even when empty. Light: no (omit empty
|
|
2420
|
+
* regions). Shadow: yes — the native `<slot>`s must exist to project DSD
|
|
2421
|
+
* content + be scanned (hidden via `[mono-empty]` when empty). */
|
|
2422
|
+
get _slotsAlwaysRender() {
|
|
2423
|
+
return false;
|
|
2424
|
+
}
|
|
2425
|
+
_hasSlot(name) {
|
|
2426
|
+
return name === "label" ? this._hasLabelSlotState : this._hasHelperSlotState;
|
|
2427
|
+
}
|
|
2428
|
+
_setSlotState(name, has) {
|
|
2429
|
+
if (name === "label") this._hasLabelSlotState = has;
|
|
2430
|
+
else if (name === "list") this._hasListSlotState = has;
|
|
2431
|
+
else this._hasHelperSlotState = has;
|
|
2432
|
+
}
|
|
2433
|
+
/**
|
|
2434
|
+
* Slot outlet. Light build (default): a `data-mono-slot` placeholder the
|
|
2435
|
+
* captured light-DOM nodes are re-parented into when present, else the prop
|
|
2436
|
+
* `fallback`. Shadow build overrides this with a native `<slot name>` carrying
|
|
2437
|
+
* the fallback as native slot content.
|
|
2438
|
+
*/
|
|
2439
|
+
_slotOutlet(name, fallback = nothing) {
|
|
2440
|
+
return this._hasSlot(name) ? html`<span data-mono-slot=${name}></span>` : html`${fallback}`;
|
|
2441
|
+
}
|
|
2442
|
+
/**
|
|
2443
|
+
* Icon hook. Light build (default): the global `.mono-icon` / `i-mdi-*` UnoCSS
|
|
2444
|
+
* icon. Shadow overrides with inline SVG (UnoCSS can't reach a shadow root).
|
|
2445
|
+
*
|
|
2446
|
+
* Only the close glyph goes through here. The caret and the scroll chevrons
|
|
2447
|
+
* are inline SVG from `composables/field-icons`, shared with
|
|
2448
|
+
* `<mono-dropdown-table>` — see `_renderActions`.
|
|
2449
|
+
*/
|
|
2450
|
+
renderIcon(_name) {
|
|
2451
|
+
return html`<span class="mono-icon i-mdi-close" mono-icon aria-hidden="true"></span>`;
|
|
2452
|
+
}
|
|
2453
|
+
}
|
|
2454
|
+
__decorate([property({ type: String })], MonoTagInputCoreClass.prototype, "size", void 0);
|
|
2455
|
+
__decorate([property({ type: String })], MonoTagInputCoreClass.prototype, "color", void 0);
|
|
2456
|
+
__decorate([property({ type: String })], MonoTagInputCoreClass.prototype, "variant", void 0);
|
|
2457
|
+
__decorate([property({ attribute: false })], MonoTagInputCoreClass.prototype, "chip", void 0);
|
|
2458
|
+
__decorate([property({
|
|
2459
|
+
attribute: "model-value",
|
|
2460
|
+
reflect: false,
|
|
2461
|
+
hasChanged: arrayHasChanged
|
|
2462
|
+
})], MonoTagInputCoreClass.prototype, "modelValue", void 0);
|
|
2463
|
+
__decorate([property({
|
|
2464
|
+
attribute: false,
|
|
2465
|
+
hasChanged: arrayHasChanged
|
|
2466
|
+
})], MonoTagInputCoreClass.prototype, "value", void 0);
|
|
2467
|
+
__decorate([property({ type: String })], MonoTagInputCoreClass.prototype, "name", void 0);
|
|
2468
|
+
__decorate([property({ type: String })], MonoTagInputCoreClass.prototype, "label", void 0);
|
|
2469
|
+
__decorate([property({ type: String })], MonoTagInputCoreClass.prototype, "placeholder", void 0);
|
|
2470
|
+
__decorate([property({
|
|
2471
|
+
type: String,
|
|
2472
|
+
attribute: "helper-text"
|
|
2473
|
+
})], MonoTagInputCoreClass.prototype, "helperText", void 0);
|
|
2474
|
+
__decorate([property({
|
|
2475
|
+
type: String,
|
|
2476
|
+
attribute: "validation-state"
|
|
2477
|
+
})], MonoTagInputCoreClass.prototype, "validationState", void 0);
|
|
2478
|
+
__decorate([property({
|
|
2479
|
+
type: String,
|
|
2480
|
+
attribute: "validation-message"
|
|
2481
|
+
})], MonoTagInputCoreClass.prototype, "validationMessage", void 0);
|
|
2482
|
+
__decorate([property({
|
|
2483
|
+
type: String,
|
|
2484
|
+
attribute: "error-message"
|
|
2485
|
+
})], MonoTagInputCoreClass.prototype, "errorMessage", void 0);
|
|
2486
|
+
__decorate([property({
|
|
2487
|
+
type: String,
|
|
2488
|
+
attribute: "success-message"
|
|
2489
|
+
})], MonoTagInputCoreClass.prototype, "successMessage", void 0);
|
|
2490
|
+
__decorate([property({
|
|
2491
|
+
type: String,
|
|
2492
|
+
attribute: "aria-label"
|
|
2493
|
+
})], MonoTagInputCoreClass.prototype, "ariaLabelText", void 0);
|
|
2494
|
+
__decorate([property({
|
|
2495
|
+
reflect: true,
|
|
2496
|
+
converter: booleanStringConverter
|
|
2497
|
+
})], MonoTagInputCoreClass.prototype, "disabled", void 0);
|
|
2498
|
+
__decorate([property({
|
|
2499
|
+
reflect: true,
|
|
2500
|
+
converter: booleanStringConverter
|
|
2501
|
+
})], MonoTagInputCoreClass.prototype, "readonly", void 0);
|
|
2502
|
+
__decorate([property({
|
|
2503
|
+
reflect: true,
|
|
2504
|
+
converter: booleanStringConverter
|
|
2505
|
+
})], MonoTagInputCoreClass.prototype, "required", void 0);
|
|
2506
|
+
__decorate([property({
|
|
2507
|
+
reflect: true,
|
|
2508
|
+
converter: booleanStringConverter
|
|
2509
|
+
})], MonoTagInputCoreClass.prototype, "clearable", void 0);
|
|
2510
|
+
__decorate([property({
|
|
2511
|
+
attribute: "allow-custom",
|
|
2512
|
+
reflect: true,
|
|
2513
|
+
converter: booleanStringConverter
|
|
2514
|
+
})], MonoTagInputCoreClass.prototype, "allowCustom", void 0);
|
|
2515
|
+
__decorate([property({
|
|
2516
|
+
attribute: "max",
|
|
2517
|
+
converter: numberStringConverter
|
|
2518
|
+
})], MonoTagInputCoreClass.prototype, "max", void 0);
|
|
2519
|
+
__decorate([property({
|
|
2520
|
+
attribute: "min",
|
|
2521
|
+
converter: numberStringConverter
|
|
2522
|
+
})], MonoTagInputCoreClass.prototype, "min", void 0);
|
|
2523
|
+
__decorate([property({
|
|
2524
|
+
reflect: true,
|
|
2525
|
+
converter: booleanStringConverter
|
|
2526
|
+
})], MonoTagInputCoreClass.prototype, "checkable", void 0);
|
|
2527
|
+
__decorate([property({
|
|
2528
|
+
attribute: "select-all",
|
|
2529
|
+
reflect: true,
|
|
2530
|
+
converter: booleanStringConverter
|
|
2531
|
+
})], MonoTagInputCoreClass.prototype, "selectAll", void 0);
|
|
2532
|
+
__decorate([property({
|
|
2533
|
+
type: String,
|
|
2534
|
+
attribute: "select-all-label",
|
|
2535
|
+
reflect: true
|
|
2536
|
+
})], MonoTagInputCoreClass.prototype, "selectAllLabel", void 0);
|
|
2537
|
+
__decorate([property({
|
|
2538
|
+
attribute: "group-select-all",
|
|
2539
|
+
reflect: true,
|
|
2540
|
+
converter: booleanStringConverter
|
|
2541
|
+
})], MonoTagInputCoreClass.prototype, "groupSelectAll", void 0);
|
|
2542
|
+
__decorate([property({
|
|
2543
|
+
attribute: "max-visible",
|
|
2544
|
+
converter: numberStringConverter
|
|
2545
|
+
})], MonoTagInputCoreClass.prototype, "maxVisible", void 0);
|
|
2546
|
+
__decorate([property({
|
|
2547
|
+
attribute: "min-visible",
|
|
2548
|
+
converter: numberStringConverter
|
|
2549
|
+
})], MonoTagInputCoreClass.prototype, "minVisible", void 0);
|
|
2550
|
+
__decorate([property({
|
|
2551
|
+
attribute: false,
|
|
2552
|
+
hasChanged: arrayHasChanged
|
|
2553
|
+
})], MonoTagInputCoreClass.prototype, "items", void 0);
|
|
2554
|
+
__decorate([property({ attribute: false })], MonoTagInputCoreClass.prototype, "dataSource", void 0);
|
|
2555
|
+
__decorate([property({
|
|
2556
|
+
attribute: "immediate",
|
|
2557
|
+
reflect: true,
|
|
2558
|
+
converter: booleanStringConverter
|
|
2559
|
+
})], MonoTagInputCoreClass.prototype, "immediate", void 0);
|
|
2560
|
+
__decorate([property({
|
|
2561
|
+
attribute: "load-more",
|
|
2562
|
+
reflect: true
|
|
2563
|
+
})], MonoTagInputCoreClass.prototype, "loadMore", void 0);
|
|
2564
|
+
__decorate([property({
|
|
2565
|
+
attribute: "page-size",
|
|
2566
|
+
reflect: true,
|
|
2567
|
+
type: Number
|
|
2568
|
+
})], MonoTagInputCoreClass.prototype, "pageSize", void 0);
|
|
2569
|
+
__decorate([property({ attribute: false })], MonoTagInputCoreClass.prototype, "dropdown", void 0);
|
|
2570
|
+
__decorate([property({
|
|
2571
|
+
attribute: "dropdown-height",
|
|
2572
|
+
reflect: true
|
|
2573
|
+
})], MonoTagInputCoreClass.prototype, "dropdownHeight", void 0);
|
|
2574
|
+
__decorate([property({
|
|
2575
|
+
attribute: "dropdown-max-height",
|
|
2576
|
+
reflect: true
|
|
2577
|
+
})], MonoTagInputCoreClass.prototype, "dropdownMaxHeight", void 0);
|
|
2578
|
+
__decorate([property({ converter: booleanStringConverter })], MonoTagInputCoreClass.prototype, "flip", void 0);
|
|
2579
|
+
__decorate([property({ converter: booleanStringConverter })], MonoTagInputCoreClass.prototype, "shift", void 0);
|
|
2580
|
+
__decorate([property({
|
|
2581
|
+
type: String,
|
|
2582
|
+
attribute: "key-value",
|
|
2583
|
+
reflect: true
|
|
2584
|
+
})], MonoTagInputCoreClass.prototype, "keyValue", void 0);
|
|
2585
|
+
__decorate([property({ attribute: false })], MonoTagInputCoreClass.prototype, "displayValue", void 0);
|
|
2586
|
+
__decorate([property({ attribute: false })], MonoTagInputCoreClass.prototype, "displayGroup", void 0);
|
|
2587
|
+
__decorate([property({
|
|
2588
|
+
type: String,
|
|
2589
|
+
attribute: "group-key",
|
|
2590
|
+
reflect: true
|
|
2591
|
+
})], MonoTagInputCoreClass.prototype, "groupKey", void 0);
|
|
2592
|
+
__decorate([property({
|
|
2593
|
+
type: String,
|
|
2594
|
+
attribute: "group-items",
|
|
2595
|
+
reflect: true
|
|
2596
|
+
})], MonoTagInputCoreClass.prototype, "groupItems", void 0);
|
|
2597
|
+
__decorate([property({
|
|
2598
|
+
attribute: "group",
|
|
2599
|
+
reflect: true,
|
|
2600
|
+
converter: booleanStringConverter
|
|
2601
|
+
})], MonoTagInputCoreClass.prototype, "group", void 0);
|
|
2602
|
+
__decorate([property({
|
|
2603
|
+
attribute: "group-sticky",
|
|
2604
|
+
reflect: true,
|
|
2605
|
+
converter: booleanStringConverter
|
|
2606
|
+
})], MonoTagInputCoreClass.prototype, "groupSticky", void 0);
|
|
2607
|
+
__decorate([property({
|
|
2608
|
+
attribute: "searchable",
|
|
2609
|
+
reflect: true,
|
|
2610
|
+
converter: booleanStringConverter
|
|
2611
|
+
})], MonoTagInputCoreClass.prototype, "searchable", void 0);
|
|
2612
|
+
__decorate([property({
|
|
2613
|
+
attribute: "stay-open",
|
|
2614
|
+
reflect: true,
|
|
2615
|
+
converter: booleanStringConverter
|
|
2616
|
+
})], MonoTagInputCoreClass.prototype, "stayOpen", void 0);
|
|
2617
|
+
__decorate([property({ attribute: "search-value" })], MonoTagInputCoreClass.prototype, "searchValue", void 0);
|
|
2618
|
+
__decorate([property({
|
|
2619
|
+
type: String,
|
|
2620
|
+
attribute: "search-operation"
|
|
2621
|
+
})], MonoTagInputCoreClass.prototype, "searchOperation", void 0);
|
|
2622
|
+
__decorate([property({
|
|
2623
|
+
attribute: "search-debounce",
|
|
2624
|
+
type: Number
|
|
2625
|
+
})], MonoTagInputCoreClass.prototype, "searchDebounce", void 0);
|
|
2626
|
+
__decorate([property({ attribute: false })], MonoTagInputCoreClass.prototype, "cssClass", void 0);
|
|
2627
|
+
__decorate([property({ attribute: false })], MonoTagInputCoreClass.prototype, "cssClassName", void 0);
|
|
2628
|
+
__decorate([state()], MonoTagInputCoreClass.prototype, "_inputValue", void 0);
|
|
2629
|
+
__decorate([state()], MonoTagInputCoreClass.prototype, "_open", void 0);
|
|
2630
|
+
__decorate([state()], MonoTagInputCoreClass.prototype, "_activeIndex", void 0);
|
|
2631
|
+
__decorate([state()], MonoTagInputCoreClass.prototype, "_moreOpen", void 0);
|
|
2632
|
+
__decorate([state(), state()], MonoTagInputCoreClass.prototype, "_selectAllPending", void 0);
|
|
2633
|
+
__decorate([state()], MonoTagInputCoreClass.prototype, "_hasLabelSlotState", void 0);
|
|
2634
|
+
__decorate([state()], MonoTagInputCoreClass.prototype, "_hasHelperSlotState", void 0);
|
|
2635
|
+
__decorate([query(".mono-tag-input-native")], MonoTagInputCoreClass.prototype, "_inputEl", void 0);
|
|
2636
|
+
__decorate([state()], MonoTagInputCoreClass.prototype, "_hasListSlotState", void 0);
|
|
2637
|
+
__decorate([property({ type: String })], MonoTagInputCoreClass.prototype, "width", void 0);
|
|
2638
|
+
__decorate([property({ type: String })], MonoTagInputCoreClass.prototype, "height", void 0);
|
|
2639
|
+
__decorate([property({
|
|
2640
|
+
type: String,
|
|
2641
|
+
attribute: "min-width"
|
|
2642
|
+
})], MonoTagInputCoreClass.prototype, "minWidth", void 0);
|
|
2643
|
+
__decorate([property({
|
|
2644
|
+
type: String,
|
|
2645
|
+
attribute: "max-width"
|
|
2646
|
+
})], MonoTagInputCoreClass.prototype, "maxWidth", void 0);
|
|
2647
|
+
__decorate([property({
|
|
2648
|
+
type: String,
|
|
2649
|
+
attribute: "min-height"
|
|
2650
|
+
})], MonoTagInputCoreClass.prototype, "minHeight", void 0);
|
|
2651
|
+
__decorate([property({
|
|
2652
|
+
type: String,
|
|
2653
|
+
attribute: "max-height"
|
|
2654
|
+
})], MonoTagInputCoreClass.prototype, "maxHeight", void 0);
|
|
2655
|
+
return MonoTagInputCoreClass;
|
|
2656
|
+
};
|
|
2657
|
+
//#endregion
|
|
2658
|
+
//#region src/components/tag-input/tag-input.css?raw
|
|
2659
|
+
var tag_input_default = "/* =========================================================================\r\n mono-tag-input — a port of Basecoat's multi-select combobox: `.combobox-chips`\r\n (the field), `.combobox-chip` (+ `-remove`) and the `.combobox [data-popover]`\r\n list (basecoat-css@1.0.2, vega style), on the `.field` / `.label` chrome the\r\n ported input already carries.\r\n\r\n Styled by ATTRIBUTE, like Basecoat — and the attributes mirror the element's\r\n props one for one, so hand-written markup reads like the Lit / Vue tag:\r\n\r\n <mono-tag-input size=\"sm\" color=\"danger\" variant=\"filled\" label=\"Tags\">\r\n <div mono-tag-input mono-size=\"sm\" mono-color=\"danger\" mono-variant=\"filled\">\r\n <label mono-label>Tags</label>\r\n <div mono-field>\r\n <div mono-chip mono-removable><span mono-chip-main><span mono-chip-content>\r\n <span mono-chip-label>Vue</span><button mono-chip-close>…</button></span></span></div>\r\n <input mono-native /> <div mono-actions><span mono-arrow>…</span></div>\r\n </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 the STATES\r\n `mono-open` / `mono-more-open`; the old classes (`.mono-tag-input.sm.open`) are\r\n still emitted as inert hooks until 2.0 but no rule here reads them. The tag\r\n chips are NOT `.mono-chip`s any more: they are Basecoat combobox chips, painted\r\n here (`[mono-tag-input] [mono-chip]`), and chip.css never sees them.\r\n\r\n Selector map (ours ≡ upstream):\r\n [mono-tag-input] ≡ .field (gap-3, as margins — see the root rule) + .combobox (position: relative)\r\n [mono-tag-input] > [mono-label] ≡ .field > label / .label\r\n [mono-tag-input] > [mono-field] ≡ .combobox-chips (min-h-9 gap-1.5 rounded-md border-input px-1.5 py-1.5 text-sm shadow-xs)\r\n [mono-field] > [mono-native] ≡ .combobox-chips > input[role='combobox'] (min-w-16 flex-1, borderless)\r\n [mono-field] [mono-chip] > [mono-chip-main] ≡ .combobox-chip (h-5.5 gap-1 rounded-sm bg-muted px-1.5 text-xs font-medium)\r\n [mono-chip] [mono-chip-close] ≡ .combobox-chip-remove (-ms-1 opacity-50 hover:100, svg size-3.5)\r\n [mono-chip][mono-more] ≡ EXTENSION (the \"+N more\" counter chip, same box)\r\n [mono-actions] > [mono-arrow] > svg ≡ .combobox-trigger-icon (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-actions] > [mono-scroll] ≡ EXTENSION (the inline strip's ‹ › pager, same box)\r\n [mono-dropdown] ≡ .combobox [data-popover] + [role='listbox'] (bg-popover ring-1 rounded-md shadow-md, max-h-72 p-1 scroll)\r\n [mono-item] ≡ .combobox [role='option'] (gap-2 rounded-sm py-1.5 ps-2 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, unless the row has its own checkbox\r\n [mono-group] ≡ .combobox [role='heading'] (px-2 py-1.5 text-xs text-muted-foreground)\r\n [mono-select-all] ≡ EXTENSION (a sticky option row over the list)\r\n [mono-more-panel] ≡ [data-popover] holding the overflow chips\r\n [mono-empty-row] ≡ [role='listbox']::before (py-6 text-center text-sm)\r\n [mono-message-wrap] > [mono-message] ≡ .field > p / .field [role='alert']\r\n [mono-validation-state=\"invalid\"] ≡ .combobox-chips:has([aria-invalid=true]) + .field[data-invalid]\r\n [mono-validation-state=\"valid|warning\"] ≡ EXTENSION (the invalid pattern in --success / --warning)\r\n [mono-size=\"xs|sm|lg|xl|xxl\"] ≡ EXTENSION (the --mono-control-height-* ladder)\r\n [mono-variant=\"filled\"] ≡ EXTENSION (luma's .combobox-chips)\r\n [mono-variant=\"underlined\"] ≡ EXTENSION (sera's .combobox-chips: bottom edge only, no ring)\r\n\r\n Inner parts: [mono-label] (+ [mono-required-mark]), [mono-field] (+ [mono-inline],\r\n [mono-typing]), [mono-chip-strip], [mono-chip] (+ [mono-removable], [mono-more],\r\n [mono-chip-color=\"…\"]) > [mono-chip-main] > [mono-chip-content] > [mono-chip-dot] /\r\n [mono-chip-label] / [mono-chip-close] > [mono-icon], [mono-native], [mono-actions] >\r\n [mono-scroll=\"prev|next\"] (+ [mono-idle]) / [mono-clear] > [mono-icon] / [mono-arrow],\r\n [mono-dropdown], [mono-select-all] (+ [mono-loading]), [mono-item] (+ [mono-active],\r\n [mono-selected], [mono-disabled], [mono-check], [mono-level=\"n\"]) > [mono-check-box] /\r\n [mono-item-text] > [mono-item-title] / [mono-item-sub], [mono-group] (+ [mono-level],\r\n [mono-sticky], [mono-toggle], [mono-selected]) > [mono-group-label], [mono-empty-row],\r\n [mono-load-more] (+ [mono-loading]), [mono-list-slot], [mono-more-panel],\r\n [mono-message-wrap] > [mono-message=\"helper|valid|invalid|warning\"]. The shadow build\r\n marks an unassigned slot wrapper [mono-empty].\r\n\r\n THE PANELS ARE PORTALED (light build): [mono-dropdown] and [mono-more-panel] move\r\n into a `<div data-mono-popup-portal>` under <body> while open, and the portal\r\n mirrors the wrapper's class AND mono-* attributes, so every rule here is scoped\r\n under `[mono-tag-input]` and never relies on the panel being inside the field.\r\n\r\n FLAVORS set the same knobs as mono-input, renamed `--mono-tag-input-*`, plus the\r\n select's panel / option / group set (`--mono-tag-input-dropdown-*`,\r\n `--mono-tag-input-option-*`, `--mono-tag-input-group-*`) and the chip set\r\n (`--mono-tag-input-chip-{radius,bg,color,font-size,font-weight}`). Every fallback\r\n here is vega's value (`node scripts/basecoat-styles.mjs --varying \"^\\.combobox\"`).\r\n ========================================================================= */\r\n\r\nmono-tag-input {\r\n display: block;\r\n}\r\n\r\n[mono-tag-input] {\r\n /* ── palette: each slot is a public knob over a Basecoat token ─────────── */\r\n --_mono-tag-input-text: var(--mono-tag-input-color, var(--mono-tag-input-text, var(--foreground)));\r\n --_mono-tag-input-placeholder: var(--mono-tag-input-placeholder, var(--muted-foreground));\r\n --_mono-tag-input-muted: var(--mono-tag-input-muted, var(--muted-foreground));\r\n --_mono-tag-input-primary: var(--mono-tag-input-primary, var(--ring));\r\n --_mono-tag-input-secondary: var(--mono-tag-input-secondary, var(--muted-foreground));\r\n --_mono-tag-input-success: var(--mono-tag-input-success, var(--success));\r\n --_mono-tag-input-danger: var(--mono-tag-input-danger, var(--destructive));\r\n --_mono-tag-input-warning: var(--mono-tag-input-warning, var(--warning));\r\n --_mono-tag-input-info: var(--mono-tag-input-info, var(--info));\r\n --_mono-tag-input-teal: var(--mono-tag-input-teal, var(--teal));\r\n --_mono-tag-input-purple: var(--mono-tag-input-purple, var(--purple));\r\n --_mono-tag-input-neutral: var(--mono-tag-input-neutral, var(--neutral));\r\n --_mono-tag-input-dark: var(--mono-tag-input-dark, var(--dark));\r\n --_mono-tag-input-valid: var(--mono-tag-input-valid, var(--success));\r\n --_mono-tag-input-invalid: var(--mono-tag-input-invalid, var(--destructive));\r\n\r\n /* ── the painted result — three tiers, base = .combobox-chips (vega) ──── */\r\n --_mono-tag-input-ring-color: var(--mono-tag-input-ring-color, var(--mono-tag-input-focus-color, var(--_mono-tag-input-ring-color-preset, var(--_mono-tag-input-primary))));\r\n --_mono-tag-input-ring-width: var(--mono-tag-input-ring-width, var(--_mono-tag-input-ring-width-preset, var(--mono-ring-width)));\r\n --_mono-tag-input-ring-alpha: var(--mono-tag-input-ring-alpha, var(--mono-ring-alpha));\r\n --_mono-tag-input-border-color: var(--mono-tag-input-rest-border, var(--mono-tag-input-border-color, var(--mono-tag-input-border, var(--_mono-tag-input-border-color-preset, var(--input)))));\r\n --_mono-tag-input-bg: var(--mono-tag-input-bg, var(--mono-tag-input-surface, var(--_mono-tag-input-bg-preset, var(--mono-mode-surface))));\r\n --_mono-tag-input-shadow: var(--mono-tag-input-shadow, var(--_mono-tag-input-shadow-preset, 0 0 #0000));\r\n --_mono-tag-input-icon: var(--mono-tag-input-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-tag-input>` that names no size renders exactly like size=\"md\".\r\n basecoat@1.0.2 styles/vega.css .combobox-chips — min-h-9 gap-1.5 rounded-md\r\n px-1.5 py-1.5 text-sm; .combobox-chip h-5.5 ── */\r\n --_mono-tag-input-height: var(--mono-tag-input-height-md, var(--mono-control-height-md));\r\n --_mono-tag-input-radius: var(--mono-tag-input-radius-md, var(--_mono-tag-input-radius-preset, var(--mono-tag-input-radius, var(--mono-radius-md))));\r\n --_mono-tag-input-padding-x: var(--mono-tag-input-padding-x-md, var(--mono-tag-input-padding-x, var(--_mono-tag-input-padding-x-preset, calc(var(--mono-spacing) * 1.5))));\r\n --_mono-tag-input-padding-y: var(--mono-tag-input-padding-y-md, var(--mono-tag-input-padding-y, calc(var(--mono-spacing) * 1.5)));\r\n --_mono-tag-input-gap: var(--mono-tag-input-chip-gap, calc(var(--mono-spacing) * 1.5));\r\n --_mono-tag-input-font-size: var(--mono-tag-input-font-md, var(--mono-text-sm));\r\n --_mono-tag-input-line-height: var(--mono-tag-input-line-height, var(--mono-tag-input-line-height-md, var(--mono-text-sm--lh)));\r\n --_mono-tag-input-chip-height: var(--mono-tag-input-chip-height-md, min(calc(var(--mono-spacing) * 5.5), var(--_mono-tag-input-chip-fit)));\r\n /* The room one row of chips has: the field's height minus its block padding and borders. Each\r\n size's DEFAULT chip height is capped by it, so the rule \"chip h + 2·py + 2px ≤ token\" holds\r\n under ANY control ladder — a dense flavor (mira: xs 20px) shrinks the chip instead of growing\r\n an empty field past the token. An explicit `--mono-tag-input-chip-height-*` is not capped. */\r\n --_mono-tag-input-chip-fit: calc(var(--_mono-tag-input-height) - 2 * var(--_mono-tag-input-padding-y) - 2 * var(--mono-border-width));\r\n --_mono-tag-input-chip-font-size: var(--mono-tag-input-chip-font-size, var(--mono-text-xs));\r\n --_mono-tag-input-chip-line-height: var(--mono-tag-input-chip-line-height, var(--mono-text-xs--lh));\r\n --_mono-tag-input-action: calc(var(--mono-spacing) * 6);\r\n --_mono-tag-input-clear-glyph: calc(var(--mono-spacing) * 3.5);\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 field, above the\r\n message — instead of a flex container's content-box top (see select.css) */\r\n --_mono-tag-input-gap-y: var(--mono-tag-input-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-tag-input-text);\r\n}\r\n\r\n[mono-tag-input],\r\n[mono-tag-input] *,\r\n[mono-tag-input] *::before,\r\n[mono-tag-input] *::after {\r\n box-sizing: border-box;\r\n}\r\n\r\n[mono-tag-input] :is([mono-label], [mono-message])[mono-empty] {\r\n display: none;\r\n}\r\n\r\n/* =========================================\r\n Sizes — an EMPTY field's painted height IS the token (tests/perf/field-heights);\r\n a second row of chips grows it. Each step keeps one row of chips + its block\r\n padding under the token: chip h + 2·py + 2px ≤ token.\r\n ========================================= */\r\n\r\n[mono-tag-input][mono-size=\"xs\"] {\r\n --_mono-tag-input-height: var(--mono-tag-input-height-xs, var(--mono-control-height-xs));\r\n --_mono-tag-input-radius: var(--mono-tag-input-radius-xs, var(--_mono-tag-input-radius-preset, var(--mono-tag-input-radius, var(--mono-radius-md))));\r\n --_mono-tag-input-padding-x: var(--mono-tag-input-padding-x-xs, var(--mono-tag-input-padding-x, var(--_mono-tag-input-padding-x-preset, var(--mono-spacing))));\r\n --_mono-tag-input-padding-y: var(--mono-tag-input-padding-y-xs, var(--mono-tag-input-padding-y, calc(var(--mono-spacing) * 0.5)));\r\n --_mono-tag-input-gap: var(--mono-tag-input-chip-gap, var(--mono-spacing));\r\n --_mono-tag-input-font-size: var(--mono-tag-input-font-xs, var(--mono-text-xs));\r\n --_mono-tag-input-line-height: var(--mono-tag-input-line-height, var(--mono-tag-input-line-height-xs, var(--mono-text-xs--lh)));\r\n --_mono-tag-input-chip-height: var(--mono-tag-input-chip-height-xs, min(calc(var(--mono-spacing) * 4.5), var(--_mono-tag-input-chip-fit)));\r\n --_mono-tag-input-icon: var(--mono-tag-input-icon-size, calc(var(--mono-spacing) * 3.5));\r\n --_mono-tag-input-action: calc(var(--mono-spacing) * 4);\r\n --_mono-tag-input-clear-glyph: calc(var(--mono-spacing) * 3);\r\n}\r\n\r\n[mono-tag-input][mono-size=\"sm\"] {\r\n --_mono-tag-input-height: var(--mono-tag-input-height-sm, var(--mono-control-height-sm));\r\n --_mono-tag-input-radius: var(--mono-tag-input-radius-sm, var(--_mono-tag-input-radius-preset, var(--mono-tag-input-radius, var(--mono-radius-md))));\r\n --_mono-tag-input-padding-x: var(--mono-tag-input-padding-x-sm, var(--mono-tag-input-padding-x, var(--_mono-tag-input-padding-x-preset, var(--mono-spacing))));\r\n --_mono-tag-input-padding-y: var(--mono-tag-input-padding-y-sm, var(--mono-tag-input-padding-y, var(--mono-spacing)));\r\n --_mono-tag-input-gap: var(--mono-tag-input-chip-gap, var(--mono-spacing));\r\n --_mono-tag-input-font-size: var(--mono-tag-input-font-sm, var(--mono-tag-input-font-md, var(--mono-text-sm)));\r\n --_mono-tag-input-line-height: var(--mono-tag-input-line-height, var(--mono-tag-input-line-height-sm, var(--mono-text-sm--lh)));\r\n --_mono-tag-input-chip-height: var(--mono-tag-input-chip-height-sm, min(calc(var(--mono-spacing) * 5), var(--_mono-tag-input-chip-fit)));\r\n --_mono-tag-input-action: calc(var(--mono-spacing) * 5);\r\n}\r\n\r\n[mono-tag-input][mono-size=\"lg\"] {\r\n --_mono-tag-input-height: var(--mono-tag-input-height-lg, var(--mono-control-height-lg));\r\n --_mono-tag-input-radius: var(--mono-tag-input-radius-lg, var(--_mono-tag-input-radius-preset, var(--mono-tag-input-radius, var(--mono-radius-md))));\r\n --_mono-tag-input-padding-x: var(--mono-tag-input-padding-x-lg, var(--mono-tag-input-padding-x, var(--_mono-tag-input-padding-x-preset, calc(var(--mono-spacing) * 1.5))));\r\n --_mono-tag-input-padding-y: var(--mono-tag-input-padding-y-lg, var(--mono-tag-input-padding-y, calc(var(--mono-spacing) * 1.5)));\r\n --_mono-tag-input-font-size: var(--mono-tag-input-font-lg, var(--mono-tag-input-font-md, var(--mono-text-sm)));\r\n --_mono-tag-input-line-height: var(--mono-tag-input-line-height, var(--mono-tag-input-line-height-lg, var(--mono-text-sm--lh)));\r\n --_mono-tag-input-chip-height: var(--mono-tag-input-chip-height-lg, min(calc(var(--mono-spacing) * 6), var(--_mono-tag-input-chip-fit)));\r\n}\r\n\r\n[mono-tag-input][mono-size=\"xl\"] {\r\n --_mono-tag-input-height: var(--mono-tag-input-height-xl, var(--mono-control-height-xl));\r\n --_mono-tag-input-radius: var(--mono-tag-input-radius-xl, var(--_mono-tag-input-radius-preset, var(--mono-tag-input-radius, var(--mono-radius-md))));\r\n --_mono-tag-input-padding-x: var(--mono-tag-input-padding-x-xl, var(--mono-tag-input-padding-x, var(--_mono-tag-input-padding-x-preset, calc(var(--mono-spacing) * 2))));\r\n --_mono-tag-input-padding-y: var(--mono-tag-input-padding-y-xl, var(--mono-tag-input-padding-y, calc(var(--mono-spacing) * 2)));\r\n --_mono-tag-input-gap: var(--mono-tag-input-chip-gap, calc(var(--mono-spacing) * 2));\r\n --_mono-tag-input-font-size: var(--mono-tag-input-font-xl, var(--mono-text-base));\r\n --_mono-tag-input-line-height: var(--mono-tag-input-line-height, var(--mono-tag-input-line-height-xl, var(--mono-text-base--lh)));\r\n --_mono-tag-input-chip-height: var(--mono-tag-input-chip-height-xl, min(calc(var(--mono-spacing) * 6.5), var(--_mono-tag-input-chip-fit)));\r\n --_mono-tag-input-chip-font-size: var(--mono-tag-input-chip-font-size, var(--mono-text-sm));\r\n --_mono-tag-input-chip-line-height: var(--mono-tag-input-chip-line-height, var(--mono-text-sm--lh));\r\n --_mono-tag-input-icon: var(--mono-tag-input-icon-size, calc(var(--mono-spacing) * 5));\r\n --_mono-tag-input-action: calc(var(--mono-spacing) * 7);\r\n --_mono-tag-input-clear-glyph: calc(var(--mono-spacing) * 4);\r\n}\r\n\r\n[mono-tag-input][mono-size=\"xxl\"] {\r\n --_mono-tag-input-height: var(--mono-tag-input-height-xxl, var(--mono-control-height-xxl));\r\n --_mono-tag-input-radius: var(--mono-tag-input-radius-xxl, var(--_mono-tag-input-radius-preset, var(--mono-tag-input-radius, var(--mono-radius-md))));\r\n --_mono-tag-input-padding-x: var(--mono-tag-input-padding-x-xxl, var(--mono-tag-input-padding-x, var(--_mono-tag-input-padding-x-preset, calc(var(--mono-spacing) * 2.5))));\r\n --_mono-tag-input-padding-y: var(--mono-tag-input-padding-y-xxl, var(--mono-tag-input-padding-y, calc(var(--mono-spacing) * 2)));\r\n --_mono-tag-input-gap: var(--mono-tag-input-chip-gap, calc(var(--mono-spacing) * 2));\r\n --_mono-tag-input-font-size: var(--mono-tag-input-font-xxl, var(--mono-text-lg));\r\n --_mono-tag-input-line-height: var(--mono-tag-input-line-height, var(--mono-tag-input-line-height-xxl, var(--mono-text-lg--lh)));\r\n --_mono-tag-input-chip-height: var(--mono-tag-input-chip-height-xxl, min(calc(var(--mono-spacing) * 7), var(--_mono-tag-input-chip-fit)));\r\n --_mono-tag-input-chip-font-size: var(--mono-tag-input-chip-font-size, var(--mono-text-sm));\r\n --_mono-tag-input-chip-line-height: var(--mono-tag-input-chip-line-height, var(--mono-text-sm--lh));\r\n --_mono-tag-input-icon: var(--mono-tag-input-icon-size, calc(var(--mono-spacing) * 5));\r\n --_mono-tag-input-action: calc(var(--mono-spacing) * 8);\r\n --_mono-tag-input-clear-glyph: calc(var(--mono-spacing) * 4);\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 .combobox-chips — rounded-md border border-input\r\n bg-transparent shadow-xs (dark:bg-input/30 via --mono-mode-surface) */\r\n[mono-tag-input]:is(:not([mono-variant]), [mono-variant=\"outlined\"]) {\r\n --_mono-tag-input-bg-preset: var(--mono-tag-input-outline-bg);\r\n --_mono-tag-input-border-color-preset: var(--mono-tag-input-outline-border-color);\r\n --_mono-tag-input-side-border-color-preset: var(--mono-tag-input-outline-side-border-color);\r\n --_mono-tag-input-shadow-preset: var(--mono-tag-input-outline-shadow, var(--mono-shadow-xs));\r\n --_mono-tag-input-ring-width-preset: var(--mono-tag-input-outline-ring-width);\r\n --_mono-tag-input-radius-preset: var(--mono-tag-input-outline-radius);\r\n --_mono-tag-input-padding-x-preset: var(--mono-tag-input-outline-padding-x);\r\n}\r\n\r\n/* EXTENSION — filled ≡ basecoat@1.0.2 styles/luma.css .combobox-chips */\r\n[mono-tag-input][mono-variant=\"filled\"] {\r\n --_mono-tag-input-bg-preset: var(--mono-tag-input-filled-bg, color-mix(in oklab, var(--input) 50%, transparent));\r\n --_mono-tag-input-border-color-preset: transparent;\r\n --_mono-tag-input-shadow-preset: 0 0 #0000;\r\n}\r\n\r\n/* EXTENSION — underlined ≡ basecoat@1.0.2 styles/sera.css .combobox-chips */\r\n[mono-tag-input][mono-variant=\"underlined\"] {\r\n --_mono-tag-input-bg-preset: transparent;\r\n --_mono-tag-input-side-border-color-preset: transparent;\r\n --_mono-tag-input-shadow-preset: 0 0 #0000;\r\n --_mono-tag-input-ring-width-preset: 0px;\r\n --_mono-tag-input-radius-preset: 0;\r\n --_mono-tag-input-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-tag-input]:is(:not([mono-color]), [mono-color=\"primary\"]) {\r\n --_mono-tag-input-ring-color-preset: var(--_mono-tag-input-primary);\r\n}\r\n[mono-tag-input][mono-color=\"secondary\"] {\r\n --_mono-tag-input-ring-color-preset: var(--_mono-tag-input-secondary);\r\n}\r\n[mono-tag-input][mono-color=\"success\"] {\r\n --_mono-tag-input-ring-color-preset: var(--_mono-tag-input-success);\r\n}\r\n[mono-tag-input][mono-color=\"danger\"] {\r\n --_mono-tag-input-ring-color-preset: var(--_mono-tag-input-danger);\r\n}\r\n[mono-tag-input][mono-color=\"warning\"] {\r\n --_mono-tag-input-ring-color-preset: var(--_mono-tag-input-warning);\r\n}\r\n[mono-tag-input][mono-color=\"info\"] {\r\n --_mono-tag-input-ring-color-preset: var(--_mono-tag-input-info);\r\n}\r\n[mono-tag-input][mono-color=\"teal\"] {\r\n --_mono-tag-input-ring-color-preset: var(--_mono-tag-input-teal);\r\n}\r\n[mono-tag-input][mono-color=\"purple\"] {\r\n --_mono-tag-input-ring-color-preset: var(--_mono-tag-input-purple);\r\n}\r\n[mono-tag-input][mono-color=\"neutral\"] {\r\n --_mono-tag-input-ring-color-preset: var(--_mono-tag-input-neutral);\r\n}\r\n[mono-tag-input][mono-color=\"dark\"] {\r\n --_mono-tag-input-ring-color-preset: var(--_mono-tag-input-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-tag-input] > [mono-label] {\r\n display: flex;\r\n align-items: center;\r\n width: fit-content;\r\n margin: 0 0 var(--_mono-tag-input-gap-y);\r\n gap: var(--mono-tag-input-label-gap, calc(var(--mono-spacing) * 2));\r\n font-size: var(--mono-tag-input-label-font-size, var(--mono-text-sm));\r\n line-height: var(--mono-tag-input-label-line-height, 1);\r\n font-weight: var(--mono-tag-input-label-font-weight, var(--mono-label-font-weight, var(--mono-font-weight-medium)));\r\n text-transform: var(--mono-tag-input-label-text-transform, none);\r\n letter-spacing: var(--mono-tag-input-label-letter-spacing, normal);\r\n color: var(--_mono-tag-input-text);\r\n user-select: none;\r\n}\r\n\r\n[mono-tag-input][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-tag-input][mono-validation-state=\"invalid\"] > [mono-label] {\r\n color: var(--_mono-tag-input-invalid);\r\n}\r\n\r\n[mono-tag-input] [mono-required-mark] {\r\n color: var(--_mono-tag-input-danger);\r\n}\r\n\r\n/* =========================================\r\n The field — the chip box\r\n ========================================= */\r\n\r\n/* basecoat@1.0.2 components/combobox.css .combobox-chips — flex w-full min-w-0\r\n flex-wrap items-center */\r\n/* basecoat@1.0.2 styles/vega.css .combobox-chips — min-h-9 gap-1.5 rounded-md\r\n border border-input bg-transparent bg-clip-padding px-1.5 py-1.5 text-sm\r\n shadow-xs transition-[color,box-shadow] focus-within:border-ring\r\n focus-within:ring-3 focus-within:ring-ring/50 has-[[aria-invalid=true]]:…;\r\n mono: `--tw-ring-*` flattened to the ring + shadow slots, the min-height is\r\n the control token, the side edges read their own slot */\r\n[mono-tag-input] > [mono-field] {\r\n --_mono-tag-input-bc: var(--_mono-tag-input-border-color);\r\n --_mono-tag-input-side-bc: var(--mono-tag-input-side-border-color, var(--_mono-tag-input-side-border-color-preset, var(--_mono-tag-input-bc)));\r\n --_mono-tag-input-ring: 0 0 #0000;\r\n\r\n position: relative;\r\n display: flex;\r\n flex-wrap: wrap;\r\n align-items: center;\r\n gap: var(--_mono-tag-input-gap);\r\n width: 100%;\r\n min-width: 0;\r\n min-height: var(--_mono-tag-input-height);\r\n padding-block: var(--_mono-tag-input-padding-y);\r\n padding-inline: var(--_mono-tag-input-padding-x);\r\n outline-style: none;\r\n border: var(--mono-border-width) solid var(--_mono-tag-input-bc);\r\n border-top-color: var(--_mono-tag-input-side-bc);\r\n border-inline-color: var(--_mono-tag-input-side-bc);\r\n border-radius: var(--_mono-tag-input-radius);\r\n background: var(--_mono-tag-input-bg);\r\n background-clip: padding-box;\r\n color: var(--_mono-tag-input-text);\r\n box-shadow: var(--_mono-tag-input-ring), var(--_mono-tag-input-shadow);\r\n font-size: var(--_mono-tag-input-font-size);\r\n line-height: var(--_mono-tag-input-line-height);\r\n cursor: text;\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-within:border-ring focus-within:ring-3 focus-within:ring-ring/50 */\r\n &:focus-within {\r\n --_mono-tag-input-bc: var(--_mono-tag-input-ring-color);\r\n --_mono-tag-input-ring: 0 0 0 var(--_mono-tag-input-ring-width) color-mix(in oklab, var(--_mono-tag-input-ring-color) var(--_mono-tag-input-ring-alpha), transparent);\r\n }\r\n}\r\n\r\n/* basecoat@1.0.2 styles/vega.css .combobox-chips — has-[[aria-invalid=true]]:border-destructive\r\n has-[[aria-invalid=true]]:ring-3 has-[[aria-invalid=true]]:ring-destructive/20 */\r\n[mono-tag-input][mono-validation-state=\"invalid\"] > [mono-field],\r\n[mono-tag-input] > [mono-field]:has(> [mono-native][aria-invalid=\"true\"]) {\r\n --_mono-tag-input-bc: var(--mono-mode-invalid-border);\r\n --_mono-tag-input-ring: 0 0 0 var(--_mono-tag-input-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-tag-input][mono-validation-state=\"valid\"] > [mono-field] {\r\n --_mono-tag-input-bc: color-mix(in oklab, var(--_mono-tag-input-valid) var(--mono-mode-state-border-alpha), transparent);\r\n --_mono-tag-input-ring: 0 0 0 var(--_mono-tag-input-ring-width) color-mix(in oklab, var(--_mono-tag-input-valid) var(--mono-mode-state-ring-alpha), transparent);\r\n}\r\n[mono-tag-input][mono-validation-state=\"warning\"] > [mono-field] {\r\n --_mono-tag-input-bc: color-mix(in oklab, var(--_mono-tag-input-warning) var(--mono-mode-state-border-alpha), transparent);\r\n --_mono-tag-input-ring: 0 0 0 var(--_mono-tag-input-ring-width) color-mix(in oklab, var(--_mono-tag-input-warning) var(--mono-mode-state-ring-alpha), transparent);\r\n}\r\n\r\n/* EXTENSION — readonly: a muted surface */\r\n[mono-tag-input][mono-readonly] > [mono-field] {\r\n background: var(--mono-tag-input-readonly-bg, var(--muted));\r\n cursor: default;\r\n}\r\n\r\n/* .combobox-chips > input:disabled — opacity-50 (on the box, so the chips fade\r\n with it). The strip's ‹ › pager opts back in so the chips can still be read. */\r\n[mono-tag-input][mono-disabled] > [mono-field] {\r\n opacity: 0.5;\r\n pointer-events: none;\r\n cursor: not-allowed;\r\n background: var(--mono-tag-input-disabled-bg, var(--_mono-tag-input-bg));\r\n}\r\n\r\n[mono-tag-input][mono-disabled] [mono-scroll]:not([mono-idle]) {\r\n pointer-events: auto;\r\n cursor: pointer;\r\n}\r\n\r\n/* ── the actions row stays on the FIRST row ──────────────────────────────\r\n The field wraps, and the row is its last child, so once the chips wrapped it\r\n rode down to the bottom-right. Pinned out of that flow instead; `top` centres\r\n it on the single-row height. Not in inline mode: an inline field never wraps,\r\n so the row sits in normal flow and the strip flexes against it. */\r\n[mono-tag-input] > [mono-field]:not([mono-inline]) {\r\n padding-inline-end: calc(var(--_mono-tag-input-padding-x) + var(--_mono-tag-input-action) + var(--mono-spacing));\r\n}\r\n\r\n[mono-tag-input] > [mono-field]:not([mono-inline]) > [mono-actions] {\r\n position: absolute;\r\n inset-inline-end: var(--_mono-tag-input-padding-x);\r\n top: calc((var(--_mono-tag-input-height) - var(--_mono-tag-input-action)) / 2);\r\n}\r\n\r\n/* =========================================\r\n The text box\r\n ========================================= */\r\n\r\n/* basecoat@1.0.2 components/combobox.css .combobox-chips > input[role='combobox']\r\n — min-w-16 flex-1 bg-transparent outline-none placeholder:text-muted-foreground */\r\n[mono-tag-input] [mono-native] {\r\n flex: 1 1 calc(var(--mono-spacing) * 16);\r\n min-width: calc(var(--mono-spacing) * 16);\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-tag-input-text);\r\n font-family: inherit;\r\n font-size: var(--_mono-tag-input-font-size);\r\n line-height: var(--_mono-tag-input-line-height);\r\n /* The chip row is the box's height; the text box never exceeds it. `height`, not only\r\n `min-height`: an input's own line box is its floor, so with a chip shorter than the line (a\r\n dense flavor's capped chip — mira xs: 14px chip, 16px line) the input set the row and an\r\n empty field came out 2px over the control token. The 12px glyphs still fit. */\r\n min-height: var(--_mono-tag-input-chip-height);\r\n height: var(--_mono-tag-input-chip-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-tag-input-placeholder);\r\n }\r\n\r\n &:disabled,\r\n &:read-only {\r\n cursor: inherit;\r\n }\r\n}\r\n\r\n/* =========================================\r\n Chips\r\n ========================================= */\r\n\r\n/* basecoat@1.0.2 components/combobox.css .combobox-chip — inline-flex w-fit\r\n shrink-0 items-center whitespace-nowrap */\r\n[mono-tag-input] [mono-chip] {\r\n display: inline-flex;\r\n width: fit-content;\r\n max-width: 100%;\r\n flex-shrink: 0;\r\n align-items: center;\r\n white-space: nowrap;\r\n vertical-align: middle;\r\n line-height: 1;\r\n}\r\n\r\n/* basecoat@1.0.2 styles/vega.css .combobox-chip — h-5.5 gap-1 rounded-sm bg-muted\r\n px-1.5 text-xs font-medium text-foreground, has-[>.combobox-chip-remove]:pe-0 */\r\n[mono-tag-input] [mono-chip] > [mono-chip-main] {\r\n display: inline-flex;\r\n align-items: center;\r\n height: var(--_mono-tag-input-chip-height);\r\n max-width: 100%;\r\n gap: var(--mono-tag-input-chip-content-gap, var(--mono-spacing));\r\n margin: 0;\r\n padding-inline: var(--mono-tag-input-chip-padding-x, calc(var(--mono-spacing) * 1.5));\r\n border: 0;\r\n border-radius: var(--mono-tag-input-chip-radius, var(--mono-radius-sm));\r\n background: var(--mono-tag-input-chip-bg, var(--muted));\r\n color: var(--mono-tag-input-chip-color, var(--_mono-tag-input-text));\r\n font-family: inherit;\r\n font-size: var(--_mono-tag-input-chip-font-size);\r\n line-height: var(--_mono-tag-input-chip-line-height);\r\n font-weight: var(--mono-tag-input-chip-font-weight, var(--mono-font-weight-medium));\r\n text-decoration: none;\r\n cursor: default;\r\n}\r\n\r\n[mono-tag-input] [mono-chip][mono-removable] > [mono-chip-main] {\r\n padding-inline-end: 0;\r\n}\r\n\r\n[mono-tag-input] [mono-chip] [mono-chip-content] {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: inherit;\r\n min-width: 0;\r\n max-width: 100%;\r\n height: 100%;\r\n}\r\n\r\n[mono-tag-input] [mono-chip] [mono-chip-label] {\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n\r\n/* EXTENSION — `chip.dot`: a coloured dot before the label (the badge's dot idiom) */\r\n[mono-tag-input] [mono-chip] [mono-chip-dot] {\r\n flex: 0 0 auto;\r\n width: calc(var(--mono-spacing) * 1.5);\r\n height: calc(var(--mono-spacing) * 1.5);\r\n border-radius: var(--mono-radius-full);\r\n background: currentColor;\r\n}\r\n\r\n/* EXTENSION — `chip.color` pins a hue: the tonal pattern (bg-x/10 text-x, dark 20) */\r\n[mono-tag-input] [mono-chip][mono-chip-color=\"primary\"] > [mono-chip-main] { background: color-mix(in oklab, var(--primary) var(--mono-mode-tint), transparent); color: var(--primary); }\r\n[mono-tag-input] [mono-chip][mono-chip-color=\"secondary\"] > [mono-chip-main] { background: var(--secondary); color: var(--secondary-foreground); }\r\n[mono-tag-input] [mono-chip][mono-chip-color=\"success\"] > [mono-chip-main] { background: color-mix(in oklab, var(--success) var(--mono-mode-tint), transparent); color: var(--success); }\r\n[mono-tag-input] [mono-chip][mono-chip-color=\"danger\"] > [mono-chip-main] { background: color-mix(in oklab, var(--destructive) var(--mono-mode-tint), transparent); color: var(--destructive); }\r\n[mono-tag-input] [mono-chip][mono-chip-color=\"warning\"] > [mono-chip-main] { background: color-mix(in oklab, var(--warning) var(--mono-mode-tint), transparent); color: var(--warning); }\r\n[mono-tag-input] [mono-chip][mono-chip-color=\"info\"] > [mono-chip-main] { background: color-mix(in oklab, var(--info) var(--mono-mode-tint), transparent); color: var(--info); }\r\n[mono-tag-input] [mono-chip][mono-chip-color=\"teal\"] > [mono-chip-main] { background: color-mix(in oklab, var(--teal) var(--mono-mode-tint), transparent); color: var(--teal); }\r\n[mono-tag-input] [mono-chip][mono-chip-color=\"purple\"] > [mono-chip-main] { background: color-mix(in oklab, var(--purple) var(--mono-mode-tint), transparent); color: var(--purple); }\r\n[mono-tag-input] [mono-chip][mono-chip-color=\"neutral\"] > [mono-chip-main] { background: color-mix(in oklab, var(--neutral) var(--mono-mode-tint), transparent); color: var(--neutral); }\r\n[mono-tag-input] [mono-chip][mono-chip-color=\"dark\"] > [mono-chip-main] { background: var(--dark); color: var(--dark-foreground); }\r\n\r\n/* basecoat@1.0.2 components/combobox.css .combobox-chip-remove — inline-flex\r\n shrink-0 items-center justify-center */\r\n/* basecoat@1.0.2 styles/vega.css .combobox-chip-remove — -ms-1 opacity-50\r\n hover:opacity-100, svg size-3.5 */\r\n[mono-tag-input] [mono-chip] [mono-chip-close] {\r\n display: inline-flex;\r\n flex-shrink: 0;\r\n align-items: center;\r\n justify-content: center;\r\n /* explicit: the element still carries chip.css's `.chip-close` class as a hook,\r\n which pins a 1rem box — the raw markup has no such class */\r\n width: auto;\r\n height: 100%;\r\n min-width: 0;\r\n margin: 0;\r\n transform: none;\r\n margin-inline-start: calc(var(--mono-spacing) * -1);\r\n padding: 0 var(--mono-spacing);\r\n border: 0;\r\n border-radius: inherit;\r\n background: transparent;\r\n color: inherit;\r\n font: inherit;\r\n line-height: 1;\r\n opacity: 0.5;\r\n cursor: pointer;\r\n outline-style: none;\r\n transition-property: opacity;\r\n transition-timing-function: var(--mono-ease);\r\n transition-duration: var(--mono-duration);\r\n\r\n &:focus-visible {\r\n opacity: 1;\r\n }\r\n}\r\n\r\n@media (hover: hover) {\r\n [mono-tag-input] [mono-chip] [mono-chip-close]:hover {\r\n opacity: 1;\r\n }\r\n}\r\n\r\n[mono-tag-input] [mono-chip] [mono-chip-close] > :is(svg, .mono-icon, [mono-icon]) {\r\n display: block;\r\n width: calc(var(--mono-spacing) * 3.5);\r\n height: calc(var(--mono-spacing) * 3.5);\r\n pointer-events: none;\r\n}\r\n\r\n/* EXTENSION — the \"+N more\" counter chip is a control */\r\n[mono-tag-input] [mono-chip][mono-more] > [mono-chip-main] {\r\n cursor: pointer;\r\n outline-style: none;\r\n}\r\n\r\n[mono-tag-input] [mono-chip][mono-more] > [mono-chip-main]:focus-visible {\r\n box-shadow: 0 0 0 var(--_mono-tag-input-ring-width) color-mix(in oklab, var(--_mono-tag-input-ring-color) var(--_mono-tag-input-ring-alpha), transparent);\r\n}\r\n\r\n@media (hover: hover) {\r\n [mono-tag-input] [mono-chip][mono-more] > [mono-chip-main]:hover {\r\n background: var(--mono-mode-surface-hover);\r\n }\r\n}\r\n\r\n/* ── the inline chip strip (`chip.behaviour: 'inline'`) ──────────────────\r\n One line that never grows: the field stops wrapping, the chips live in their\r\n own strip, and the strip absorbs the overflow instead of the field.\r\n\r\n `overflow-x: hidden` — NOT `auto` — is the whole scroll contract. Hidden still\r\n honours a programmatic `scrollLeft`, so `ChipStripController` can page the\r\n strip while the browser paints no scrollbar. */\r\n[mono-tag-input] > [mono-field][mono-inline] {\r\n flex-wrap: nowrap;\r\n min-width: 0;\r\n}\r\n\r\n[mono-tag-input] [mono-chip-strip] {\r\n display: flex;\r\n flex-wrap: nowrap;\r\n align-items: center;\r\n gap: var(--_mono-tag-input-gap);\r\n flex: 0 1 auto;\r\n min-width: 0;\r\n overflow-x: hidden;\r\n overflow-y: hidden;\r\n /* NO `scroll-behavior: smooth` — see ChipStripController (one scroll event per\r\n frame would reposition every open popup). */\r\n}\r\n\r\n[mono-tag-input] [mono-chip-strip] > * {\r\n flex-shrink: 0;\r\n}\r\n\r\n/* The text box takes the SLACK: `flex-basis: 0` contributes nothing to the\r\n overflow calculation, so when the chips overflow it collapses and the strip\r\n runs up to the pager; focus earns a caret's room, typing earns a real box. */\r\n[mono-tag-input] > [mono-field][mono-inline] > [mono-native] {\r\n flex: 1 1 0;\r\n min-width: 0;\r\n}\r\n\r\n[mono-tag-input] > [mono-field][mono-inline] > [mono-native]:focus,\r\n[mono-tag-input] > [mono-field][mono-inline] > [mono-native]:focus-visible {\r\n min-width: calc(var(--mono-spacing) * 5);\r\n}\r\n\r\n[mono-tag-input] > [mono-field][mono-inline][mono-typing] > [mono-native] {\r\n min-width: calc(var(--mono-spacing) * 24);\r\n}\r\n\r\n/* =========================================\r\n Actions — ‹ › pager, clear, caret\r\n ========================================= */\r\n\r\n[mono-tag-input] [mono-actions] {\r\n display: flex;\r\n align-items: center;\r\n gap: var(--mono-spacing);\r\n flex: 0 0 auto;\r\n line-height: 1;\r\n}\r\n\r\n/* basecoat@1.0.2 components/combobox.css .combobox [data-clear] — size-6 border-0\r\n bg-transparent p-0 text-current; the caret ≡ .combobox-trigger-icon (size-4\r\n text-muted-foreground), the pager the same box. Painted as .btn[data-variant='ghost']. */\r\n[mono-tag-input] [mono-clear],\r\n[mono-tag-input] [mono-arrow],\r\n[mono-tag-input] [mono-scroll] {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n flex: 0 0 auto;\r\n width: var(--_mono-tag-input-action);\r\n height: var(--_mono-tag-input-action);\r\n margin: 0;\r\n padding: 0;\r\n border: 0;\r\n border-radius: var(--mono-tag-input-clear-radius, calc(var(--radius) - 5px));\r\n background: transparent;\r\n color: var(--_mono-tag-input-muted);\r\n font: inherit;\r\n line-height: 1;\r\n cursor: pointer;\r\n outline-style: none;\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-tag-input] :is([mono-clear], [mono-arrow], [mono-scroll]) > :is(svg, .mono-icon, [mono-icon]) {\r\n display: block;\r\n width: var(--_mono-tag-input-icon);\r\n height: var(--_mono-tag-input-icon);\r\n pointer-events: none;\r\n}\r\n\r\n[mono-tag-input] [mono-clear] > :is(svg, .mono-icon, [mono-icon]) {\r\n width: var(--_mono-tag-input-clear-glyph);\r\n height: var(--_mono-tag-input-clear-glyph);\r\n}\r\n\r\n/* basecoat@1.0.2 styles/vega.css .btn[data-variant='ghost'] — hover:bg-muted hover:text-foreground */\r\n@media (hover: hover) {\r\n [mono-tag-input] :is([mono-clear], [mono-arrow], [mono-scroll]):hover {\r\n background: var(--mono-mode-ghost-hover);\r\n color: var(--_mono-tag-input-text);\r\n }\r\n}\r\n\r\n/* EXTENSION — the caret turns while the panel is open */\r\n[mono-tag-input][mono-open] [mono-arrow] > :is(svg, .mono-icon, [mono-icon]) {\r\n transform: rotate(180deg);\r\n}\r\n\r\n/* At an end of the strip the pager keeps its box but disappears — hiding it with\r\n `display: none` would shrink the row and shove the strip sideways mid-click. */\r\n[mono-tag-input] [mono-scroll][mono-idle] {\r\n visibility: hidden;\r\n pointer-events: none;\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 overflow;\r\n mono: `display: none` while closed, `--mono-popup-z` from the shared stack,\r\n `--mono-popup-avail-h` from the portal controller */\r\n/* basecoat@1.0.2 styles/vega.css .combobox [data-popover] — bg-popover\r\n text-popover-foreground ring-foreground/10 max-h-72 rounded-md p-0 shadow-md ring-1 */\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 (our panel IS\r\n the listbox: one scrolling box) */\r\n[mono-tag-input] > [mono-dropdown] {\r\n position: absolute;\r\n /* `top: auto` = the static position (under the field, before the message); the\r\n 6px offset is a transform the controller's inline `transform: none` cancels */\r\n top: auto;\r\n transform: translateY(calc(var(--mono-spacing) * 1.5));\r\n left: 0;\r\n right: 0;\r\n z-index: var(--mono-popup-z, 1000);\r\n display: none;\r\n min-width: var(--mono-tag-input-dropdown-min-width, 9rem);\r\n max-height: min(var(--_mono-tag-input-panel-max-h, 18rem), var(--mono-popup-avail-h, 100vh));\r\n padding: var(--mono-tag-input-dropdown-padding, var(--mono-spacing));\r\n overflow: auto;\r\n overscroll-behavior: contain;\r\n scroll-padding-block: var(--mono-tag-input-dropdown-padding, var(--mono-spacing));\r\n isolation: isolate;\r\n border-radius: var(--mono-tag-input-dropdown-radius, var(--mono-radius-md));\r\n background: var(--mono-tag-input-dropdown-bg, var(--popover));\r\n color: var(--mono-tag-input-dropdown-color, var(--popover-foreground));\r\n box-shadow: var(--mono-tag-input-dropdown-ring, 0 0 0 1px color-mix(in oklab, var(--foreground) 10%, transparent)), var(--mono-tag-input-dropdown-shadow, var(--mono-shadow-md));\r\n font-size: var(--mono-tag-input-option-font-size, var(--mono-text-sm));\r\n line-height: var(--mono-tag-input-option-line-height, var(--mono-text-sm--lh));\r\n outline-style: none;\r\n}\r\n\r\n[mono-tag-input][mono-open] > [mono-dropdown] {\r\n display: block;\r\n}\r\n\r\n/* =========================================\r\n Options\r\n -----------------------------------------\r\n Every rule that paints a native line lists its stamped twin (`slot=\"list\"`:\r\n `[data-mono-type='row']`, `[data-mono-active]`, `[data-mono-selected]`,\r\n `[data-mono-chrome]`) so the two can never drift. `:where()` wraps only the\r\n 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 outline-none select-none; disabled\r\n pointer-events-none opacity-50 */\r\n/* basecoat@1.0.2 styles/vega.css .combobox [role='option'] — gap-2 rounded-sm\r\n py-1.5 ps-2 pe-8 text-sm, svg size-4; EXTENSION: one indent step per level */\r\n[mono-tag-input] [mono-item],\r\n[mono-tag-input] :where([mono-list-slot]) [data-mono-type='row'] {\r\n --_ti-item-level: 0;\r\n position: relative;\r\n display: flex;\r\n width: 100%;\r\n align-items: center;\r\n gap: var(--mono-tag-input-option-gap, calc(var(--mono-spacing) * 2));\r\n margin: 0;\r\n padding-block: var(--mono-tag-input-option-padding-y, calc(var(--mono-spacing) * 1.5));\r\n padding-inline: var(--mono-tag-input-option-padding-x, calc(var(--mono-spacing) * 2)) var(--mono-tag-input-option-padding-end, calc(var(--mono-spacing) * 8));\r\n padding-inline-start: calc(var(--mono-tag-input-option-padding-x, calc(var(--mono-spacing) * 2)) + var(--_ti-item-level) * calc(var(--mono-spacing) * 3));\r\n min-height: var(--mono-tag-input-option-min-height, 0);\r\n border: 0;\r\n border-radius: var(--mono-tag-input-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-tag-input-text);\r\n font-family: inherit;\r\n font-size: var(--mono-tag-input-option-font-size, var(--mono-text-sm));\r\n line-height: var(--mono-tag-input-option-line-height, var(--mono-text-sm--lh));\r\n font-weight: var(--mono-tag-input-option-font-weight, var(--mono-font-weight-normal));\r\n text-align: start;\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-tag-input-option-spacing`. */\r\n[mono-tag-input] [mono-item] + [mono-item],\r\n[mono-tag-input] :where([mono-list-slot]) [data-mono-type='row'] + [data-mono-type='row'] {\r\n margin-top: var(--mono-tag-input-option-spacing, 2px);\r\n}\r\n\r\n[mono-tag-input] [mono-item][mono-level='1'] { --_ti-item-level: 1; }\r\n[mono-tag-input] [mono-item][mono-level='2'] { --_ti-item-level: 2; }\r\n[mono-tag-input] [mono-item][mono-level='3'] { --_ti-item-level: 3; }\r\n[mono-tag-input] [mono-item][mono-level='4'] { --_ti-item-level: 4; }\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-tag-input] [mono-item][mono-active]:not([mono-disabled]):not(:disabled),\r\n[mono-tag-input] [mono-item]:focus-visible,\r\n[mono-tag-input] :where([mono-list-slot]) [data-mono-active] {\r\n background-color: var(--mono-tag-input-option-active-bg, var(--muted));\r\n color: var(--mono-tag-input-option-active-color, var(--_mono-tag-input-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[mono-tag-input] [mono-item]:hover:not([mono-disabled]):not(:disabled),\r\n[mono-tag-input] :where([mono-list-slot]) [data-mono-type='row']:hover {\r\n background-color: var(--mono-tag-input-option-active-bg, var(--muted));\r\n color: var(--mono-tag-input-option-active-color, var(--_mono-tag-input-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. A row with its OWN checkbox says it there instead. */\r\n[mono-tag-input] [mono-item][mono-selected]:not([mono-check]),\r\n[mono-tag-input] :where([mono-list-slot]) [data-mono-type='row'][data-mono-selected] {\r\n background-image: var(--mono-tag-input-check-icon, var(--check-icon));\r\n background-size: var(--mono-tag-input-check-size, 0.875rem);\r\n background-position: center right calc(var(--mono-spacing) * 2);\r\n background-repeat: no-repeat;\r\n}\r\n\r\n[mono-tag-input] [mono-item][mono-selected]:not([mono-check]):dir(rtl),\r\n[mono-tag-input] :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-tag-input] [mono-item][mono-disabled],\r\n[mono-tag-input] [mono-item]:disabled {\r\n opacity: 0.5;\r\n pointer-events: none;\r\n cursor: not-allowed;\r\n}\r\n\r\n/* the title IS the consumer's line — a custom row has no title element */\r\n[mono-tag-input] [mono-item-text] {\r\n flex: 1 1 auto;\r\n min-width: 0;\r\n}\r\n\r\n[mono-tag-input] [mono-item-title],\r\n[mono-tag-input] :where([mono-list-slot]) [data-mono-type='row'] {\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n\r\n/* EXTENSION — `item.description`: a muted second line */\r\n[mono-tag-input] [mono-item-sub] {\r\n margin-top: 0;\r\n font-size: var(--mono-text-xs);\r\n line-height: var(--mono-text-xs--lh);\r\n color: var(--_mono-tag-input-muted);\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n\r\n/* checkable rows: the box IS a mono-checkbox — the row emits the element's own\r\n markup ([mono-checkbox] > [mono-box], [mono-size=\"sm\"], the checked /\r\n indeterminate / loading states) and checkbox.css paints every pixel of it, in\r\n both builds; this sheet says only how it sits in the row: it must not shrink\r\n or take clicks (the row's button handles the toggle). A consumer's line lays\r\n out the same. */\r\n[mono-tag-input] [mono-check-box],\r\n[mono-tag-input] :where([mono-list-slot]) [data-mono-chrome] {\r\n flex: 0 0 auto;\r\n gap: 0;\r\n pointer-events: none;\r\n}\r\n\r\n[mono-tag-input] :where([mono-list-slot]) [data-mono-type='group'] {\r\n display: flex;\r\n align-items: center;\r\n gap: var(--mono-tag-input-option-gap, calc(var(--mono-spacing) * 2));\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 */\r\n[mono-tag-input] [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-tag-input-option-font-size, var(--mono-text-sm));\r\n line-height: var(--mono-tag-input-option-line-height, var(--mono-text-sm--lh));\r\n color: var(--_mono-tag-input-muted);\r\n text-align: center;\r\n cursor: default;\r\n user-select: none;\r\n}\r\n\r\n/* basecoat@1.0.2 styles/vega.css .combobox [role='heading'] — px-2 py-1.5 text-xs\r\n text-muted-foreground; EXTENSION: one indent step per level, a <button> when the\r\n header selects its group */\r\n[mono-tag-input] [mono-group],\r\n[mono-tag-input] :where([mono-list-slot]) [data-mono-type='group'] {\r\n --_ti-group-level: 0;\r\n width: 100%;\r\n margin: 0;\r\n padding-block: var(--mono-tag-input-group-padding-y, calc(var(--mono-spacing) * 1.5));\r\n padding-inline: var(--mono-tag-input-group-padding-x, calc(var(--mono-spacing) * 2));\r\n padding-inline-start: calc(var(--mono-tag-input-group-padding-x, calc(var(--mono-spacing) * 2)) + var(--_ti-group-level) * calc(var(--mono-spacing) * 3));\r\n border: 0;\r\n border-radius: var(--mono-tag-input-option-radius, var(--mono-radius-sm));\r\n background: transparent;\r\n font-family: inherit;\r\n font-size: var(--mono-tag-input-group-font-size, var(--mono-text-xs));\r\n line-height: var(--mono-tag-input-group-line-height, var(--mono-text-xs--lh));\r\n font-weight: var(--mono-tag-input-group-font-weight, var(--mono-font-weight-normal));\r\n text-transform: var(--mono-tag-input-group-text-transform, none);\r\n letter-spacing: var(--mono-tag-input-group-letter-spacing, normal);\r\n text-align: start;\r\n color: var(--_mono-tag-input-muted);\r\n cursor: default;\r\n user-select: none;\r\n}\r\n\r\n[mono-tag-input] [mono-group][mono-level='1'],\r\n[mono-tag-input] :where([mono-list-slot]) [data-mono-level='1'] { --_ti-group-level: 1; --_ti-item-level: 1; }\r\n[mono-tag-input] [mono-group][mono-level='2'],\r\n[mono-tag-input] :where([mono-list-slot]) [data-mono-level='2'] { --_ti-group-level: 2; --_ti-item-level: 2; }\r\n[mono-tag-input] [mono-group][mono-level='3'],\r\n[mono-tag-input] :where([mono-list-slot]) [data-mono-level='3'] { --_ti-group-level: 3; --_ti-item-level: 3; }\r\n[mono-tag-input] [mono-group][mono-level='4'],\r\n[mono-tag-input] :where([mono-list-slot]) [data-mono-level='4'] { --_ti-group-level: 4; --_ti-item-level: 4; }\r\n\r\n/* a header that selects its own group is a <button> laid out like the rows */\r\n[mono-tag-input] [mono-group][mono-toggle],\r\n[mono-tag-input] :where([mono-list-slot]) [data-mono-type='group']:has([data-mono-chrome]) {\r\n display: flex;\r\n align-items: center;\r\n gap: var(--mono-tag-input-option-gap, calc(var(--mono-spacing) * 2));\r\n cursor: pointer;\r\n}\r\n\r\n@media (hover: hover) {\r\n [mono-tag-input] [mono-group][mono-toggle]:hover {\r\n background-color: var(--mono-tag-input-option-active-bg, var(--muted));\r\n color: var(--_mono-tag-input-text);\r\n }\r\n}\r\n\r\n/* a group carrying a selection reads at a glance while scrolling */\r\n[mono-tag-input] [mono-group][mono-toggle][mono-selected] {\r\n color: var(--_mono-tag-input-text);\r\n}\r\n\r\n[mono-tag-input] [mono-group-label] {\r\n flex: 1 1 auto;\r\n min-width: 0;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n\r\n/* group-sticky: pin headers while their rows scroll, on the panel's own surface */\r\n[mono-tag-input] [mono-group][mono-sticky] {\r\n position: sticky;\r\n top: calc(var(--_ti-group-level) * 1.5rem);\r\n z-index: calc(5 - var(--_ti-group-level));\r\n background: var(--mono-tag-input-dropdown-bg, var(--popover));\r\n}\r\n\r\n/* EXTENSION — the \"All\" row: always first, always sticky, on the panel surface\r\n with a hairline under it; z above the group headers (which stack from 5 down) */\r\n[mono-tag-input] [mono-select-all] {\r\n position: sticky;\r\n top: 0;\r\n z-index: 6;\r\n background-color: var(--mono-tag-input-dropdown-bg, var(--popover));\r\n box-shadow: 0 1px 0 0 var(--border);\r\n font-weight: var(--mono-font-weight-medium);\r\n}\r\n\r\n@media (hover: hover) {\r\n [mono-tag-input] [mono-select-all]:hover:not(:disabled) {\r\n background-color: var(--mono-tag-input-option-active-bg, var(--muted));\r\n }\r\n}\r\n\r\n/* while it drains the server the row is `disabled` so a second click cannot start\r\n a second drain — but it is busy, not unavailable: undo the disabled look */\r\n[mono-tag-input] [mono-select-all][mono-loading],\r\n[mono-tag-input] [mono-select-all][mono-loading]:hover {\r\n opacity: 1;\r\n cursor: progress;\r\n pointer-events: none;\r\n background-color: var(--mono-tag-input-option-active-bg, var(--muted));\r\n}\r\n\r\n/* EXTENSION — the load-more affordance: an option-shaped ghost button */\r\n[mono-tag-input] [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-tag-input-option-gap, calc(var(--mono-spacing) * 2));\r\n margin: 0;\r\n padding-block: var(--mono-tag-input-option-padding-y, calc(var(--mono-spacing) * 1.5));\r\n padding-inline: var(--mono-tag-input-option-padding-x, calc(var(--mono-spacing) * 2));\r\n border: 0;\r\n border-radius: var(--mono-tag-input-option-radius, var(--mono-radius-sm));\r\n background: transparent;\r\n color: var(--_mono-tag-input-muted);\r\n font-family: inherit;\r\n font-size: var(--mono-tag-input-option-font-size, var(--mono-text-sm));\r\n line-height: var(--mono-tag-input-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-tag-input] [mono-load-more]:hover:not([mono-loading]) {\r\n background: var(--mono-tag-input-option-active-bg, var(--muted));\r\n color: var(--_mono-tag-input-text);\r\n }\r\n}\r\n\r\n[mono-tag-input] [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. */\r\n[mono-tag-input] [mono-list-slot] {\r\n display: contents;\r\n}\r\n\r\n/* =========================================\r\n The \"+N more\" overflow panel — a popover holding the overflow chips\r\n ========================================= */\r\n\r\n/* basecoat@1.0.2 styles/vega.css .combobox [data-popover] — bg-popover ring-1\r\n ring-foreground/10 rounded-md shadow-md; EXTENSION: p-1.5 gap-1.5 flex-wrap */\r\n[mono-tag-input] > [mono-more-panel] {\r\n position: absolute;\r\n left: 0;\r\n right: 0;\r\n top: auto;\r\n transform: translateY(calc(var(--mono-spacing) * 1.5));\r\n z-index: var(--mono-popup-z, 1000);\r\n display: none;\r\n flex-wrap: wrap;\r\n align-items: flex-start;\r\n gap: var(--_mono-tag-input-gap);\r\n padding: calc(var(--mono-spacing) * 1.5);\r\n max-height: min(14rem, var(--mono-popup-avail-h, 100vh));\r\n overflow: auto;\r\n overscroll-behavior: contain;\r\n border-radius: var(--mono-tag-input-dropdown-radius, var(--mono-radius-md));\r\n background: var(--mono-tag-input-dropdown-bg, var(--popover));\r\n color: var(--mono-tag-input-dropdown-color, var(--popover-foreground));\r\n box-shadow: var(--mono-tag-input-dropdown-ring, 0 0 0 1px color-mix(in oklab, var(--foreground) 10%, transparent)), var(--mono-tag-input-dropdown-shadow, var(--mono-shadow-md));\r\n}\r\n\r\n[mono-tag-input][mono-more-open] > [mono-more-panel] {\r\n display: flex;\r\n}\r\n\r\n/* =========================================\r\n Message\r\n ========================================= */\r\n\r\n/* basecoat@1.0.2 styles/vega.css .fieldset legend + p, .field > p, .field section > p */\r\n[mono-tag-input] > [mono-message-wrap] {\r\n display: block;\r\n margin-top: var(--_mono-tag-input-gap-y);\r\n}\r\n\r\n[mono-tag-input] > [mono-message-wrap]:not(:has([mono-message]:not([mono-empty]))) {\r\n display: none;\r\n}\r\n\r\n[mono-tag-input] [mono-message] {\r\n font-size: var(--mono-tag-input-message-font-size, var(--mono-text-sm));\r\n line-height: var(--mono-tag-input-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-tag-input-muted);\r\n}\r\n\r\n/* basecoat@1.0.2 styles/vega.css .field [role=\"alert\"] — text-destructive text-sm */\r\n[mono-tag-input] [mono-message=\"invalid\"] {\r\n color: var(--_mono-tag-input-invalid);\r\n}\r\n\r\n[mono-tag-input] [mono-message=\"valid\"] {\r\n color: var(--_mono-tag-input-valid);\r\n}\r\n\r\n[mono-tag-input] [mono-message=\"warning\"] {\r\n color: var(--_mono-tag-input-warning);\r\n}\r\n\r\n@media (prefers-reduced-motion: reduce) {\r\n [mono-tag-input] > [mono-field],\r\n [mono-tag-input] [mono-clear],\r\n [mono-tag-input] [mono-arrow],\r\n [mono-tag-input] [mono-scroll],\r\n [mono-tag-input] [mono-item],\r\n [mono-tag-input] [mono-chip-close] {\r\n transition: none;\r\n }\r\n}\r\n";
|
|
2660
|
+
//#endregion
|
|
2661
|
+
//#region src/components/tag-input/mono-tag-input.ts
|
|
2662
|
+
var MonoTagInput = class MonoTagInput extends MonoTagInputCore(LitElement) {
|
|
2663
|
+
constructor(..._args) {
|
|
2664
|
+
super(..._args);
|
|
2665
|
+
this._slotsCaptured = false;
|
|
2666
|
+
this._slotLabel = [];
|
|
2667
|
+
this._slotHelper = [];
|
|
2668
|
+
this._slotList = null;
|
|
2669
|
+
}
|
|
2670
|
+
static {
|
|
2671
|
+
this.styles = [unsafeCSS(tag_input_default)];
|
|
2672
|
+
}
|
|
2673
|
+
createRenderRoot() {
|
|
2674
|
+
return this;
|
|
2675
|
+
}
|
|
2676
|
+
connectedCallback() {
|
|
2677
|
+
super.connectedCallback();
|
|
2678
|
+
this._captureSlots();
|
|
2679
|
+
if (this.isConnected) this.performUpdate();
|
|
2680
|
+
}
|
|
2681
|
+
updated(changed) {
|
|
2682
|
+
super.updated(changed);
|
|
2683
|
+
this._onLateListSlot();
|
|
2684
|
+
this._placeSlot("label", this._slotLabel);
|
|
2685
|
+
this._placeSlot("helper", this._slotHelper);
|
|
2686
|
+
this._placeListSlot();
|
|
2687
|
+
this._watchListChrome();
|
|
2688
|
+
this._syncListChrome();
|
|
2689
|
+
}
|
|
2690
|
+
/**
|
|
2691
|
+
* The captured wrapper, which is the truth for this build at every moment: parked out of the
|
|
2692
|
+
* host before the panel exists, and inside the panel after. The core's default (a light child of
|
|
2693
|
+
* the host) is the SHADOW build's answer and would find nothing here.
|
|
2694
|
+
*/
|
|
2695
|
+
get _listSlotWrapper() {
|
|
2696
|
+
return this._slotList;
|
|
2697
|
+
}
|
|
2698
|
+
/** Light-DOM target for the list wrapper; the shadow build projects instead. */
|
|
2699
|
+
renderListSlot() {
|
|
2700
|
+
return html`<div class="mono-tag-input-list-slot" mono-list-slot data-mono-slot="list" @click=${this._onListSlotClick}></div>`;
|
|
2701
|
+
}
|
|
2702
|
+
/**
|
|
2703
|
+
* Move the wrapper into the panel, once it exists.
|
|
2704
|
+
*
|
|
2705
|
+
* The panel is relocated into a body portal while open, so the target is queried through the
|
|
2706
|
+
* core's portal-aware root rather than the host. Idempotent: once the wrapper is inside the
|
|
2707
|
+
* target it is left alone, which matters because re-appending it on every render would blow away
|
|
2708
|
+
* the consumer's scroll position and focus.
|
|
2709
|
+
*/
|
|
2710
|
+
_placeListSlot() {
|
|
2711
|
+
const wrapper = this._slotList;
|
|
2712
|
+
if (!wrapper) return;
|
|
2713
|
+
const target = this._listSlotTarget;
|
|
2714
|
+
if (!target || wrapper.parentNode === target) return;
|
|
2715
|
+
target.appendChild(wrapper);
|
|
2716
|
+
}
|
|
2717
|
+
_captureSlots() {
|
|
2718
|
+
if (this._slotsCaptured) return;
|
|
2719
|
+
this._slotsCaptured = true;
|
|
2720
|
+
const captured = monoHostChildNodes(this);
|
|
2721
|
+
const capturedSlotNodes = /* @__PURE__ */ new Set();
|
|
2722
|
+
for (const node of captured) {
|
|
2723
|
+
if (!(node instanceof Element)) continue;
|
|
2724
|
+
const slotName = node.getAttribute("slot");
|
|
2725
|
+
if (slotName === "label") {
|
|
2726
|
+
node.removeAttribute("slot");
|
|
2727
|
+
this._slotLabel.push(node);
|
|
2728
|
+
capturedSlotNodes.add(node);
|
|
2729
|
+
}
|
|
2730
|
+
if (slotName === "helper") {
|
|
2731
|
+
node.removeAttribute("slot");
|
|
2732
|
+
this._slotHelper.push(node);
|
|
2733
|
+
capturedSlotNodes.add(node);
|
|
2734
|
+
}
|
|
2735
|
+
if (slotName === "list" && !this._slotList) {
|
|
2736
|
+
this._slotList = node;
|
|
2737
|
+
this._hasListSlotState = true;
|
|
2738
|
+
capturedSlotNodes.add(node);
|
|
2739
|
+
}
|
|
2740
|
+
}
|
|
2741
|
+
this._hasLabelSlotState = this._slotLabel.length > 0;
|
|
2742
|
+
this._hasHelperSlotState = this._slotHelper.length > 0;
|
|
2743
|
+
for (const node of capturedSlotNodes) if (node.parentNode === this) this.removeChild(node);
|
|
2744
|
+
}
|
|
2745
|
+
/**
|
|
2746
|
+
* Adopt a wrapper that appeared after `connectedCallback` — see `LateSlotWatcher`.
|
|
2747
|
+
*
|
|
2748
|
+
* Two things have to happen and the order matters. It is PARKED first, out of the host, because
|
|
2749
|
+
* until it is placed it would otherwise paint in the host's own flow, under the field rather
|
|
2750
|
+
* than inside the panel — that is the bug this exists for. Only then is the flag flipped, which
|
|
2751
|
+
* schedules the render that creates the target `_placeListSlot` needs.
|
|
2752
|
+
*
|
|
2753
|
+
* Parking detached is safe for the subtree inside it: the consumer's `v-for` inserts against
|
|
2754
|
+
* anchors that are its OWN children, and those move with it.
|
|
2755
|
+
*/
|
|
2756
|
+
_onLateListSlot() {
|
|
2757
|
+
if (this._slotList) return;
|
|
2758
|
+
const wrapper = this._lateListSlot.find();
|
|
2759
|
+
if (!wrapper) return;
|
|
2760
|
+
this._slotList = wrapper;
|
|
2761
|
+
if (wrapper.parentNode === this) this.removeChild(wrapper);
|
|
2762
|
+
this._hasListSlotState = true;
|
|
2763
|
+
}
|
|
2764
|
+
_placeSlot(name, nodes) {
|
|
2765
|
+
if (!nodes.length) return;
|
|
2766
|
+
const target = this.querySelector(`[data-mono-slot="${name}"]`);
|
|
2767
|
+
if (!target) return;
|
|
2768
|
+
for (const node of nodes) placeSlotNode(target, node);
|
|
2769
|
+
}
|
|
2770
|
+
};
|
|
2771
|
+
MonoTagInput = __decorate([customElement("mono-tag-input")], MonoTagInput);
|
|
2772
|
+
//#endregion
|
|
2773
|
+
//#region src/components/tag-input/tag-input-utils.ts
|
|
2774
|
+
function validateTagInputProps(props) {
|
|
2775
|
+
const validSizes = [
|
|
2776
|
+
"xs",
|
|
2777
|
+
"sm",
|
|
2778
|
+
"md",
|
|
2779
|
+
"lg",
|
|
2780
|
+
"xl",
|
|
2781
|
+
"xxl"
|
|
2782
|
+
];
|
|
2783
|
+
const validColors = [
|
|
2784
|
+
"primary",
|
|
2785
|
+
"secondary",
|
|
2786
|
+
"success",
|
|
2787
|
+
"danger",
|
|
2788
|
+
"warning",
|
|
2789
|
+
"info",
|
|
2790
|
+
"teal",
|
|
2791
|
+
"purple",
|
|
2792
|
+
"neutral",
|
|
2793
|
+
"dark"
|
|
2794
|
+
];
|
|
2795
|
+
const validVariants = [
|
|
2796
|
+
"outlined",
|
|
2797
|
+
"filled",
|
|
2798
|
+
"underlined"
|
|
2799
|
+
];
|
|
2800
|
+
const validStates = [
|
|
2801
|
+
"default",
|
|
2802
|
+
"valid",
|
|
2803
|
+
"invalid",
|
|
2804
|
+
"warning"
|
|
2805
|
+
];
|
|
2806
|
+
if (props.size && !validSizes.includes(props.size)) return false;
|
|
2807
|
+
if (props.color && !validColors.includes(props.color)) return false;
|
|
2808
|
+
if (props.variant && !validVariants.includes(props.variant)) return false;
|
|
2809
|
+
if (props.validationState && !validStates.includes(props.validationState)) return false;
|
|
2810
|
+
return true;
|
|
2811
|
+
}
|
|
2812
|
+
function normalizeSuggestions(items) {
|
|
2813
|
+
return items.map((item) => ({
|
|
2814
|
+
...item,
|
|
2815
|
+
value: item.value ?? item.label
|
|
2816
|
+
}));
|
|
2817
|
+
}
|
|
2818
|
+
//#endregion
|
|
2819
|
+
export { MonoTagInput, normalizeSuggestions, validateTagInputProps };
|