@vielzeug/refine 1.1.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/README.md +89 -0
- package/dist/_dev.cjs +2 -0
- package/dist/_dev.cjs.map +1 -0
- package/dist/_dev.d.ts +2 -0
- package/dist/_dev.d.ts.map +1 -0
- package/dist/_dev.js +9 -0
- package/dist/_dev.js.map +1 -0
- package/dist/_virtual/_rolldown/runtime.cjs +1 -0
- package/dist/accordion-item.cjs +26 -0
- package/dist/accordion-item.cjs.map +1 -0
- package/dist/accordion-item.js +124 -0
- package/dist/accordion-item.js.map +1 -0
- package/dist/accordion.cjs +2 -0
- package/dist/accordion.cjs.map +1 -0
- package/dist/accordion.js +47 -0
- package/dist/accordion.js.map +1 -0
- package/dist/alert.cjs +36 -0
- package/dist/alert.cjs.map +1 -0
- package/dist/alert.js +93 -0
- package/dist/alert.js.map +1 -0
- package/dist/async.cjs +55 -0
- package/dist/async.cjs.map +1 -0
- package/dist/async.js +99 -0
- package/dist/async.js.map +1 -0
- package/dist/avatar.cjs +18 -0
- package/dist/avatar.cjs.map +1 -0
- package/dist/avatar.js +108 -0
- package/dist/avatar.js.map +1 -0
- package/dist/badge.cjs +7 -0
- package/dist/badge.cjs.map +1 -0
- package/dist/badge.js +65 -0
- package/dist/badge.js.map +1 -0
- package/dist/box.cjs +2 -0
- package/dist/box.cjs.map +1 -0
- package/dist/box.js +31 -0
- package/dist/box.js.map +1 -0
- package/dist/breadcrumb.cjs +21 -0
- package/dist/breadcrumb.cjs.map +1 -0
- package/dist/breadcrumb.js +57 -0
- package/dist/breadcrumb.js.map +1 -0
- package/dist/button-group.cjs +6 -0
- package/dist/button-group.cjs.map +1 -0
- package/dist/button-group.js +33 -0
- package/dist/button-group.js.map +1 -0
- package/dist/button.cjs +18 -0
- package/dist/button.cjs.map +1 -0
- package/dist/button.js +124 -0
- package/dist/button.js.map +1 -0
- package/dist/calendar.cjs +126 -0
- package/dist/calendar.cjs.map +1 -0
- package/dist/calendar.js +300 -0
- package/dist/calendar.js.map +1 -0
- package/dist/card.cjs +23 -0
- package/dist/card.cjs.map +1 -0
- package/dist/card.js +87 -0
- package/dist/card.js.map +1 -0
- package/dist/carousel.cjs +61 -0
- package/dist/carousel.cjs.map +1 -0
- package/dist/carousel.js +280 -0
- package/dist/carousel.js.map +1 -0
- package/dist/checkbox-group.cjs +18 -0
- package/dist/checkbox-group.cjs.map +1 -0
- package/dist/checkbox-group.js +118 -0
- package/dist/checkbox-group.js.map +1 -0
- package/dist/checkbox.cjs +11 -0
- package/dist/checkbox.cjs.map +1 -0
- package/dist/checkbox.js +88 -0
- package/dist/checkbox.js.map +1 -0
- package/dist/chip.cjs +42 -0
- package/dist/chip.cjs.map +1 -0
- package/dist/chip.js +133 -0
- package/dist/chip.js.map +1 -0
- package/dist/code-window.cjs +19 -0
- package/dist/code-window.cjs.map +1 -0
- package/dist/code-window.js +41 -0
- package/dist/code-window.js.map +1 -0
- package/dist/combobox.cjs +103 -0
- package/dist/combobox.cjs.map +1 -0
- package/dist/combobox.js +444 -0
- package/dist/combobox.js.map +1 -0
- package/dist/content/avatar/avatar-group.css?inline.cjs +2 -0
- package/dist/content/avatar/avatar-group.css?inline.cjs.map +1 -0
- package/dist/content/avatar/avatar-group.css?inline.js +6 -0
- package/dist/content/avatar/avatar-group.css?inline.js.map +1 -0
- package/dist/content/avatar/avatar.css?inline.cjs +2 -0
- package/dist/content/avatar/avatar.css?inline.cjs.map +1 -0
- package/dist/content/avatar/avatar.css?inline.js +6 -0
- package/dist/content/avatar/avatar.css?inline.js.map +1 -0
- package/dist/content/avatar/avatar.d.ts +88 -0
- package/dist/content/avatar/avatar.d.ts.map +1 -0
- package/dist/content/breadcrumb/breadcrumb-item.css?inline.cjs +2 -0
- package/dist/content/breadcrumb/breadcrumb-item.css?inline.cjs.map +1 -0
- package/dist/content/breadcrumb/breadcrumb-item.css?inline.js +6 -0
- package/dist/content/breadcrumb/breadcrumb-item.css?inline.js.map +1 -0
- package/dist/content/breadcrumb/breadcrumb.css?inline.cjs +2 -0
- package/dist/content/breadcrumb/breadcrumb.css?inline.cjs.map +1 -0
- package/dist/content/breadcrumb/breadcrumb.css?inline.js +6 -0
- package/dist/content/breadcrumb/breadcrumb.css?inline.js.map +1 -0
- package/dist/content/breadcrumb/breadcrumb.d.ts +57 -0
- package/dist/content/breadcrumb/breadcrumb.d.ts.map +1 -0
- package/dist/content/card/card.css?inline.cjs +2 -0
- package/dist/content/card/card.css?inline.cjs.map +1 -0
- package/dist/content/card/card.css?inline.js +6 -0
- package/dist/content/card/card.css?inline.js.map +1 -0
- package/dist/content/card/card.d.ts +74 -0
- package/dist/content/card/card.d.ts.map +1 -0
- package/dist/content/carousel/carousel-slide.cjs +2 -0
- package/dist/content/carousel/carousel-slide.cjs.map +1 -0
- package/dist/content/carousel/carousel-slide.css?inline.cjs +2 -0
- package/dist/content/carousel/carousel-slide.css?inline.cjs.map +1 -0
- package/dist/content/carousel/carousel-slide.css?inline.js +6 -0
- package/dist/content/carousel/carousel-slide.css?inline.js.map +1 -0
- package/dist/content/carousel/carousel-slide.d.ts +2 -0
- package/dist/content/carousel/carousel-slide.d.ts.map +1 -0
- package/dist/content/carousel/carousel-slide.js +18 -0
- package/dist/content/carousel/carousel-slide.js.map +1 -0
- package/dist/content/carousel/carousel.css?inline.cjs +2 -0
- package/dist/content/carousel/carousel.css?inline.cjs.map +1 -0
- package/dist/content/carousel/carousel.css?inline.js +6 -0
- package/dist/content/carousel/carousel.css?inline.js.map +1 -0
- package/dist/content/carousel/carousel.d.ts +110 -0
- package/dist/content/carousel/carousel.d.ts.map +1 -0
- package/dist/content/carousel/index.d.ts +3 -0
- package/dist/content/carousel/index.d.ts.map +1 -0
- package/dist/content/code-window/code-window.css?inline.cjs +2 -0
- package/dist/content/code-window/code-window.css?inline.cjs.map +1 -0
- package/dist/content/code-window/code-window.css?inline.js +6 -0
- package/dist/content/code-window/code-window.css?inline.js.map +1 -0
- package/dist/content/code-window/code-window.d.ts +61 -0
- package/dist/content/code-window/code-window.d.ts.map +1 -0
- package/dist/content/copy-command/copy-command.css?inline.cjs +2 -0
- package/dist/content/copy-command/copy-command.css?inline.cjs.map +1 -0
- package/dist/content/copy-command/copy-command.css?inline.js +6 -0
- package/dist/content/copy-command/copy-command.css?inline.js.map +1 -0
- package/dist/content/copy-command/copy-command.d.ts +66 -0
- package/dist/content/copy-command/copy-command.d.ts.map +1 -0
- package/dist/content/icon/icon.css?inline.cjs +2 -0
- package/dist/content/icon/icon.css?inline.cjs.map +1 -0
- package/dist/content/icon/icon.css?inline.js +6 -0
- package/dist/content/icon/icon.css?inline.js.map +1 -0
- package/dist/content/icon/icon.d.ts +45 -0
- package/dist/content/icon/icon.d.ts.map +1 -0
- package/dist/content/index.d.ts +23 -0
- package/dist/content/index.d.ts.map +1 -0
- package/dist/content/pagination/pagination.css?inline.cjs +2 -0
- package/dist/content/pagination/pagination.css?inline.cjs.map +1 -0
- package/dist/content/pagination/pagination.css?inline.js +6 -0
- package/dist/content/pagination/pagination.css?inline.js.map +1 -0
- package/dist/content/pagination/pagination.d.ts +61 -0
- package/dist/content/pagination/pagination.d.ts.map +1 -0
- package/dist/content/separator/separator.css?inline.cjs +2 -0
- package/dist/content/separator/separator.css?inline.cjs.map +1 -0
- package/dist/content/separator/separator.css?inline.js +6 -0
- package/dist/content/separator/separator.css?inline.js.map +1 -0
- package/dist/content/separator/separator.d.ts +38 -0
- package/dist/content/separator/separator.d.ts.map +1 -0
- package/dist/content/table/table.css?inline.cjs +2 -0
- package/dist/content/table/table.css?inline.cjs.map +1 -0
- package/dist/content/table/table.css?inline.js +6 -0
- package/dist/content/table/table.css?inline.js.map +1 -0
- package/dist/content/table/table.d.ts +76 -0
- package/dist/content/table/table.d.ts.map +1 -0
- package/dist/content/text/text.css?inline.cjs +2 -0
- package/dist/content/text/text.css?inline.cjs.map +1 -0
- package/dist/content/text/text.css?inline.js +6 -0
- package/dist/content/text/text.css?inline.js.map +1 -0
- package/dist/content/text/text.d.ts +55 -0
- package/dist/content/text/text.d.ts.map +1 -0
- package/dist/copy-command.cjs +17 -0
- package/dist/copy-command.cjs.map +1 -0
- package/dist/copy-command.js +55 -0
- package/dist/copy-command.js.map +1 -0
- package/dist/custom-elements.json +12641 -0
- package/dist/datagrid.cjs +435 -0
- package/dist/datagrid.cjs.map +1 -0
- package/dist/datagrid.js +764 -0
- package/dist/datagrid.js.map +1 -0
- package/dist/date-picker.cjs +133 -0
- package/dist/date-picker.cjs.map +1 -0
- package/dist/date-picker.js +315 -0
- package/dist/date-picker.js.map +1 -0
- package/dist/dialog.cjs +28 -0
- package/dist/dialog.cjs.map +1 -0
- package/dist/dialog.js +88 -0
- package/dist/dialog.js.map +1 -0
- package/dist/disclosure/accordion/accordion.css?inline.cjs +2 -0
- package/dist/disclosure/accordion/accordion.css?inline.cjs.map +1 -0
- package/dist/disclosure/accordion/accordion.css?inline.js +6 -0
- package/dist/disclosure/accordion/accordion.css?inline.js.map +1 -0
- package/dist/disclosure/accordion/accordion.d.ts +62 -0
- package/dist/disclosure/accordion/accordion.d.ts.map +1 -0
- package/dist/disclosure/accordion-item/accordion-item.css?inline.cjs +2 -0
- package/dist/disclosure/accordion-item/accordion-item.css?inline.cjs.map +1 -0
- package/dist/disclosure/accordion-item/accordion-item.css?inline.js +6 -0
- package/dist/disclosure/accordion-item/accordion-item.css?inline.js.map +1 -0
- package/dist/disclosure/accordion-item/accordion-item.d.ts +70 -0
- package/dist/disclosure/accordion-item/accordion-item.d.ts.map +1 -0
- package/dist/disclosure/index.d.ts +11 -0
- package/dist/disclosure/index.d.ts.map +1 -0
- package/dist/disclosure/tab-item/tab-item.css?inline.cjs +2 -0
- package/dist/disclosure/tab-item/tab-item.css?inline.cjs.map +1 -0
- package/dist/disclosure/tab-item/tab-item.css?inline.js +6 -0
- package/dist/disclosure/tab-item/tab-item.css?inline.js.map +1 -0
- package/dist/disclosure/tab-item/tab-item.d.ts +49 -0
- package/dist/disclosure/tab-item/tab-item.d.ts.map +1 -0
- package/dist/disclosure/tab-panel/tab-panel.css?inline.cjs +2 -0
- package/dist/disclosure/tab-panel/tab-panel.css?inline.cjs.map +1 -0
- package/dist/disclosure/tab-panel/tab-panel.css?inline.js +6 -0
- package/dist/disclosure/tab-panel/tab-panel.css?inline.js.map +1 -0
- package/dist/disclosure/tab-panel/tab-panel.d.ts +33 -0
- package/dist/disclosure/tab-panel/tab-panel.d.ts.map +1 -0
- package/dist/disclosure/tabs/tabs.css?inline.cjs +2 -0
- package/dist/disclosure/tabs/tabs.css?inline.cjs.map +1 -0
- package/dist/disclosure/tabs/tabs.css?inline.js +6 -0
- package/dist/disclosure/tabs/tabs.css?inline.js.map +1 -0
- package/dist/disclosure/tabs/tabs.d.ts +75 -0
- package/dist/disclosure/tabs/tabs.d.ts.map +1 -0
- package/dist/drawer.cjs +32 -0
- package/dist/drawer.cjs.map +1 -0
- package/dist/drawer.js +199 -0
- package/dist/drawer.js.map +1 -0
- package/dist/errors.cjs +2 -0
- package/dist/errors.cjs.map +1 -0
- package/dist/errors.d.ts +9 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +13 -0
- package/dist/errors.js.map +1 -0
- package/dist/feedback/alert/alert.css?inline.cjs +2 -0
- package/dist/feedback/alert/alert.css?inline.cjs.map +1 -0
- package/dist/feedback/alert/alert.css?inline.js +6 -0
- package/dist/feedback/alert/alert.css?inline.js.map +1 -0
- package/dist/feedback/alert/alert.d.ts +74 -0
- package/dist/feedback/alert/alert.d.ts.map +1 -0
- package/dist/feedback/async/async.css?inline.cjs +2 -0
- package/dist/feedback/async/async.css?inline.cjs.map +1 -0
- package/dist/feedback/async/async.css?inline.js +6 -0
- package/dist/feedback/async/async.css?inline.js.map +1 -0
- package/dist/feedback/async/async.d.ts +54 -0
- package/dist/feedback/async/async.d.ts.map +1 -0
- package/dist/feedback/badge/badge.css?inline.cjs +2 -0
- package/dist/feedback/badge/badge.css?inline.cjs.map +1 -0
- package/dist/feedback/badge/badge.css?inline.js +6 -0
- package/dist/feedback/badge/badge.css?inline.js.map +1 -0
- package/dist/feedback/badge/badge.d.ts +69 -0
- package/dist/feedback/badge/badge.d.ts.map +1 -0
- package/dist/feedback/chip/chip.css?inline.cjs +2 -0
- package/dist/feedback/chip/chip.css?inline.cjs.map +1 -0
- package/dist/feedback/chip/chip.css?inline.js +6 -0
- package/dist/feedback/chip/chip.css?inline.js.map +1 -0
- package/dist/feedback/chip/chip.d.ts +136 -0
- package/dist/feedback/chip/chip.d.ts.map +1 -0
- package/dist/feedback/index.d.ts +17 -0
- package/dist/feedback/index.d.ts.map +1 -0
- package/dist/feedback/password-strength/password-strength.css?inline.cjs +2 -0
- package/dist/feedback/password-strength/password-strength.css?inline.cjs.map +1 -0
- package/dist/feedback/password-strength/password-strength.css?inline.js +6 -0
- package/dist/feedback/password-strength/password-strength.css?inline.js.map +1 -0
- package/dist/feedback/password-strength/password-strength.d.ts +66 -0
- package/dist/feedback/password-strength/password-strength.d.ts.map +1 -0
- package/dist/feedback/progress/progress.css?inline.cjs +2 -0
- package/dist/feedback/progress/progress.css?inline.cjs.map +1 -0
- package/dist/feedback/progress/progress.css?inline.js +6 -0
- package/dist/feedback/progress/progress.css?inline.js.map +1 -0
- package/dist/feedback/progress/progress.d.ts +68 -0
- package/dist/feedback/progress/progress.d.ts.map +1 -0
- package/dist/feedback/skeleton/skeleton.css?inline.cjs +2 -0
- package/dist/feedback/skeleton/skeleton.css?inline.cjs.map +1 -0
- package/dist/feedback/skeleton/skeleton.css?inline.js +6 -0
- package/dist/feedback/skeleton/skeleton.css?inline.js.map +1 -0
- package/dist/feedback/skeleton/skeleton.d.ts +63 -0
- package/dist/feedback/skeleton/skeleton.d.ts.map +1 -0
- package/dist/feedback/toast/index.d.ts +2 -0
- package/dist/feedback/toast/index.d.ts.map +1 -0
- package/dist/feedback/toast/toast.css?inline.cjs +2 -0
- package/dist/feedback/toast/toast.css?inline.cjs.map +1 -0
- package/dist/feedback/toast/toast.css?inline.js +6 -0
- package/dist/feedback/toast/toast.css?inline.js.map +1 -0
- package/dist/feedback/toast/toast.d.ts +127 -0
- package/dist/feedback/toast/toast.d.ts.map +1 -0
- package/dist/file-input.cjs +70 -0
- package/dist/file-input.cjs.map +1 -0
- package/dist/file-input.js +209 -0
- package/dist/file-input.js.map +1 -0
- package/dist/form.cjs +11 -0
- package/dist/form.cjs.map +1 -0
- package/dist/form.js +56 -0
- package/dist/form.js.map +1 -0
- package/dist/grid-item.cjs +2 -0
- package/dist/grid-item.cjs.map +1 -0
- package/dist/grid-item.js +35 -0
- package/dist/grid-item.js.map +1 -0
- package/dist/grid.cjs +2 -0
- package/dist/grid.cjs.map +1 -0
- package/dist/grid.js +90 -0
- package/dist/grid.js.map +1 -0
- package/dist/headless/_internal.d.ts +17 -0
- package/dist/headless/_internal.d.ts.map +1 -0
- package/dist/headless/announcer.cjs +2 -0
- package/dist/headless/announcer.cjs.map +1 -0
- package/dist/headless/announcer.d.ts +25 -0
- package/dist/headless/announcer.d.ts.map +1 -0
- package/dist/headless/announcer.js +24 -0
- package/dist/headless/announcer.js.map +1 -0
- package/dist/headless/checkable.cjs +2 -0
- package/dist/headless/checkable.cjs.map +1 -0
- package/dist/headless/checkable.d.ts +42 -0
- package/dist/headless/checkable.d.ts.map +1 -0
- package/dist/headless/checkable.js +36 -0
- package/dist/headless/checkable.js.map +1 -0
- package/dist/headless/choice-field.cjs +2 -0
- package/dist/headless/choice-field.cjs.map +1 -0
- package/dist/headless/choice-field.d.ts +36 -0
- package/dist/headless/choice-field.d.ts.map +1 -0
- package/dist/headless/choice-field.js +42 -0
- package/dist/headless/choice-field.js.map +1 -0
- package/dist/headless/datagrid.cjs +2 -0
- package/dist/headless/datagrid.cjs.map +1 -0
- package/dist/headless/datagrid.d.ts +158 -0
- package/dist/headless/datagrid.d.ts.map +1 -0
- package/dist/headless/datagrid.js +55 -0
- package/dist/headless/datagrid.js.map +1 -0
- package/dist/headless/date-picker.cjs +2 -0
- package/dist/headless/date-picker.cjs.map +1 -0
- package/dist/headless/date-picker.d.ts +114 -0
- package/dist/headless/date-picker.d.ts.map +1 -0
- package/dist/headless/date-picker.js +184 -0
- package/dist/headless/date-picker.js.map +1 -0
- package/dist/headless/dialog-focus.cjs +2 -0
- package/dist/headless/dialog-focus.cjs.map +1 -0
- package/dist/headless/dialog-focus.d.ts +40 -0
- package/dist/headless/dialog-focus.d.ts.map +1 -0
- package/dist/headless/dialog-focus.js +22 -0
- package/dist/headless/dialog-focus.js.map +1 -0
- package/dist/headless/direction.cjs +2 -0
- package/dist/headless/direction.cjs.map +1 -0
- package/dist/headless/direction.d.ts +11 -0
- package/dist/headless/direction.d.ts.map +1 -0
- package/dist/headless/direction.js +14 -0
- package/dist/headless/direction.js.map +1 -0
- package/dist/headless/field-base.cjs +2 -0
- package/dist/headless/field-base.cjs.map +1 -0
- package/dist/headless/field-base.d.ts +148 -0
- package/dist/headless/field-base.d.ts.map +1 -0
- package/dist/headless/field-base.js +46 -0
- package/dist/headless/field-base.js.map +1 -0
- package/dist/headless/focus-trap.cjs +2 -0
- package/dist/headless/focus-trap.cjs.map +1 -0
- package/dist/headless/focus-trap.d.ts +45 -0
- package/dist/headless/focus-trap.d.ts.map +1 -0
- package/dist/headless/focus-trap.js +51 -0
- package/dist/headless/focus-trap.js.map +1 -0
- package/dist/headless/focus.cjs +2 -0
- package/dist/headless/focus.cjs.map +1 -0
- package/dist/headless/focus.d.ts +34 -0
- package/dist/headless/focus.d.ts.map +1 -0
- package/dist/headless/focus.js +34 -0
- package/dist/headless/focus.js.map +1 -0
- package/dist/headless/index.d.ts +28 -0
- package/dist/headless/index.d.ts.map +1 -0
- package/dist/headless/keyboard.cjs +2 -0
- package/dist/headless/keyboard.cjs.map +1 -0
- package/dist/headless/keyboard.d.ts +52 -0
- package/dist/headless/keyboard.d.ts.map +1 -0
- package/dist/headless/keyboard.js +29 -0
- package/dist/headless/keyboard.js.map +1 -0
- package/dist/headless/light-dom.cjs +2 -0
- package/dist/headless/light-dom.cjs.map +1 -0
- package/dist/headless/light-dom.d.ts +12 -0
- package/dist/headless/light-dom.d.ts.map +1 -0
- package/dist/headless/light-dom.js +6 -0
- package/dist/headless/light-dom.js.map +1 -0
- package/dist/headless/nav.cjs +2 -0
- package/dist/headless/nav.cjs.map +1 -0
- package/dist/headless/nav.d.ts +66 -0
- package/dist/headless/nav.d.ts.map +1 -0
- package/dist/headless/nav.js +115 -0
- package/dist/headless/nav.js.map +1 -0
- package/dist/headless/numbers.cjs +2 -0
- package/dist/headless/numbers.cjs.map +1 -0
- package/dist/headless/numbers.d.ts +14 -0
- package/dist/headless/numbers.d.ts.map +1 -0
- package/dist/headless/numbers.js +9 -0
- package/dist/headless/numbers.js.map +1 -0
- package/dist/headless/option-list.cjs +2 -0
- package/dist/headless/option-list.cjs.map +1 -0
- package/dist/headless/option-list.d.ts +107 -0
- package/dist/headless/option-list.d.ts.map +1 -0
- package/dist/headless/option-list.js +66 -0
- package/dist/headless/option-list.js.map +1 -0
- package/dist/headless/ore.cjs +2 -0
- package/dist/headless/ore.cjs.map +1 -0
- package/dist/headless/ore.d.ts +20 -0
- package/dist/headless/ore.d.ts.map +1 -0
- package/dist/headless/ore.js +9 -0
- package/dist/headless/ore.js.map +1 -0
- package/dist/headless/overlay.cjs +2 -0
- package/dist/headless/overlay.cjs.map +1 -0
- package/dist/headless/overlay.d.ts +62 -0
- package/dist/headless/overlay.d.ts.map +1 -0
- package/dist/headless/overlay.js +29 -0
- package/dist/headless/overlay.js.map +1 -0
- package/dist/headless/paginated-list.cjs +2 -0
- package/dist/headless/paginated-list.cjs.map +1 -0
- package/dist/headless/paginated-list.d.ts +42 -0
- package/dist/headless/paginated-list.d.ts.map +1 -0
- package/dist/headless/paginated-list.js +34 -0
- package/dist/headless/paginated-list.js.map +1 -0
- package/dist/headless/parse.cjs +2 -0
- package/dist/headless/parse.cjs.map +1 -0
- package/dist/headless/parse.d.ts +15 -0
- package/dist/headless/parse.d.ts.map +1 -0
- package/dist/headless/parse.js +9 -0
- package/dist/headless/parse.js.map +1 -0
- package/dist/headless/positioner.cjs +2 -0
- package/dist/headless/positioner.cjs.map +1 -0
- package/dist/headless/positioner.d.ts +40 -0
- package/dist/headless/positioner.d.ts.map +1 -0
- package/dist/headless/positioner.js +38 -0
- package/dist/headless/positioner.js.map +1 -0
- package/dist/headless/selection-control.cjs +2 -0
- package/dist/headless/selection-control.cjs.map +1 -0
- package/dist/headless/selection-control.d.ts +30 -0
- package/dist/headless/selection-control.d.ts.map +1 -0
- package/dist/headless/selection-control.js +44 -0
- package/dist/headless/selection-control.js.map +1 -0
- package/dist/headless/signals.cjs +2 -0
- package/dist/headless/signals.cjs.map +1 -0
- package/dist/headless/signals.d.ts +20 -0
- package/dist/headless/signals.d.ts.map +1 -0
- package/dist/headless/signals.js +12 -0
- package/dist/headless/signals.js.map +1 -0
- package/dist/headless/slider.cjs +2 -0
- package/dist/headless/slider.cjs.map +1 -0
- package/dist/headless/slider.d.ts +28 -0
- package/dist/headless/slider.d.ts.map +1 -0
- package/dist/headless/slider.js +40 -0
- package/dist/headless/slider.js.map +1 -0
- package/dist/headless/sort-control.cjs +2 -0
- package/dist/headless/sort-control.cjs.map +1 -0
- package/dist/headless/sort-control.d.ts +22 -0
- package/dist/headless/sort-control.d.ts.map +1 -0
- package/dist/headless/sort-control.js +36 -0
- package/dist/headless/sort-control.js.map +1 -0
- package/dist/headless/spinner.cjs +2 -0
- package/dist/headless/spinner.cjs.map +1 -0
- package/dist/headless/spinner.d.ts +19 -0
- package/dist/headless/spinner.d.ts.map +1 -0
- package/dist/headless/spinner.js +52 -0
- package/dist/headless/spinner.js.map +1 -0
- package/dist/headless/swipe.cjs +2 -0
- package/dist/headless/swipe.cjs.map +1 -0
- package/dist/headless/swipe.d.ts +38 -0
- package/dist/headless/swipe.d.ts.map +1 -0
- package/dist/headless/swipe.js +58 -0
- package/dist/headless/swipe.js.map +1 -0
- package/dist/headless/text-field.cjs +2 -0
- package/dist/headless/text-field.cjs.map +1 -0
- package/dist/headless/text-field.d.ts +45 -0
- package/dist/headless/text-field.d.ts.map +1 -0
- package/dist/headless/text-field.js +41 -0
- package/dist/headless/text-field.js.map +1 -0
- package/dist/headless/typeahead.cjs +2 -0
- package/dist/headless/typeahead.cjs.map +1 -0
- package/dist/headless/typeahead.d.ts +53 -0
- package/dist/headless/typeahead.d.ts.map +1 -0
- package/dist/headless/typeahead.js +23 -0
- package/dist/headless/typeahead.js.map +1 -0
- package/dist/headless.cjs +1 -0
- package/dist/headless.js +26 -0
- package/dist/icon.cjs +2 -0
- package/dist/icon.cjs.map +1 -0
- package/dist/icon.js +87 -0
- package/dist/icon.js.map +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +61 -0
- package/dist/input.cjs +67 -0
- package/dist/input.cjs.map +1 -0
- package/dist/input.js +184 -0
- package/dist/input.js.map +1 -0
- package/dist/inputs/button/button.css?inline.cjs +2 -0
- package/dist/inputs/button/button.css?inline.cjs.map +1 -0
- package/dist/inputs/button/button.css?inline.js +6 -0
- package/dist/inputs/button/button.css?inline.js.map +1 -0
- package/dist/inputs/button/button.d.ts +85 -0
- package/dist/inputs/button/button.d.ts.map +1 -0
- package/dist/inputs/button-group/button-group.css?inline.cjs +2 -0
- package/dist/inputs/button-group/button-group.css?inline.cjs.map +1 -0
- package/dist/inputs/button-group/button-group.css?inline.js +6 -0
- package/dist/inputs/button-group/button-group.css?inline.js.map +1 -0
- package/dist/inputs/button-group/button-group.d.ts +64 -0
- package/dist/inputs/button-group/button-group.d.ts.map +1 -0
- package/dist/inputs/calendar/calendar.css?inline.cjs +2 -0
- package/dist/inputs/calendar/calendar.css?inline.cjs.map +1 -0
- package/dist/inputs/calendar/calendar.css?inline.js +6 -0
- package/dist/inputs/calendar/calendar.css?inline.js.map +1 -0
- package/dist/inputs/calendar/calendar.d.ts +134 -0
- package/dist/inputs/calendar/calendar.d.ts.map +1 -0
- package/dist/inputs/checkbox/checkbox.css?inline.cjs +2 -0
- package/dist/inputs/checkbox/checkbox.css?inline.cjs.map +1 -0
- package/dist/inputs/checkbox/checkbox.css?inline.js +6 -0
- package/dist/inputs/checkbox/checkbox.css?inline.js.map +1 -0
- package/dist/inputs/checkbox/checkbox.d.ts +60 -0
- package/dist/inputs/checkbox/checkbox.d.ts.map +1 -0
- package/dist/inputs/checkbox-group/checkbox-group.css?inline.cjs +2 -0
- package/dist/inputs/checkbox-group/checkbox-group.css?inline.cjs.map +1 -0
- package/dist/inputs/checkbox-group/checkbox-group.css?inline.js +6 -0
- package/dist/inputs/checkbox-group/checkbox-group.css?inline.js.map +1 -0
- package/dist/inputs/checkbox-group/checkbox-group.d.ts +75 -0
- package/dist/inputs/checkbox-group/checkbox-group.d.ts.map +1 -0
- package/dist/inputs/combobox/combobox-options.cjs +2 -0
- package/dist/inputs/combobox/combobox-options.cjs.map +1 -0
- package/dist/inputs/combobox/combobox-options.d.ts +6 -0
- package/dist/inputs/combobox/combobox-options.d.ts.map +1 -0
- package/dist/inputs/combobox/combobox-options.js +26 -0
- package/dist/inputs/combobox/combobox-options.js.map +1 -0
- package/dist/inputs/combobox/combobox.css?inline.cjs +2 -0
- package/dist/inputs/combobox/combobox.css?inline.cjs.map +1 -0
- package/dist/inputs/combobox/combobox.css?inline.js +6 -0
- package/dist/inputs/combobox/combobox.css?inline.js.map +1 -0
- package/dist/inputs/combobox/combobox.d.ts +45 -0
- package/dist/inputs/combobox/combobox.d.ts.map +1 -0
- package/dist/inputs/combobox/combobox.types.d.ts +45 -0
- package/dist/inputs/combobox/combobox.types.d.ts.map +1 -0
- package/dist/inputs/datagrid/datagrid-column.cjs +2 -0
- package/dist/inputs/datagrid/datagrid-column.cjs.map +1 -0
- package/dist/inputs/datagrid/datagrid-column.d.ts +7 -0
- package/dist/inputs/datagrid/datagrid-column.d.ts.map +1 -0
- package/dist/inputs/datagrid/datagrid-column.js +31 -0
- package/dist/inputs/datagrid/datagrid-column.js.map +1 -0
- package/dist/inputs/datagrid/datagrid-controls.cjs +2 -0
- package/dist/inputs/datagrid/datagrid-controls.cjs.map +1 -0
- package/dist/inputs/datagrid/datagrid-controls.d.ts +98 -0
- package/dist/inputs/datagrid/datagrid-controls.d.ts.map +1 -0
- package/dist/inputs/datagrid/datagrid-controls.js +147 -0
- package/dist/inputs/datagrid/datagrid-controls.js.map +1 -0
- package/dist/inputs/datagrid/datagrid-nav.cjs +2 -0
- package/dist/inputs/datagrid/datagrid-nav.cjs.map +1 -0
- package/dist/inputs/datagrid/datagrid-nav.d.ts +33 -0
- package/dist/inputs/datagrid/datagrid-nav.d.ts.map +1 -0
- package/dist/inputs/datagrid/datagrid-nav.js +51 -0
- package/dist/inputs/datagrid/datagrid-nav.js.map +1 -0
- package/dist/inputs/datagrid/datagrid.css?inline.cjs +2 -0
- package/dist/inputs/datagrid/datagrid.css?inline.cjs.map +1 -0
- package/dist/inputs/datagrid/datagrid.css?inline.js +6 -0
- package/dist/inputs/datagrid/datagrid.css?inline.js.map +1 -0
- package/dist/inputs/datagrid/datagrid.d.ts +302 -0
- package/dist/inputs/datagrid/datagrid.d.ts.map +1 -0
- package/dist/inputs/date-picker/date-picker.css?inline.cjs +2 -0
- package/dist/inputs/date-picker/date-picker.css?inline.cjs.map +1 -0
- package/dist/inputs/date-picker/date-picker.css?inline.js +6 -0
- package/dist/inputs/date-picker/date-picker.css?inline.js.map +1 -0
- package/dist/inputs/date-picker/date-picker.d.ts +112 -0
- package/dist/inputs/date-picker/date-picker.d.ts.map +1 -0
- package/dist/inputs/file-input/file-input.css?inline.cjs +2 -0
- package/dist/inputs/file-input/file-input.css?inline.cjs.map +1 -0
- package/dist/inputs/file-input/file-input.css?inline.js +6 -0
- package/dist/inputs/file-input/file-input.css?inline.js.map +1 -0
- package/dist/inputs/file-input/file-input.d.ts +90 -0
- package/dist/inputs/file-input/file-input.d.ts.map +1 -0
- package/dist/inputs/form/form.css?inline.cjs +2 -0
- package/dist/inputs/form/form.css?inline.cjs.map +1 -0
- package/dist/inputs/form/form.css?inline.js +6 -0
- package/dist/inputs/form/form.css?inline.js.map +1 -0
- package/dist/inputs/form/form.d.ts +59 -0
- package/dist/inputs/form/form.d.ts.map +1 -0
- package/dist/inputs/index.d.ts +47 -0
- package/dist/inputs/index.d.ts.map +1 -0
- package/dist/inputs/input/input.css?inline.cjs +2 -0
- package/dist/inputs/input/input.css?inline.cjs.map +1 -0
- package/dist/inputs/input/input.css?inline.js +6 -0
- package/dist/inputs/input/input.css?inline.js.map +1 -0
- package/dist/inputs/input/input.d.ts +96 -0
- package/dist/inputs/input/input.d.ts.map +1 -0
- package/dist/inputs/number-input/number-input.css?inline.cjs +2 -0
- package/dist/inputs/number-input/number-input.css?inline.cjs.map +1 -0
- package/dist/inputs/number-input/number-input.css?inline.js +6 -0
- package/dist/inputs/number-input/number-input.css?inline.js.map +1 -0
- package/dist/inputs/number-input/number-input.d.ts +102 -0
- package/dist/inputs/number-input/number-input.d.ts.map +1 -0
- package/dist/inputs/otp-input/otp-input.css?inline.cjs +2 -0
- package/dist/inputs/otp-input/otp-input.css?inline.cjs.map +1 -0
- package/dist/inputs/otp-input/otp-input.css?inline.js +6 -0
- package/dist/inputs/otp-input/otp-input.css?inline.js.map +1 -0
- package/dist/inputs/otp-input/otp-input.d.ts +82 -0
- package/dist/inputs/otp-input/otp-input.d.ts.map +1 -0
- package/dist/inputs/radio/radio.css?inline.cjs +2 -0
- package/dist/inputs/radio/radio.css?inline.cjs.map +1 -0
- package/dist/inputs/radio/radio.css?inline.js +6 -0
- package/dist/inputs/radio/radio.css?inline.js.map +1 -0
- package/dist/inputs/radio/radio.d.ts +56 -0
- package/dist/inputs/radio/radio.d.ts.map +1 -0
- package/dist/inputs/radio-group/radio-group.css?inline.cjs +2 -0
- package/dist/inputs/radio-group/radio-group.css?inline.cjs.map +1 -0
- package/dist/inputs/radio-group/radio-group.css?inline.js +6 -0
- package/dist/inputs/radio-group/radio-group.css?inline.js.map +1 -0
- package/dist/inputs/radio-group/radio-group.d.ts +74 -0
- package/dist/inputs/radio-group/radio-group.d.ts.map +1 -0
- package/dist/inputs/rating/rating.css?inline.cjs +2 -0
- package/dist/inputs/rating/rating.css?inline.cjs.map +1 -0
- package/dist/inputs/rating/rating.css?inline.js +6 -0
- package/dist/inputs/rating/rating.css?inline.js.map +1 -0
- package/dist/inputs/rating/rating.d.ts +68 -0
- package/dist/inputs/rating/rating.d.ts.map +1 -0
- package/dist/inputs/select/select.css?inline.cjs +2 -0
- package/dist/inputs/select/select.css?inline.cjs.map +1 -0
- package/dist/inputs/select/select.css?inline.js +6 -0
- package/dist/inputs/select/select.css?inline.js.map +1 -0
- package/dist/inputs/select/select.d.ts +89 -0
- package/dist/inputs/select/select.d.ts.map +1 -0
- package/dist/inputs/shared/field-binding.cjs +2 -0
- package/dist/inputs/shared/field-binding.cjs.map +1 -0
- package/dist/inputs/shared/field-binding.d.ts +31 -0
- package/dist/inputs/shared/field-binding.d.ts.map +1 -0
- package/dist/inputs/shared/field-binding.js +31 -0
- package/dist/inputs/shared/field-binding.js.map +1 -0
- package/dist/inputs/shared/form-context.cjs +2 -0
- package/dist/inputs/shared/form-context.cjs.map +1 -0
- package/dist/inputs/shared/form-context.d.ts +49 -0
- package/dist/inputs/shared/form-context.d.ts.map +1 -0
- package/dist/inputs/shared/form-context.js +15 -0
- package/dist/inputs/shared/form-context.js.map +1 -0
- package/dist/inputs/shared/index.d.ts +5 -0
- package/dist/inputs/shared/index.d.ts.map +1 -0
- package/dist/inputs/shared/templates.cjs +11 -0
- package/dist/inputs/shared/templates.cjs.map +1 -0
- package/dist/inputs/shared/templates.d.ts +13 -0
- package/dist/inputs/shared/templates.d.ts.map +1 -0
- package/dist/inputs/shared/templates.js +18 -0
- package/dist/inputs/shared/templates.js.map +1 -0
- package/dist/inputs/shared/use-form-action.cjs +2 -0
- package/dist/inputs/shared/use-form-action.cjs.map +1 -0
- package/dist/inputs/shared/use-form-action.d.ts +17 -0
- package/dist/inputs/shared/use-form-action.d.ts.map +1 -0
- package/dist/inputs/shared/use-form-action.js +19 -0
- package/dist/inputs/shared/use-form-action.js.map +1 -0
- package/dist/inputs/slider/slider.css?inline.cjs +2 -0
- package/dist/inputs/slider/slider.css?inline.cjs.map +1 -0
- package/dist/inputs/slider/slider.css?inline.js +6 -0
- package/dist/inputs/slider/slider.css?inline.js.map +1 -0
- package/dist/inputs/slider/slider.d.ts +95 -0
- package/dist/inputs/slider/slider.d.ts.map +1 -0
- package/dist/inputs/switch/switch.css?inline.cjs +2 -0
- package/dist/inputs/switch/switch.css?inline.cjs.map +1 -0
- package/dist/inputs/switch/switch.css?inline.js +6 -0
- package/dist/inputs/switch/switch.css?inline.js.map +1 -0
- package/dist/inputs/switch/switch.d.ts +56 -0
- package/dist/inputs/switch/switch.d.ts.map +1 -0
- package/dist/inputs/textarea/textarea.css?inline.cjs +2 -0
- package/dist/inputs/textarea/textarea.css?inline.cjs.map +1 -0
- package/dist/inputs/textarea/textarea.css?inline.js +6 -0
- package/dist/inputs/textarea/textarea.css?inline.js.map +1 -0
- package/dist/inputs/textarea/textarea.d.ts +91 -0
- package/dist/inputs/textarea/textarea.d.ts.map +1 -0
- package/dist/inputs/time-picker/time-picker.css?inline.cjs +2 -0
- package/dist/inputs/time-picker/time-picker.css?inline.cjs.map +1 -0
- package/dist/inputs/time-picker/time-picker.css?inline.js +6 -0
- package/dist/inputs/time-picker/time-picker.css?inline.js.map +1 -0
- package/dist/inputs/time-picker/time-picker.d.ts +103 -0
- package/dist/inputs/time-picker/time-picker.d.ts.map +1 -0
- package/dist/layout/box/box.css?inline.cjs +2 -0
- package/dist/layout/box/box.css?inline.cjs.map +1 -0
- package/dist/layout/box/box.css?inline.js +6 -0
- package/dist/layout/box/box.css?inline.js.map +1 -0
- package/dist/layout/box/box.d.ts +52 -0
- package/dist/layout/box/box.d.ts.map +1 -0
- package/dist/layout/grid/grid.css?inline.cjs +2 -0
- package/dist/layout/grid/grid.css?inline.cjs.map +1 -0
- package/dist/layout/grid/grid.css?inline.js +6 -0
- package/dist/layout/grid/grid.css?inline.js.map +1 -0
- package/dist/layout/grid/grid.d.ts +105 -0
- package/dist/layout/grid/grid.d.ts.map +1 -0
- package/dist/layout/grid-item/grid-item.css?inline.cjs +2 -0
- package/dist/layout/grid-item/grid-item.css?inline.cjs.map +1 -0
- package/dist/layout/grid-item/grid-item.css?inline.js +6 -0
- package/dist/layout/grid-item/grid-item.css?inline.js.map +1 -0
- package/dist/layout/grid-item/grid-item.d.ts +54 -0
- package/dist/layout/grid-item/grid-item.d.ts.map +1 -0
- package/dist/layout/index.d.ts +11 -0
- package/dist/layout/index.d.ts.map +1 -0
- package/dist/layout/navbar/navbar.css?inline.cjs +2 -0
- package/dist/layout/navbar/navbar.css?inline.cjs.map +1 -0
- package/dist/layout/navbar/navbar.css?inline.js +6 -0
- package/dist/layout/navbar/navbar.css?inline.js.map +1 -0
- package/dist/layout/navbar/navbar.d.ts +153 -0
- package/dist/layout/navbar/navbar.d.ts.map +1 -0
- package/dist/layout/sidebar/sidebar-group.css?inline.cjs +2 -0
- package/dist/layout/sidebar/sidebar-group.css?inline.cjs.map +1 -0
- package/dist/layout/sidebar/sidebar-group.css?inline.js +6 -0
- package/dist/layout/sidebar/sidebar-group.css?inline.js.map +1 -0
- package/dist/layout/sidebar/sidebar-item.css?inline.cjs +2 -0
- package/dist/layout/sidebar/sidebar-item.css?inline.cjs.map +1 -0
- package/dist/layout/sidebar/sidebar-item.css?inline.js +6 -0
- package/dist/layout/sidebar/sidebar-item.css?inline.js.map +1 -0
- package/dist/layout/sidebar/sidebar.css?inline.cjs +2 -0
- package/dist/layout/sidebar/sidebar.css?inline.cjs.map +1 -0
- package/dist/layout/sidebar/sidebar.css?inline.js +6 -0
- package/dist/layout/sidebar/sidebar.css?inline.js.map +1 -0
- package/dist/layout/sidebar/sidebar.d.ts +226 -0
- package/dist/layout/sidebar/sidebar.d.ts.map +1 -0
- package/dist/menu.cjs +30 -0
- package/dist/menu.cjs.map +1 -0
- package/dist/menu.js +197 -0
- package/dist/menu.js.map +1 -0
- package/dist/navbar.cjs +68 -0
- package/dist/navbar.cjs.map +1 -0
- package/dist/navbar.js +283 -0
- package/dist/navbar.js.map +1 -0
- package/dist/number-input.cjs +40 -0
- package/dist/number-input.cjs.map +1 -0
- package/dist/number-input.js +141 -0
- package/dist/number-input.js.map +1 -0
- package/dist/ore/dist/_dev.cjs +2 -0
- package/dist/ore/dist/_dev.cjs.map +1 -0
- package/dist/ore/dist/_dev.js +12 -0
- package/dist/ore/dist/_dev.js.map +1 -0
- package/dist/ore/dist/aria.cjs +2 -0
- package/dist/ore/dist/aria.cjs.map +1 -0
- package/dist/ore/dist/aria.js +37 -0
- package/dist/ore/dist/aria.js.map +1 -0
- package/dist/ore/dist/base-element.cjs +2 -0
- package/dist/ore/dist/base-element.cjs.map +1 -0
- package/dist/ore/dist/base-element.js +146 -0
- package/dist/ore/dist/base-element.js.map +1 -0
- package/dist/ore/dist/context-bag.cjs +2 -0
- package/dist/ore/dist/context-bag.cjs.map +1 -0
- package/dist/ore/dist/context-bag.js +28 -0
- package/dist/ore/dist/context-bag.js.map +1 -0
- package/dist/ore/dist/context.cjs +2 -0
- package/dist/ore/dist/context.cjs.map +1 -0
- package/dist/ore/dist/context.js +38 -0
- package/dist/ore/dist/context.js.map +1 -0
- package/dist/ore/dist/define.cjs +2 -0
- package/dist/ore/dist/define.cjs.map +1 -0
- package/dist/ore/dist/define.js +27 -0
- package/dist/ore/dist/define.js.map +1 -0
- package/dist/ore/dist/directives/classMap.cjs +1 -0
- package/dist/ore/dist/directives/classMap.js +1 -0
- package/dist/ore/dist/directives/each.cjs +1 -0
- package/dist/ore/dist/directives/each.js +5 -0
- package/dist/ore/dist/directives/live.cjs +2 -0
- package/dist/ore/dist/directives/live.cjs.map +1 -0
- package/dist/ore/dist/directives/live.js +6 -0
- package/dist/ore/dist/directives/live.js.map +1 -0
- package/dist/ore/dist/directives/model.cjs +1 -0
- package/dist/ore/dist/directives/model.js +3 -0
- package/dist/ore/dist/directives/raw.cjs +2 -0
- package/dist/ore/dist/directives/raw.cjs.map +1 -0
- package/dist/ore/dist/directives/raw.js +35 -0
- package/dist/ore/dist/directives/raw.js.map +1 -0
- package/dist/ore/dist/directives/styleMap.cjs +2 -0
- package/dist/ore/dist/directives/styleMap.cjs.map +1 -0
- package/dist/ore/dist/directives/styleMap.js +20 -0
- package/dist/ore/dist/directives/styleMap.js.map +1 -0
- package/dist/ore/dist/directives/when.cjs +2 -0
- package/dist/ore/dist/directives/when.cjs.map +1 -0
- package/dist/ore/dist/directives/when.js +33 -0
- package/dist/ore/dist/directives/when.js.map +1 -0
- package/dist/ore/dist/directives.cjs +1 -0
- package/dist/ore/dist/directives.js +8 -0
- package/dist/ore/dist/errors.cjs +3 -0
- package/dist/ore/dist/errors.cjs.map +1 -0
- package/dist/ore/dist/errors.js +41 -0
- package/dist/ore/dist/errors.js.map +1 -0
- package/dist/ore/dist/host-bind.cjs +2 -0
- package/dist/ore/dist/host-bind.cjs.map +1 -0
- package/dist/ore/dist/host-bind.js +60 -0
- package/dist/ore/dist/host-bind.js.map +1 -0
- package/dist/ore/dist/observers/intersection-observe.cjs +2 -0
- package/dist/ore/dist/observers/intersection-observe.cjs.map +1 -0
- package/dist/ore/dist/observers/intersection-observe.js +12 -0
- package/dist/ore/dist/observers/intersection-observe.js.map +1 -0
- package/dist/ore/dist/observers/media-observe.cjs +1 -0
- package/dist/ore/dist/observers/media-observe.js +1 -0
- package/dist/ore/dist/observers/mutation-observe.cjs +1 -0
- package/dist/ore/dist/observers/mutation-observe.js +1 -0
- package/dist/ore/dist/observers/resize-observe.cjs +2 -0
- package/dist/ore/dist/observers/resize-observe.cjs.map +1 -0
- package/dist/ore/dist/observers/resize-observe.js +20 -0
- package/dist/ore/dist/observers/resize-observe.js.map +1 -0
- package/dist/ore/dist/observers.cjs +1 -0
- package/dist/ore/dist/observers.js +5 -0
- package/dist/ore/dist/props.cjs +2 -0
- package/dist/ore/dist/props.cjs.map +1 -0
- package/dist/ore/dist/props.js +54 -0
- package/dist/ore/dist/props.js.map +1 -0
- package/dist/ore/dist/runtime.cjs +2 -0
- package/dist/ore/dist/runtime.cjs.map +1 -0
- package/dist/ore/dist/runtime.js +33 -0
- package/dist/ore/dist/runtime.js.map +1 -0
- package/dist/ore/dist/slots.cjs +2 -0
- package/dist/ore/dist/slots.cjs.map +1 -0
- package/dist/ore/dist/slots.js +61 -0
- package/dist/ore/dist/slots.js.map +1 -0
- package/dist/ore/dist/testing/flush.cjs +2 -0
- package/dist/ore/dist/testing/flush.cjs.map +1 -0
- package/dist/ore/dist/testing/flush.js +11 -0
- package/dist/ore/dist/testing/flush.js.map +1 -0
- package/dist/ore/dist/testing/mount.cjs +2 -0
- package/dist/ore/dist/testing/mount.cjs.map +1 -0
- package/dist/ore/dist/testing/mount.js +94 -0
- package/dist/ore/dist/testing/mount.js.map +1 -0
- package/dist/ore/dist/testing/query.cjs +2 -0
- package/dist/ore/dist/testing/query.cjs.map +1 -0
- package/dist/ore/dist/testing/query.js +12 -0
- package/dist/ore/dist/testing/query.js.map +1 -0
- package/dist/ore/dist/testing/render-hook.cjs +1 -0
- package/dist/ore/dist/testing/render-hook.js +4 -0
- package/dist/ore/dist/testing/testing.cjs +1 -0
- package/dist/ore/dist/testing/testing.js +4 -0
- package/dist/ore/dist/testing/wait.cjs +1 -0
- package/dist/ore/dist/testing/wait.js +1 -0
- package/dist/ore/dist/testing.cjs +1 -0
- package/dist/ore/dist/testing.js +6 -0
- package/dist/ore/dist/types/bindings.cjs +2 -0
- package/dist/ore/dist/types/bindings.cjs.map +1 -0
- package/dist/ore/dist/types/bindings.js +15 -0
- package/dist/ore/dist/types/bindings.js.map +1 -0
- package/dist/ore/dist/types.cjs +2 -0
- package/dist/ore/dist/types.cjs.map +1 -0
- package/dist/ore/dist/types.js +15 -0
- package/dist/ore/dist/types.js.map +1 -0
- package/dist/ore/dist/utils/aria.cjs +2 -0
- package/dist/ore/dist/utils/aria.cjs.map +1 -0
- package/dist/ore/dist/utils/aria.js +6 -0
- package/dist/ore/dist/utils/aria.js.map +1 -0
- package/dist/ore/dist/utils/css.cjs +2 -0
- package/dist/ore/dist/utils/css.cjs.map +1 -0
- package/dist/ore/dist/utils/css.js +18 -0
- package/dist/ore/dist/utils/css.js.map +1 -0
- package/dist/ore/dist/utils/dom.cjs +2 -0
- package/dist/ore/dist/utils/dom.cjs.map +1 -0
- package/dist/ore/dist/utils/dom.js +47 -0
- package/dist/ore/dist/utils/dom.js.map +1 -0
- package/dist/ore/dist/utils/emit.cjs +2 -0
- package/dist/ore/dist/utils/emit.cjs.map +1 -0
- package/dist/ore/dist/utils/emit.js +16 -0
- package/dist/ore/dist/utils/emit.js.map +1 -0
- package/dist/ore/dist/utils/id.cjs +2 -0
- package/dist/ore/dist/utils/id.cjs.map +1 -0
- package/dist/ore/dist/utils/id.js +4 -0
- package/dist/ore/dist/utils/id.js.map +1 -0
- package/dist/otp-input.cjs +21 -0
- package/dist/otp-input.cjs.map +1 -0
- package/dist/otp-input.js +145 -0
- package/dist/otp-input.js.map +1 -0
- package/dist/overlay/dialog/dialog.css?inline.cjs +2 -0
- package/dist/overlay/dialog/dialog.css?inline.cjs.map +1 -0
- package/dist/overlay/dialog/dialog.css?inline.js +6 -0
- package/dist/overlay/dialog/dialog.css?inline.js.map +1 -0
- package/dist/overlay/dialog/dialog.d.ts +108 -0
- package/dist/overlay/dialog/dialog.d.ts.map +1 -0
- package/dist/overlay/drawer/drawer.css?inline.cjs +2 -0
- package/dist/overlay/drawer/drawer.css?inline.cjs.map +1 -0
- package/dist/overlay/drawer/drawer.css?inline.js +6 -0
- package/dist/overlay/drawer/drawer.css?inline.js.map +1 -0
- package/dist/overlay/drawer/drawer.d.ts +111 -0
- package/dist/overlay/drawer/drawer.d.ts.map +1 -0
- package/dist/overlay/index.d.ts +11 -0
- package/dist/overlay/index.d.ts.map +1 -0
- package/dist/overlay/menu/menu-item.css?inline.cjs +2 -0
- package/dist/overlay/menu/menu-item.css?inline.cjs.map +1 -0
- package/dist/overlay/menu/menu-item.css?inline.js +6 -0
- package/dist/overlay/menu/menu-item.css?inline.js.map +1 -0
- package/dist/overlay/menu/menu-separator.css?inline.cjs +2 -0
- package/dist/overlay/menu/menu-separator.css?inline.cjs.map +1 -0
- package/dist/overlay/menu/menu-separator.css?inline.js +6 -0
- package/dist/overlay/menu/menu-separator.css?inline.js.map +1 -0
- package/dist/overlay/menu/menu.css?inline.cjs +2 -0
- package/dist/overlay/menu/menu.css?inline.cjs.map +1 -0
- package/dist/overlay/menu/menu.css?inline.js +6 -0
- package/dist/overlay/menu/menu.css?inline.js.map +1 -0
- package/dist/overlay/menu/menu.d.ts +110 -0
- package/dist/overlay/menu/menu.d.ts.map +1 -0
- package/dist/overlay/popover/popover.css?inline.cjs +2 -0
- package/dist/overlay/popover/popover.css?inline.cjs.map +1 -0
- package/dist/overlay/popover/popover.css?inline.js +6 -0
- package/dist/overlay/popover/popover.css?inline.js.map +1 -0
- package/dist/overlay/popover/popover.d.ts +56 -0
- package/dist/overlay/popover/popover.d.ts.map +1 -0
- package/dist/overlay/shared/await-exit.cjs +2 -0
- package/dist/overlay/shared/await-exit.cjs.map +1 -0
- package/dist/overlay/shared/await-exit.d.ts +14 -0
- package/dist/overlay/shared/await-exit.d.ts.map +1 -0
- package/dist/overlay/shared/await-exit.js +18 -0
- package/dist/overlay/shared/await-exit.js.map +1 -0
- package/dist/overlay/shared/background-lock.cjs +2 -0
- package/dist/overlay/shared/background-lock.cjs.map +1 -0
- package/dist/overlay/shared/background-lock.d.ts +22 -0
- package/dist/overlay/shared/background-lock.d.ts.map +1 -0
- package/dist/overlay/shared/background-lock.js +25 -0
- package/dist/overlay/shared/background-lock.js.map +1 -0
- package/dist/overlay/shared/use-dialog.cjs +2 -0
- package/dist/overlay/shared/use-dialog.cjs.map +1 -0
- package/dist/overlay/shared/use-dialog.d.ts +76 -0
- package/dist/overlay/shared/use-dialog.d.ts.map +1 -0
- package/dist/overlay/shared/use-dialog.js +92 -0
- package/dist/overlay/shared/use-dialog.js.map +1 -0
- package/dist/overlay/shared/use-floating-trigger.cjs +2 -0
- package/dist/overlay/shared/use-floating-trigger.cjs.map +1 -0
- package/dist/overlay/shared/use-floating-trigger.d.ts +67 -0
- package/dist/overlay/shared/use-floating-trigger.d.ts.map +1 -0
- package/dist/overlay/shared/use-floating-trigger.js +128 -0
- package/dist/overlay/shared/use-floating-trigger.js.map +1 -0
- package/dist/overlay/tooltip/tooltip.css?inline.cjs +2 -0
- package/dist/overlay/tooltip/tooltip.css?inline.cjs.map +1 -0
- package/dist/overlay/tooltip/tooltip.css?inline.js +6 -0
- package/dist/overlay/tooltip/tooltip.css?inline.js.map +1 -0
- package/dist/overlay/tooltip/tooltip.d.ts +72 -0
- package/dist/overlay/tooltip/tooltip.d.ts.map +1 -0
- package/dist/pagination.cjs +63 -0
- package/dist/pagination.cjs.map +1 -0
- package/dist/pagination.js +113 -0
- package/dist/pagination.js.map +1 -0
- package/dist/password-strength.cjs +19 -0
- package/dist/password-strength.cjs.map +1 -0
- package/dist/password-strength.js +69 -0
- package/dist/password-strength.js.map +1 -0
- package/dist/popover.cjs +16 -0
- package/dist/popover.cjs.map +1 -0
- package/dist/popover.js +81 -0
- package/dist/popover.js.map +1 -0
- package/dist/progress.cjs +46 -0
- package/dist/progress.cjs.map +1 -0
- package/dist/progress.js +96 -0
- package/dist/progress.js.map +1 -0
- package/dist/radio-group.cjs +25 -0
- package/dist/radio-group.cjs.map +1 -0
- package/dist/radio-group.js +145 -0
- package/dist/radio-group.js.map +1 -0
- package/dist/radio.cjs +10 -0
- package/dist/radio.cjs.map +1 -0
- package/dist/radio.js +146 -0
- package/dist/radio.js.map +1 -0
- package/dist/rating.cjs +28 -0
- package/dist/rating.cjs.map +1 -0
- package/dist/rating.js +123 -0
- package/dist/rating.js.map +1 -0
- package/dist/refine.cjs +2705 -0
- package/dist/refine.cjs.map +1 -0
- package/dist/refine.iife.js +2705 -0
- package/dist/refine.iife.js.map +1 -0
- package/dist/refine.js +2705 -0
- package/dist/refine.js.map +1 -0
- package/dist/select.cjs +79 -0
- package/dist/select.cjs.map +1 -0
- package/dist/select.js +289 -0
- package/dist/select.js.map +1 -0
- package/dist/separator.cjs +27 -0
- package/dist/separator.cjs.map +1 -0
- package/dist/separator.js +47 -0
- package/dist/separator.js.map +1 -0
- package/dist/shared/index.d.ts +14 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/prop-bundles.cjs +2 -0
- package/dist/shared/prop-bundles.cjs.map +1 -0
- package/dist/shared/prop-bundles.d.ts +45 -0
- package/dist/shared/prop-bundles.d.ts.map +1 -0
- package/dist/shared/prop-bundles.js +13 -0
- package/dist/shared/prop-bundles.js.map +1 -0
- package/dist/shared/size-presets.cjs +2 -0
- package/dist/shared/size-presets.cjs.map +1 -0
- package/dist/shared/size-presets.d.ts +101 -0
- package/dist/shared/size-presets.d.ts.map +1 -0
- package/dist/shared/size-presets.js +96 -0
- package/dist/shared/size-presets.js.map +1 -0
- package/dist/shared/types.d.ts +76 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/sidebar.cjs +123 -0
- package/dist/sidebar.cjs.map +1 -0
- package/dist/sidebar.js +344 -0
- package/dist/sidebar.js.map +1 -0
- package/dist/skeleton.cjs +10 -0
- package/dist/skeleton.cjs.map +1 -0
- package/dist/skeleton.js +59 -0
- package/dist/skeleton.js.map +1 -0
- package/dist/slider.cjs +27 -0
- package/dist/slider.cjs.map +1 -0
- package/dist/slider.js +219 -0
- package/dist/slider.js.map +1 -0
- package/dist/styles/animation.css +94 -0
- package/dist/styles/index.cjs +2 -0
- package/dist/styles/index.cjs.map +1 -0
- package/dist/styles/index.d.ts +41 -0
- package/dist/styles/index.d.ts.map +1 -0
- package/dist/styles/index.js +24 -0
- package/dist/styles/index.js.map +1 -0
- package/dist/styles/layer.css +19 -0
- package/dist/styles/mixins/accessibility.css.cjs +51 -0
- package/dist/styles/mixins/accessibility.css.cjs.map +1 -0
- package/dist/styles/mixins/accessibility.css.d.ts +80 -0
- package/dist/styles/mixins/accessibility.css.d.ts.map +1 -0
- package/dist/styles/mixins/accessibility.css.js +56 -0
- package/dist/styles/mixins/accessibility.css.js.map +1 -0
- package/dist/styles/mixins/animation.css.cjs +133 -0
- package/dist/styles/mixins/animation.css.cjs.map +1 -0
- package/dist/styles/mixins/animation.css.d.ts +43 -0
- package/dist/styles/mixins/animation.css.d.ts.map +1 -0
- package/dist/styles/mixins/animation.css.js +166 -0
- package/dist/styles/mixins/animation.css.js.map +1 -0
- package/dist/styles/mixins/shape.css.cjs +66 -0
- package/dist/styles/mixins/shape.css.cjs.map +1 -0
- package/dist/styles/mixins/shape.css.d.ts +96 -0
- package/dist/styles/mixins/shape.css.d.ts.map +1 -0
- package/dist/styles/mixins/shape.css.js +98 -0
- package/dist/styles/mixins/shape.css.js.map +1 -0
- package/dist/styles/mixins/states.css.cjs +37 -0
- package/dist/styles/mixins/states.css.cjs.map +1 -0
- package/dist/styles/mixins/states.css.d.ts +27 -0
- package/dist/styles/mixins/states.css.d.ts.map +1 -0
- package/dist/styles/mixins/states.css.js +44 -0
- package/dist/styles/mixins/states.css.js.map +1 -0
- package/dist/styles/mixins/table-base.css.cjs +94 -0
- package/dist/styles/mixins/table-base.css.cjs.map +1 -0
- package/dist/styles/mixins/table-base.css.d.ts +24 -0
- package/dist/styles/mixins/table-base.css.d.ts.map +1 -0
- package/dist/styles/mixins/table-base.css.js +99 -0
- package/dist/styles/mixins/table-base.css.js.map +1 -0
- package/dist/styles/mixins/theme.css.cjs +80 -0
- package/dist/styles/mixins/theme.css.cjs.map +1 -0
- package/dist/styles/mixins/theme.css.d.ts +77 -0
- package/dist/styles/mixins/theme.css.d.ts.map +1 -0
- package/dist/styles/mixins/theme.css.js +98 -0
- package/dist/styles/mixins/theme.css.js.map +1 -0
- package/dist/styles/mixins/variants.css.cjs +55 -0
- package/dist/styles/mixins/variants.css.cjs.map +1 -0
- package/dist/styles/mixins/variants.css.d.ts +22 -0
- package/dist/styles/mixins/variants.css.d.ts.map +1 -0
- package/dist/styles/mixins/variants.css.js +60 -0
- package/dist/styles/mixins/variants.css.js.map +1 -0
- package/dist/styles/preflight.css +239 -0
- package/dist/styles/styles.css +5 -0
- package/dist/styles/theme.css +553 -0
- package/dist/switch.cjs +10 -0
- package/dist/switch.cjs.map +1 -0
- package/dist/switch.js +79 -0
- package/dist/switch.js.map +1 -0
- package/dist/tab-item.cjs +17 -0
- package/dist/tab-item.cjs.map +1 -0
- package/dist/tab-item.js +62 -0
- package/dist/tab-item.js.map +1 -0
- package/dist/tab-panel.cjs +14 -0
- package/dist/tab-panel.cjs.map +1 -0
- package/dist/tab-panel.js +61 -0
- package/dist/tab-panel.js.map +1 -0
- package/dist/table.cjs +2 -0
- package/dist/table.cjs.map +1 -0
- package/dist/table.js +101 -0
- package/dist/table.js.map +1 -0
- package/dist/tabs.cjs +17 -0
- package/dist/tabs.cjs.map +1 -0
- package/dist/tabs.js +126 -0
- package/dist/tabs.js.map +1 -0
- package/dist/testing/index.d.ts +233 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing.cjs +2 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.js +44 -0
- package/dist/testing.js.map +1 -0
- package/dist/text.cjs +2 -0
- package/dist/text.cjs.map +1 -0
- package/dist/text.js +34 -0
- package/dist/text.js.map +1 -0
- package/dist/textarea.cjs +33 -0
- package/dist/textarea.cjs.map +1 -0
- package/dist/textarea.js +137 -0
- package/dist/textarea.js.map +1 -0
- package/dist/time-picker.cjs +98 -0
- package/dist/time-picker.cjs.map +1 -0
- package/dist/time-picker.js +261 -0
- package/dist/time-picker.js.map +1 -0
- package/dist/toast.cjs +69 -0
- package/dist/toast.cjs.map +1 -0
- package/dist/toast.js +316 -0
- package/dist/toast.js.map +1 -0
- package/dist/tooltip.cjs +15 -0
- package/dist/tooltip.cjs.map +1 -0
- package/dist/tooltip.js +121 -0
- package/dist/tooltip.js.map +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/utils/css.cjs +2 -0
- package/dist/utils/css.cjs.map +1 -0
- package/dist/utils/css.d.ts +10 -0
- package/dist/utils/css.d.ts.map +1 -0
- package/dist/utils/css.js +10 -0
- package/dist/utils/css.js.map +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/link.cjs +2 -0
- package/dist/utils/link.cjs.map +1 -0
- package/dist/utils/link.d.ts +44 -0
- package/dist/utils/link.d.ts.map +1 -0
- package/dist/utils/link.js +19 -0
- package/dist/utils/link.js.map +1 -0
- package/package.json +464 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refine.iife.js","names":["e","t","n","r","i","a","o","s","c","l","u","t","n","r","i","a","o","s","c","e","t","n","r","o","s","c","l","e","t","i","a","e","e","t","n","n"],"sources":["../../ore/dist/_dev.js","../../ore/dist/types/bindings.js","../../ore/dist/utils/dom.js","../../ore/dist/directives/live.js","../../ore/dist/directives/raw.js","../../ore/dist/directives/styleMap.js","../../ore/dist/directives/when.js","../src/content/code-window/code-window.css?inline","../src/content/code-window/code-window.ts","../src/styles/mixins/accessibility.css.ts","../src/styles/mixins/shape.css.ts","../src/styles/mixins/states.css.ts","../src/styles/mixins/theme.css.ts","../src/styles/mixins/animation.css.ts","../src/styles/mixins/variants.css.ts","../src/styles/mixins/table-base.css.ts","../src/styles/index.ts","../src/_dev.ts","../src/content/icon/icon.css?inline","../src/content/icon/icon.ts","../src/content/copy-command/copy-command.css?inline","../src/content/copy-command/copy-command.ts","../src/shared/prop-bundles.ts","../src/shared/size-presets.ts","../src/feedback/progress/progress.css?inline","../src/feedback/progress/progress.ts","../src/headless/ore.ts","../src/headless/field-base.ts","../src/headless/signals.ts","../src/headless/text-field.ts","../src/headless/choice-field.ts","../src/headless/keyboard.ts","../src/headless/checkable.ts","../src/errors.ts","../src/headless/typeahead.ts","../src/headless/nav.ts","../src/headless/overlay.ts","../src/headless/direction.ts","../src/headless/positioner.ts","../src/headless/option-list.ts","../src/headless/paginated-list.ts","../src/headless/numbers.ts","../src/headless/spinner.ts","../src/headless/slider.ts","../src/headless/swipe.ts","../src/headless/announcer.ts","../src/headless/date-picker.ts","../src/headless/focus.ts","../src/headless/light-dom.ts","../src/headless/selection-control.ts","../src/headless/sort-control.ts","../src/headless/datagrid.ts","../src/headless/parse.ts","../src/content/carousel/carousel.css?inline","../src/content/carousel/carousel-slide.css?inline","../src/content/carousel/carousel-slide.ts","../src/content/carousel/carousel.ts","../src/content/avatar/avatar-group.css?inline","../src/content/avatar/avatar.css?inline","../src/content/avatar/avatar.ts","../src/content/breadcrumb/breadcrumb-item.css?inline","../src/content/breadcrumb/breadcrumb.css?inline","../src/content/breadcrumb/breadcrumb.ts","../src/content/card/card.css?inline","../src/content/card/card.ts","../src/utils/css.ts","../src/utils/link.ts","../src/inputs/button-group/button-group.css?inline","../src/inputs/button-group/button-group.ts","../src/inputs/shared/field-binding.ts","../src/inputs/shared/form-context.ts","../src/inputs/shared/templates.ts","../src/inputs/shared/use-form-action.ts","../src/inputs/button/button.css?inline","../src/inputs/button/button.ts","../src/content/pagination/pagination.css?inline","../src/content/pagination/pagination.ts","../src/content/separator/separator.css?inline","../src/content/separator/separator.ts","../src/content/table/table.css?inline","../src/content/table/table.ts","../src/content/text/text.css?inline","../src/content/text/text.ts","../src/disclosure/accordion/accordion.css?inline","../src/disclosure/accordion/accordion.ts","../src/disclosure/tabs/tabs.css?inline","../src/disclosure/tabs/tabs.ts","../src/disclosure/accordion-item/accordion-item.css?inline","../src/disclosure/accordion-item/accordion-item.ts","../src/disclosure/tab-item/tab-item.css?inline","../src/disclosure/tab-item/tab-item.ts","../src/disclosure/tab-panel/tab-panel.css?inline","../src/disclosure/tab-panel/tab-panel.ts","../src/feedback/async/async.css?inline","../src/feedback/async/async.ts","../src/overlay/shared/await-exit.ts","../src/feedback/alert/alert.css?inline","../src/feedback/alert/alert.ts","../src/feedback/badge/badge.css?inline","../src/feedback/badge/badge.ts","../src/feedback/chip/chip.css?inline","../src/feedback/chip/chip.ts","../src/feedback/password-strength/password-strength.css?inline","../src/feedback/password-strength/password-strength.ts","../../ore/dist/observers/intersection-observe.js","../../ore/dist/observers/resize-observe.js","../src/feedback/skeleton/skeleton.css?inline","../src/feedback/skeleton/skeleton.ts","../src/feedback/toast/toast.css?inline","../src/feedback/toast/toast.ts","../src/inputs/checkbox-group/checkbox-group.css?inline","../src/inputs/checkbox-group/checkbox-group.ts","../src/inputs/checkbox/checkbox.css?inline","../src/inputs/checkbox/checkbox.ts","../src/inputs/combobox/combobox-options.ts","../src/inputs/input/input.css?inline","../src/inputs/input/input.ts","../src/inputs/combobox/combobox.css?inline","../src/inputs/combobox/combobox.ts","../src/inputs/select/select.css?inline","../src/inputs/select/select.ts","../src/overlay/shared/use-floating-trigger.ts","../src/overlay/popover/popover.css?inline","../src/overlay/popover/popover.ts","../src/inputs/datagrid/datagrid-column.ts","../src/inputs/datagrid/datagrid-controls.ts","../src/inputs/datagrid/datagrid-nav.ts","../src/inputs/datagrid/datagrid.css?inline","../src/inputs/datagrid/datagrid.ts","../src/inputs/calendar/calendar.css?inline","../src/inputs/calendar/calendar.ts","../src/inputs/date-picker/date-picker.css?inline","../src/inputs/date-picker/date-picker.ts","../src/inputs/file-input/file-input.css?inline","../src/inputs/file-input/file-input.ts","../src/inputs/form/form.css?inline","../src/inputs/form/form.ts","../src/inputs/number-input/number-input.css?inline","../src/inputs/number-input/number-input.ts","../src/inputs/otp-input/otp-input.css?inline","../src/inputs/otp-input/otp-input.ts","../src/inputs/radio-group/radio-group.css?inline","../src/inputs/radio-group/radio-group.ts","../src/inputs/radio/radio.css?inline","../src/inputs/radio/radio.ts","../src/inputs/rating/rating.css?inline","../src/inputs/rating/rating.ts","../src/inputs/slider/slider.css?inline","../src/inputs/slider/slider.ts","../src/inputs/switch/switch.css?inline","../src/inputs/switch/switch.ts","../src/inputs/textarea/textarea.css?inline","../src/inputs/textarea/textarea.ts","../src/inputs/time-picker/time-picker.css?inline","../src/inputs/time-picker/time-picker.ts","../src/layout/box/box.css?inline","../src/layout/box/box.ts","../src/layout/grid-item/grid-item.css?inline","../src/layout/grid-item/grid-item.ts","../src/layout/grid/grid.css?inline","../src/layout/grid/grid.ts","../src/layout/navbar/navbar.css?inline","../src/layout/navbar/navbar.ts","../src/layout/sidebar/sidebar-group.css?inline","../src/layout/sidebar/sidebar-item.css?inline","../src/layout/sidebar/sidebar.css?inline","../src/layout/sidebar/sidebar.ts","../src/overlay/shared/background-lock.ts","../src/overlay/shared/use-dialog.ts","../src/overlay/dialog/dialog.css?inline","../src/overlay/dialog/dialog.ts","../src/overlay/drawer/drawer.css?inline","../src/overlay/drawer/drawer.ts","../src/overlay/menu/menu-item.css?inline","../src/overlay/menu/menu-separator.css?inline","../src/overlay/menu/menu.css?inline","../src/overlay/menu/menu.ts","../src/overlay/tooltip/tooltip.css?inline","../src/overlay/tooltip/tooltip.ts"],"sourcesContent":["var e=!globalThis.__ORE_PROD__;function t(t){e&&console.warn(`[@vielzeug/ore] ${t}`)}function n(t,...n){e&&console.error(`[@vielzeug/ore] ${t}`,...n)}function r(t){e&&t()}export{r as devOnly,n as error,t as warn};\n//# sourceMappingURL=_dev.js.map","import{signal as e}from\"@vielzeug/ripple\";function t(){return e(null)}var n=e=>{let t=Symbol.for(e);return{is:e=>typeof e==`object`&&!!e&&t in e,stamp:e=>Object.assign(e,{[t]:!0})}},r=n(`ore:directive`),i=e=>r.stamp({mount:e}),a=r.is,o=n(`ore:spread`),s=e=>o.stamp({apply:e}),c=o.is,l=n(`ore:html-result`),u=l.is;function d(e,t){return l.stamp({apply:t,fragment:e,mount:(n,r,i)=>{let a=Array.from(e.childNodes);return n.insertBefore(e,r),t(i),a}})}export{i as createDirectiveResult,d as createHtmlResult,s as createSpreadObject,a as isDirectiveResult,u as isHtmlResult,c as isSpreadObject,t as ref};\n//# sourceMappingURL=bindings.js.map","import{warn as e}from\"../_dev.js\";var t=e=>{for(let t=e.length-1;t>=0;t--)e[t]()},n=e=>{for(let t of e)t.remove()},r=new Set([`action`,`cite`,`codebase`,`data`,`formaction`,`href`,`manifest`,`ping`,`poster`,`src`,`xlink:href`]),i=/^\\s*(?:(?:javascript|vbscript|blob):|data:(?:[^,]*\\/(?:html|svg\\+xml)|application\\/(?:xhtml|xml)))/i,a=(t,n,a)=>{let o=n.toLowerCase();if(/^on[a-z]/i.test(n)){e(`Blocked setAttribute(\"${n}\", ...) — inline event handler attributes are not supported. Use @${n.slice(2)} binding syntax instead.`),t.removeAttribute(n);return}if(o===`srcdoc`){e(`Blocked setAttribute(\"srcdoc\", ...) — \"srcdoc\" holds raw HTML, not a URL, and is not supported via attribute binding. Use raw() with a registered sanitizer if you need to inject trusted HTML.`),t.removeAttribute(n);return}if(a==null||a===!1){t.removeAttribute(n);return}let s=a===!0?`true`:String(a);if(r.has(o)&&i.test(s)){e(`Blocked dangerous URL scheme in attribute \"${n}\". Only safe URLs are permitted in URL-accepting attributes.`),t.removeAttribute(n);return}t.setAttribute(n,s)},o=(e,t,n,r)=>{if(!e)return()=>{};let i=n;return e.addEventListener(t,i,r),()=>e.removeEventListener(t,i,r)},s=e=>e.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`),c=e=>Array.isArray(e)||typeof e==`object`&&!!e;export{c as isStructuredValue,o as listen,n as removeNodes,t as runAll,a as setAttr,s as toKebab};\n//# sourceMappingURL=dom.js.map","var e=new WeakSet,t=t=>(e.add(t),t),n=t=>typeof t==`object`&&!!t&&e.has(t),r=()=>{e=new WeakSet};export{r as _resetLiveSignals,n as isLiveSignal,t as live};\n//# sourceMappingURL=live.js.map","import{warn as e}from\"../_dev.js\";import{createDirectiveResult as t}from\"../types/bindings.js\";import{removeNodes as n}from\"../utils/dom.js\";import{computed as r,effect as i,isReactive as a}from\"@vielzeug/ripple\";var o=null,s=!1,c=e=>{o=e,e||(s=!1)},l=()=>{o=null,s=!1},u=t=>o?o(t):(t&&!s&&(s=!0,e(`raw() was called without a sanitizer registered. Passing user-supplied HTML directly to raw() is an XSS risk. Register a sanitizer with setRawSanitizer() — e.g. setRawSanitizer(DOMPURIFY.sanitize).`)),t),d=(e,t,n)=>{let r=document.createElement(`template`);r.innerHTML=e;let i=Array.from(r.content.cloneNode(!0).childNodes);for(let e of i)t.insertBefore(e,n);return i};function f(e){if(typeof e==`function`){let n=r(e);return t((e,t)=>{t(()=>n.dispose()),f(n).mount(e,t)})}return t((t,r)=>{let o=t.parentNode,s=document.createComment(`raw/end`);if(o.insertBefore(s,t.nextSibling),a(e)){let t=[],a=e,c=i(()=>{n(t),t=d(u(a.value),o,s)});r(()=>c.dispose()),r(()=>{n(t),s.remove()})}else d(u(e),o,s),r(()=>s.remove())})}export{l as _resetRawSanitizer,f as raw,c as setRawSanitizer};\n//# sourceMappingURL=raw.js.map","import{toKebab as e}from\"../utils/dom.js\";import{computed as t,isReactive as n}from\"@vielzeug/ripple\";var r=e=>{let t=typeof e==`function`?e():n(e)?e.value:e;return t==null||t===!1?``:String(t).replace(/[;{}]/g,``)},i=/[;{}]/g,a=n=>t(()=>{let t=[];for(let[a,o]of Object.entries(n)){let n=r(o);if(!n)continue;let s=e(a).replace(i,``);s&&t.push(`${s}:${n}`)}return t.join(`;`)});export{a as styleMap};\n//# sourceMappingURL=styleMap.js.map","import{createDirectiveResult as e,isHtmlResult as t}from\"../types/bindings.js\";import{removeNodes as n,runAll as r}from\"../utils/dom.js\";import{computed as i,effect as a,isReactive as o,untrack as s}from\"@vielzeug/ripple\";var c=(e,t,n,r)=>e.mount(t,n,r);function l(l,u,d){return typeof l!=`function`&&!o(l)?e((e,r)=>{let i=l?u():d?d():null;if(!i||!t(i))return;let a=e.parentNode,o=c(i,a,e,r);r(()=>n(o))}):e((e,o)=>{let f=typeof l==`function`?i(l):null,p=f??l;f&&o(()=>f.dispose());let m=e.parentNode,h=document.createComment(`when/end`);m.insertBefore(h,e.nextSibling);let g=[],_=[],v=a(()=>{let e=p.value;r(_),n(g),_=[],g=[];let i=e?u():d?d():null;if(!i||!t(i))return;let a=[];g=s(()=>c(i,m,h,e=>a.push(e))),_=a});o(()=>v.dispose()),o(()=>{r(_),n(g),h.remove()})})}export{l as when};\n//# sourceMappingURL=when.js.map","@layer refine.base {\n :host {\n --_bg: var(--code-window-bg, var(--color-canvas));\n --_header-bg: var(--code-window-header-bg, var(--color-contrast-100));\n --_border-color: var(--code-window-border-color, var(--color-contrast-300));\n --_radius: var(--code-window-radius, var(--rounded-lg));\n --_shadow: var(--code-window-shadow, var(--shadow-sm));\n --_body-padding: var(--code-window-body-padding, var(--size-5) var(--size-6));\n\n display: block;\n }\n\n .window {\n overflow: hidden;\n background: var(--_bg);\n border: var(--border) solid var(--_border-color);\n border-radius: var(--_radius);\n box-shadow: var(--_shadow);\n transition:\n border-color var(--transition-normal),\n box-shadow var(--transition-normal);\n }\n\n .header {\n display: flex;\n gap: var(--size-1-5);\n align-items: center;\n padding: var(--size-3) var(--size-5);\n overflow: hidden;\n background: var(--_header-bg);\n border-bottom: var(--border) solid var(--_border-color);\n transition: background var(--transition-normal);\n }\n\n /* ── code variant ─────────────────────────────────────────── */\n\n .lang {\n flex-shrink: 0;\n padding: 2px var(--size-1-5);\n font-family: var(--font-mono);\n font-size: var(--text-2xs);\n font-weight: var(--font-semibold);\n color: var(--color-primary);\n letter-spacing: 0.03em;\n background: var(--color-primary-backdrop);\n border: var(--border) solid oklch(70% 0.12 293deg / 20%);\n border-radius: var(--rounded-sm);\n }\n\n .filename {\n min-width: 0;\n margin-inline-start: var(--size-2);\n overflow: hidden;\n text-overflow: ellipsis;\n font-family: var(--font-mono);\n font-size: var(--text-xs);\n color: var(--text-color-secondary);\n white-space: nowrap;\n }\n\n /* ── chat variant ─────────────────────────────────────────── */\n\n .dots {\n display: flex;\n flex-shrink: 0;\n gap: var(--size-1-5);\n align-items: center;\n padding-inline-end: var(--size-3);\n margin-inline-end: var(--size-1-5);\n border-inline-end: var(--border) solid var(--_border-color);\n }\n\n /* Authentic macOS traffic-light palette — muted so they don't fight the content */\n .dots span {\n display: block;\n width: var(--size-3);\n height: var(--size-3);\n border-radius: var(--rounded-full);\n }\n\n .dots span:nth-child(1) {\n background: oklch(65% 0.18 25deg);\n }\n\n .dots span:nth-child(2) {\n background: oklch(72% 0.18 80deg);\n }\n\n .dots span:nth-child(3) {\n background: oklch(62% 0.18 145deg);\n }\n\n .title {\n font-family: var(--font-mono);\n font-size: var(--text-xs);\n color: var(--text-color-secondary);\n letter-spacing: 0.02em;\n }\n\n /* ── header-end spacer ────────────────────────────────────── */\n\n .header-spacer {\n flex: 1;\n }\n\n ::slotted([slot='header-end']) {\n flex-shrink: 0;\n }\n\n /* ── body ─────────────────────────────────────────────────── */\n\n .body {\n padding: var(--_body-padding);\n overflow-x: auto;\n }\n}\n","import { define, html, prop } from '@vielzeug/ore';\nimport { when } from '@vielzeug/ore/directives';\nimport { computed } from '@vielzeug/ripple';\n\nimport componentStyles from './code-window.css?inline';\n\n/** `ore-code-window` variant */\nexport type CodeWindowVariant = 'code' | 'chat';\n\n/** `ore-code-window` component properties */\nexport type OreCodeWindowProps = {\n /** Filename label shown after the language badge (`variant=\"code\"` only) */\n filename?: string;\n /** Language badge text, e.g. `\"ts\"`, `\"sh\"` (`variant=\"code\"` only) */\n lang?: string;\n /** Title string shown beside the traffic-light dots (`variant=\"chat\"` only) */\n title?: string;\n /**\n * `\"code\"` (default) — header shows a language badge + filename.\n * `\"chat\"` — header shows traffic-light dots + a title.\n */\n variant?: CodeWindowVariant;\n};\n\n/**\n * A styled window chrome for code blocks and AI/MCP conversation flows.\n *\n * Two variants:\n * - `variant=\"code\"` (default) — language badge + optional filename header.\n * - `variant=\"chat\"` — traffic-light dots + title header.\n *\n * @element ore-code-window\n *\n * @attr {'code'|'chat'} variant - Window style variant\n * @attr {string} lang - Language badge label (variant=\"code\" only)\n * @attr {string} filename - Filename shown next to the badge (variant=\"code\" only)\n * @attr {string} title - Label beside the dots (variant=\"chat\" only)\n *\n * @slot - Main body content (code, conversation turns, or any markup)\n * @slot header-end - Optional content appended to the trailing edge of the header\n *\n * @cssprop --code-window-bg - Window background color\n * @cssprop --code-window-header-bg - Header background color\n * @cssprop --code-window-border-color - Border color\n * @cssprop --code-window-radius - Border radius\n * @cssprop --code-window-shadow - Box shadow\n * @cssprop --code-window-body-padding - Body slot padding\n *\n * @part window - The root window element\n * @part header - The header bar\n * @part lang - The language badge (`variant=\"code\"`)\n * @part filename - The filename label (`variant=\"code\"`)\n * @part dots - The traffic-light dot container (`variant=\"chat\"`)\n * @part title - The title label (`variant=\"chat\"`)\n * @part body - The body container wrapping the default slot\n *\n * @example\n * ```html\n * <ore-code-window lang=\"ts\" filename=\"app.ts\">\n * <pre>const x = 1;</pre>\n * </ore-code-window>\n *\n * <ore-code-window variant=\"chat\" title=\"MCP tool call\">\n * <!-- conversation turns go here -->\n * </ore-code-window>\n * ```\n */\nexport const CODE_WINDOW_TAG = 'ore-code-window' as const;\ndefine<OreCodeWindowProps>(CODE_WINDOW_TAG, {\n props: {\n filename: prop.string(),\n lang: prop.string('ts'),\n title: prop.string('MCP tool call'),\n variant: prop.oneOf(['code', 'chat'] as const, 'code'),\n },\n setup(props) {\n const isCode = computed(() => props.variant.value === 'code');\n const hasFilename = computed(() => Boolean(props.filename.value));\n\n return html`\n <div class=\"window\" part=\"window\">\n <div class=\"header\" part=\"header\">\n ${when(\n isCode,\n () => html`\n <span class=\"lang\" part=\"lang\">${props.lang}</span>\n ${when(hasFilename, () => html`<span class=\"filename\" part=\"filename\">${props.filename}</span>`)}\n `,\n () => html`\n <div class=\"dots\" part=\"dots\" aria-hidden=\"true\"><span></span><span></span><span></span></div>\n <span class=\"title\" part=\"title\">${props.title}</span>\n `,\n )}\n <div class=\"header-spacer\"></div>\n <slot name=\"header-end\"></slot>\n </div>\n <div class=\"body\" part=\"body\">\n <slot></slot>\n </div>\n </div>\n `;\n },\n styles: [componentStyles],\n});\n","import { css } from '@vielzeug/ore';\n\n/**\n * Visually-Hidden (\"sr-only\") Style\n *\n * Single source of truth for the standard visually-hidden-but-accessible\n * clipping technique — hides content visually while keeping it in the\n * accessibility tree (screen readers, `aria-live` regions).\n *\n * Two forms are exported from the same declarations so component stylesheets\n * and JS-created DOM elements never drift out of sync:\n * - `srOnlyMixin` — a `.sr-only` class for component `styles: [...]` arrays.\n * - `SR_ONLY_INLINE_STYLE` — the equivalent `cssText` string for elements\n * created outside any component's shadow root (e.g. a live region appended\n * directly to `document.body`).\n *\n * @example\n * ```ts\n * // Component stylesheet\n * import { srOnlyMixin } from '../../styles';\n * return { styles: [srOnlyMixin, componentStyles], template: html`<span class=\"sr-only\">...</span>` };\n *\n * // JS-created element outside a shadow root\n * import { SR_ONLY_INLINE_STYLE } from '../../styles';\n * el.style.cssText = SR_ONLY_INLINE_STYLE;\n * ```\n */\nexport const SR_ONLY_INLINE_STYLE =\n 'position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;' +\n 'white-space:nowrap;border-width:0;clip-path:inset(50%);';\n\nexport const srOnlyMixin = css`\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n white-space: nowrap;\n border-width: 0;\n clip-path: inset(50%);\n }\n`;\n\n/**\n * Coarse Pointer Mixin\n *\n * Under `@media (pointer: coarse)`, promotes the full component one size tier\n * so padding, gap, font-size, height, and icon-size all grow proportionally\n * with the WCAG 44 px touch target — not just the minimum height in isolation:\n *\n * - default / `size=\"md\"` → lg-scale tokens + `--_touch-target: var(--size-11)`\n * - `size=\"sm\"` → md-scale tokens + `--_touch-target: var(--size-11)`\n * - `size=\"lg\"` → touch target only (already at max scale)\n *\n * Interactive elements inside the component that need a guaranteed tap target\n * should still reference `--_touch-target`:\n *\n * ```css\n * .close { min-height: var(--_touch-target); min-width: var(--_touch-target); }\n * ```\n *\n * @example\n * ```ts\n * import { coarsePointerMixin } from '../../styles';\n *\n * return {\n * styles: [coarsePointerMixin, componentStyles],\n * template: html`...`\n * };\n * ```\n */\nexport const coarsePointerMixin = css`\n @media (pointer: coarse) {\n /* Default / md size: promote all scale tokens one tier up (md → lg) */\n :host,\n :host([size='md']) {\n --_touch-target: var(--size-11);\n --_font-size: var(--text-base);\n --_gap: var(--size-2-5);\n --_height: var(--size-12);\n --_size: var(--size-6);\n --_icon-size: var(--size-6);\n --_padding: var(--size-2-5) var(--size-5);\n }\n\n /* sm size: promote to md scale */\n :host([size='sm']) {\n --_touch-target: var(--size-11);\n --_font-size: var(--text-sm);\n --_gap: var(--size-2);\n --_height: var(--size-10);\n --_size: var(--size-5);\n --_icon-size: var(--size-5);\n --_padding: var(--size-2) var(--size-4);\n }\n\n /* lg size: already max, just enforce touch target */\n :host([size='lg']) {\n --_touch-target: var(--size-11);\n }\n }\n`;\n\n/**\n * Reduced Motion Mixin\n *\n * Defines `--_motion-transition: none` and `--_motion-animation: none` on\n * `:host` under `@media (prefers-reduced-motion: reduce)`.\n * Component CSS opts in via CSS variable fallbacks:\n *\n * ```css\n * .panel { transition: var(--_motion-transition, opacity 300ms ease); }\n * .loader { animation: var(--_motion-animation, spin 0.6s linear infinite); }\n * ```\n *\n * @example\n * ```ts\n * import { reducedMotionMixin } from '../../styles';\n *\n * return {\n * styles: [reducedMotionMixin, componentStyles],\n * template: html`...`\n * };\n * ```\n */\nexport const reducedMotionMixin = css`\n @media (prefers-reduced-motion: reduce) {\n :host {\n --_motion-transition: none;\n --_motion-animation: none;\n }\n }\n`;\n","import { css } from '@vielzeug/ore';\n\n// ── Padding ───────────────────────────────────────────────────────────────────\n\n/**\n * Padding Variant Mixin\n *\n * Provides padding size variants (none, sm, md, lg, xl) via CSS custom properties.\n * Sets the --_padding variable based on padding attribute.\n *\n * @example\n * ```ts\n * import { paddingMixin } from '../../styles';\n *\n * return {\n * styles: [paddingMixin, componentStyles],\n * template: html`...`\n * };\n * ```\n */\nexport const paddingMixin = css`\n /* ========================================\n Padding Variants\n ======================================== */\n\n :host([padding='none']) {\n --_padding: var(--size-0);\n }\n\n :host([padding='sm']) {\n --_padding: var(--size-3);\n }\n\n :host([padding='md']) {\n --_padding: var(--size-4);\n }\n\n :host([padding='lg']) {\n --_padding: var(--size-6);\n }\n\n :host([padding='xl']) {\n --_padding: var(--size-8);\n }\n`;\n\n// ── Rounded ───────────────────────────────────────────────────────────────────\n\n/**\n * Rounded Variant Mixin\n *\n * Shared border-radius variant styles for components.\n * Maps rounded attribute values to theme border radius tokens.\n *\n * @example\n * ```ts\n * import { roundedVariantMixin } from '../../styles';\n *\n * return {\n * styles: [roundedVariantMixin, componentStyles],\n * template: html`...`\n * };\n * ```\n */\nexport const roundedVariantMixin = css`\n :host([rounded='none']) {\n --_radius: var(--rounded-none);\n }\n :host([rounded='sm']) {\n --_radius: var(--rounded-sm);\n }\n :host([rounded='md']) {\n --_radius: var(--rounded-md);\n }\n :host([rounded='lg']) {\n --_radius: var(--rounded-lg);\n }\n :host([rounded='xl']) {\n --_radius: var(--rounded-xl);\n }\n :host([rounded='2xl']) {\n --_radius: var(--rounded-2xl);\n }\n :host([rounded='3xl']) {\n --_radius: var(--rounded-3xl);\n }\n :host([rounded='full']),\n :host([rounded='']) {\n --_radius: var(--rounded-full);\n }\n`;\n\n// ── Size Variants ─────────────────────────────────────────────────────────────\n\n/**\n * Size Variant Mixin\n *\n * Injects the three standard size tiers (sm / md / lg) as CSS custom property\n * blocks on `:host([size=\"…\"])`. Per-component overrides are supplied as a raw\n * CSS string for each tier and are appended after the shared defaults.\n *\n * All property names use the `--_` internal convention already established by\n * other mixins. The mapping is:\n *\n * | Config key | CSS custom property |\n * |------------- |----------------------|\n * | fontSize | --_font-size |\n * | gap | --_gap |\n * | height | --_height |\n * | iconSize | --_icon-size |\n * | lineHeight | --_line-height |\n * | padding | --_padding |\n * | size | --_size |\n * | thumbSize | --_thumb-size |\n * | width | --_width |\n * | --foo | --foo (pass-through) |\n *\n * @example\n * ```ts\n * styles: [\n * sizeVariantMixin({\n * sm: { height: 'var(--size-8)', padding: 'var(--size-1-5) var(--size-3)' },\n * lg: { height: 'var(--size-12)', padding: 'var(--size-2-5) var(--size-5)' },\n * }),\n * componentStyles,\n * ]\n * ```\n */\nexport type SizeConfig = {\n /** Arbitrary CSS custom properties (must start with --) */\n [key: `--${string}`]: string | undefined;\n /** Font size — maps to --_font-size */\n fontSize?: string;\n /** Gap between elements — maps to --_gap */\n gap?: string;\n /** Element height — maps to --_height */\n height?: string;\n /** Icon size — maps to --_icon-size */\n iconSize?: string;\n /** Line height — maps to --_line-height */\n lineHeight?: string;\n /** Internal padding — maps to --_padding */\n padding?: string;\n /** Element size (width/height) — maps to --_size */\n size?: string;\n /** Thumb size (e.g. toggle/switch thumb) — maps to --_thumb-size */\n thumbSize?: string;\n /** Element width — maps to --_width */\n width?: string;\n};\n\nconst PROP_MAP: Record<string, string> = {\n fontSize: '--_font-size',\n gap: '--_gap',\n height: '--_height',\n iconSize: '--_icon-size',\n lineHeight: '--_line-height',\n padding: '--_padding',\n size: '--_size',\n thumbSize: '--_thumb-size',\n width: '--_width',\n};\n\nconst configToBlock = (config: SizeConfig): string =>\n Object.entries(config)\n .filter(([, v]) => v !== undefined)\n .map(([k, v]) => `${k.startsWith('--') ? k : (PROP_MAP[k] ?? `--_${k}`)}: ${v};`)\n .join('\\n ');\n\nexport const sizeVariantMixin = (config?: { lg?: SizeConfig; md?: SizeConfig; sm?: SizeConfig }) => {\n const sm = configToBlock({\n fontSize: 'var(--text-xs)',\n gap: 'var(--size-1-5)',\n size: 'var(--size-4)',\n ...config?.sm,\n });\n const md = configToBlock({\n fontSize: 'var(--text-sm)',\n gap: 'var(--size-2)',\n size: 'var(--size-5)',\n ...config?.md,\n });\n const lg = configToBlock({\n fontSize: 'var(--text-base)',\n gap: 'var(--size-2-5)',\n size: 'var(--size-6)',\n ...config?.lg,\n });\n\n return css`\n :host {\n ${md}\n }\n :host([size='sm']) {\n ${sm}\n }\n :host([size='md']) {\n ${md}\n }\n :host([size='lg']) {\n ${lg}\n }\n `;\n};\n","import { css } from '@vielzeug/ore';\n\n/**\n * Disabled State Mixin\n *\n * Reduces opacity and shows `not-allowed` cursor on the host.\n * `pointer-events: none` is placed on the inner slot so the host stays\n * hoverable (e.g. for tooltips that explain why the control is disabled).\n */\nexport const disabledStateMixin = css`\n :host([disabled]) {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n :host([disabled]) ::slotted(*),\n :host([disabled]) > :not(slot) {\n pointer-events: none;\n }\n`;\n\n/**\n * Loading State Mixin\n *\n * Shows `wait` cursor on the host; blocks pointer events on inner content.\n */\nexport const loadingStateMixin = css`\n :host([loading]) {\n opacity: 0.5;\n cursor: wait;\n }\n\n :host([loading]) ::slotted(*),\n :host([loading]) > :not(slot) {\n pointer-events: none;\n }\n`;\n\n/**\n * Combined Disabled & Loading State Mixin\n *\n * Convenience mixin combining both disabled and loading host states.\n * Use for most interactive components that support both attributes.\n *\n * - Host receives the correct cursor (not-allowed / wait) and remains\n * hoverable so external tooltip wrappers can still fire pointer events.\n * - Inner shadow-DOM children have pointer-events disabled so they refuse\n * clicks while the host cursor signal is still visible.\n */\nexport const disabledLoadingMixin = css`\n :host([disabled]),\n :host([loading]) {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n :host([loading]) {\n cursor: wait;\n }\n\n :host([disabled]) > :not(slot),\n :host([loading]) > :not(slot) {\n pointer-events: none;\n }\n`;\n","import { css } from '@vielzeug/ore';\n\n// ── Color Theme ───────────────────────────────────────────────────────────────\n\nconst THEME_COLORS = ['primary', 'secondary', 'info', 'success', 'warning', 'error'] as const;\n\ntype ThemeColorName = (typeof THEME_COLORS)[number];\n\n// Standard token suffix for each --_theme-* variable. The 'shadow' slot maps\n// to --color-*-focus-shadow (not --color-*-shadow) and 'halo' maps to --halo-shadow-*.\nconst TOKEN_SUFFIX: Record<string, (color: ThemeColorName) => string> = {\n backdrop: (c) => `var(--color-${c}-backdrop)`,\n base: (c) => `var(--color-${c})`,\n border: (c) => `var(--color-${c}-border)`,\n content: (c) => `var(--color-${c}-content)`,\n contrast: (c) => `var(--color-${c}-contrast)`,\n focus: (c) => `var(--color-${c}-focus)`,\n halo: (c) => `var(--halo-shadow-${c})`,\n shadow: (c) => `var(--color-${c}-focus-shadow)`,\n};\n\nconst colorBlock = (color: ThemeColorName): string =>\n `:host([color='${color}']) {\\n${Object.entries(TOKEN_SUFFIX)\n .map(([slot, fn]) => ` --_theme-${slot}: ${fn(color)};`)\n .join('\\n')}\\n}`;\n\nexport const colorThemeMixin = css`\n :host {\n --_theme-base: var(--color-neutral);\n --_theme-content: var(--color-neutral-content);\n --_theme-contrast: var(--color-neutral-contrast);\n --_theme-focus: var(--color-neutral-focus);\n --_theme-backdrop: var(--color-neutral-backdrop);\n --_theme-border: var(--color-neutral-border);\n --_theme-shadow: var(--color-neutral-focus-shadow);\n --_theme-halo: var(--halo-shadow-neutral);\n }\n\n ${THEME_COLORS.map(colorBlock).join('\\n\\n ')}\n`;\n\n// ── Elevation ─────────────────────────────────────────────────────────────────\n\n/**\n * Elevation Mixin\n *\n * Provides elevation shadow levels (0-5) via CSS custom properties.\n * Sets the --_shadow variable based on elevation attribute.\n *\n * @example\n * ```ts\n * import { elevationMixin } from '../../styles';\n *\n * return {\n * styles: [elevationMixin, componentStyles],\n * template: html`...`\n * };\n * ```\n */\nexport const elevationMixin = css`\n /* ========================================\n Elevation Levels (0-5)\n ======================================== */\n\n :host([elevation='0']) {\n --_shadow: none;\n }\n\n :host([elevation='1']) {\n --_shadow: var(--shadow-sm);\n }\n\n :host([elevation='2']) {\n --_shadow: var(--shadow-md);\n }\n\n :host([elevation='3']) {\n --_shadow: var(--shadow-lg);\n }\n\n :host([elevation='4']) {\n --_shadow: var(--shadow-xl);\n }\n\n :host([elevation='5']) {\n --_shadow: var(--shadow-2xl);\n }\n`;\n\n// ── Forced Colors ─────────────────────────────────────────────────────────────\n\n/**\n * Forced Colors Mixin\n *\n * Ensures components are visually distinct in Windows High Contrast / forced-colors mode.\n * The browser already overrides `color`, `background-color`, and `border-color` to system\n * color keywords, but components that rely solely on `background` for visual identity\n * (no border) or that use `box-shadow` for focus rings need explicit fallbacks.\n *\n * Usage: apply to any component that has a background but no natural border.\n *\n * @example\n * ```ts\n * import { forcedColorsMixin } from '../../styles';\n *\n * return {\n * styles: [forcedColorsMixin, componentStyles],\n * template: html`...`\n * };\n * ```\n */\nexport const forcedColorsMixin = css`\n @media (forced-colors: active) {\n :host {\n border: 1px solid ButtonText;\n }\n }\n`;\n\n/**\n * Forced Colors Focus Ring Mixin\n *\n * Replaces box-shadow focus rings (which are removed in forced-colors mode)\n * with a proper system-color outline.\n *\n * @param selector - CSS selector for the focusable element inside the host\n *\n * @example\n * ```ts\n * import { forcedColorsFocusMixin } from '../../styles';\n *\n * return {\n * styles: [forcedColorsFocusMixin('button'), componentStyles],\n * template: html`...`\n * };\n * ```\n */\nexport const forcedColorsFocusMixin = (selector: string) => css`\n @media (forced-colors: active) {\n ${selector}:focus-visible {\n outline: 2px solid Highlight;\n outline-offset: 2px;\n box-shadow: none;\n }\n }\n`;\n\n/**\n * Forced Colors Form Control Mixin\n *\n * For custom form controls (checkbox, radio, switch, slider) that paint their\n * own visual state. Maps checked/active state to system colors so they remain\n * distinguishable in forced-colors mode.\n *\n * @example\n * ```ts\n * import { forcedColorsFormControlMixin } from '../../styles';\n *\n * return {\n * styles: [forcedColorsFormControlMixin, componentStyles],\n * template: html`...`\n * };\n * ```\n */\nexport const forcedColorsFormControlMixin = css`\n @media (forced-colors: active) {\n :host {\n forced-color-adjust: none;\n color: ButtonText;\n background: ButtonFace;\n border: 1px solid ButtonText;\n }\n\n :host([checked]) {\n background: Highlight;\n color: HighlightText;\n border-color: Highlight;\n }\n\n :host([disabled]) {\n color: GrayText;\n border-color: GrayText;\n }\n }\n`;\n","import { css } from '@vielzeug/ore';\n\n/**\n * Register the --rainbow-angle CSS custom property so browsers can\n * interpolate it inside conic-gradient().\n * Called automatically by rainbowEffectMixin on first use.\n */\nlet rainbowRegistered = false;\n\nexport function registerRainbowProperty() {\n if (rainbowRegistered) return;\n\n if (typeof CSS !== 'undefined' && CSS.registerProperty) {\n try {\n CSS.registerProperty({\n inherits: false,\n initialValue: '0deg',\n name: '--rainbow-angle',\n syntax: '<angle>',\n });\n } catch {\n // Already registered — safe to ignore\n }\n }\n\n rainbowRegistered = true;\n}\n\n/**\n * Register the --shine-angle CSS custom property so browsers can\n * interpolate it inside conic-gradient().\n * Called automatically by shineEffectMixin on first use.\n */\nlet shineRegistered = false;\n\nexport function registerShineProperty() {\n if (shineRegistered) return;\n\n if (typeof CSS !== 'undefined' && CSS.registerProperty) {\n try {\n CSS.registerProperty({\n inherits: false,\n initialValue: '0deg',\n name: '--shine-angle',\n syntax: '<angle>',\n });\n } catch {\n // Already registered — safe to ignore\n }\n }\n\n shineRegistered = true;\n}\n\n/**\n * Rainbow Border Effect Mixin\n *\n * Animated rainbow border with glow effect.\n * Perfect for highlighting call-to-action elements or special features.\n *\n * @param selector - CSS selector for the element (e.g., 'button', '.box')\n * @returns CSSResult with rainbow border animation\n *\n * @example\n * ```ts\n * import { rainbowEffectMixin } from '../../styles/effects/rainbow.css';\n *\n * return {\n * styles: [rainbowEffectMixin('button'), componentStyles],\n * template: html`...`\n * };\n * ```\n */\nexport const rainbowEffectMixin = (selector: string) => {\n registerRainbowProperty();\n\n return css`\n /* ========================================\n Rainbow Border Effect\n ======================================== */\n\n :host([effect='rainbow']) ${selector} {\n position: relative;\n border: var(--border-2) solid transparent !important;\n overflow: visible;\n }\n\n /* Rainbow border and glow layers */\n :host([effect='rainbow']) ${selector}::before, :host([effect='rainbow']) ${selector}::after {\n content: '';\n position: absolute;\n inset: calc(-1 * var(--border-2));\n border: inherit;\n border-radius: inherit;\n\n /* Reserve no-clip space for glow */\n box-shadow: 0 0 calc(3 * var(--blur-xl)) rgba(0 0 0 / 0.001);\n\n /* Rainbow gradient — Okabe-Ito colorblind-safe palette */\n background: conic-gradient(\n from var(--rainbow-angle),\n #56b4e9,\n /* Sky Blue */ #0072b2,\n /* Deep Blue */ #009e73,\n /* Bluish Green */ #f0e442,\n /* Yellow */ #e69f00,\n /* Orange */ #d55e00,\n /* Vermillion */ #cc79a7,\n /* Reddish Purple */ #56b4e9 /* Back to Sky Blue */\n )\n border-box;\n\n /* Make everything inside padding-box transparent\n by subtracting padding-box from no-clip box */\n -webkit-mask:\n conic-gradient(red 0 0) no-clip subtract,\n conic-gradient(red 0 0) padding-box;\n mask:\n conic-gradient(red 0 0) no-clip subtract,\n conic-gradient(red 0 0) padding-box;\n\n pointer-events: none;\n animation: rainbow-rotate 4s linear infinite;\n }\n\n /* Turn one pseudo layer into glow halo */\n :host([effect='rainbow']) ${selector}::after {\n filter: blur(var(--blur-xl));\n }\n\n /* ========================================\n Animation\n ======================================== */\n\n @keyframes rainbow-rotate {\n to {\n --rainbow-angle: 1turn;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n :host([effect='rainbow']) ${selector}::before, :host([effect='rainbow']) ${selector}::after {\n animation: none;\n }\n }\n `;\n};\n\n/**\n * Shine Border Effect Mixin\n *\n * Animated color-aware border shine. A tight arc of the component's own\n * theme color rotates around the border, producing the glossy \"shimmer\"\n * look seen in modern card and button designs.\n *\n * Respects the `color` attribute via `--_theme-*` tokens — no extra\n * configuration needed. Falls back to the neutral theme when no color\n * is set.\n *\n * @param selector - CSS selector for the inner element (e.g., 'button', '.box')\n * @returns CSSResult with shine border animation\n *\n * @example\n * ```ts\n * styles: [shineEffectMixin('button'), componentStyles]\n * ```\n */\nexport const shineEffectMixin = (selector: string) => {\n registerShineProperty();\n\n return css`\n /* ========================================\n Shine Border Effect\n ======================================== */\n\n :host([effect='shine']) ${selector} {\n position: relative;\n overflow: visible;\n --_shine-color: light-dark(\n oklch(from var(--_theme-focus) 0.6 calc(c * 1.2) h),\n oklch(from var(--_theme-focus) 0.85 calc(c * 1.2) h)\n );\n }\n\n /* Shine border — single pseudo, glow via box-shadow (follows border-radius, no artifacts) */\n :host([effect='shine']) ${selector}::before {\n content: '';\n position: absolute;\n inset: calc(-1 * var(--border-2));\n border: var(--border-2) solid transparent;\n border-radius: calc(var(--_radius, 0px) + var(--border-2));\n\n /* Two comet tails 180deg apart, same shape rotating together */\n background:\n conic-gradient(from var(--shine-angle), transparent 0%, transparent 75%, var(--_shine-color) 100%) border-box,\n conic-gradient(\n from calc(var(--shine-angle) + 180deg),\n transparent 0%,\n transparent 75%,\n var(--_shine-color) 100%\n )\n border-box;\n\n -webkit-mask:\n conic-gradient(red 0 0) no-clip subtract,\n conic-gradient(red 0 0) padding-box;\n mask:\n conic-gradient(red 0 0) no-clip subtract,\n conic-gradient(red 0 0) padding-box;\n\n /* Use the theme's own focus-shadow — color-aware, well-tuned, no artifacts */\n box-shadow: var(--_theme-shadow);\n\n pointer-events: none;\n animation: shine-rotate 2.5s linear infinite;\n }\n\n /* ========================================\n Animation\n ======================================== */\n\n @keyframes shine-rotate {\n to {\n --shine-angle: 1turn;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n :host([effect='shine']) ${selector}::before {\n animation: none;\n }\n }\n `;\n};\n","import { css } from '@vielzeug/ore';\n\n/**\n * Frost Variant Mixin\n *\n * Shared frost variant styles for components.\n * Provides consistent frosted glass effect with backdrop blur,\n * theme-aware colors, halo shadows, and elevation support.\n *\n * @param selector - CSS selector for the element (e.g., 'button', '.card', '.field')\n * @returns CSSResult with complete frost variant implementation\n *\n * @example\n * ```ts\n * import { frostVariantMixin } from '../../styles/mixins/frost.css';\n *\n * return {\n * styles: [frostVariantMixin('button'), componentStyles],\n * template: html`...`\n * };\n * ```\n */\nexport const frostVariantMixin = (selector: string) => css`\n :host([variant='frost']) ${selector} {\n backdrop-filter: blur(var(--blur-xl)) saturate(200%) brightness(1.1);\n -webkit-backdrop-filter: blur(var(--blur-xl)) saturate(200%) brightness(1.1);\n }\n\n :host([variant='frost']:not([color])) ${selector} {\n background: color-mix(in oklch, var(--color-canvas) 55%, transparent);\n color: var(--color-contrast);\n text-shadow: var(--text-shadow-xs);\n border: var(--border) solid color-mix(in oklch, var(--color-contrast-400) 45%, transparent);\n }\n\n /* Frost neutral without elevation: use halo shadow */\n :host([variant='frost']:not([color]):not([elevation])) ${selector} {\n box-shadow: var(--halo-shadow-neutral);\n }\n\n /* Frost neutral with elevation: combine halo with elevation shadow */\n :host([variant='frost']:not([color])[elevation]) ${selector} {\n box-shadow: var(--halo-shadow-neutral), var(--_shadow);\n }\n\n :host([variant='frost'][color]) ${selector} {\n background: color-mix(in oklch, var(--_theme-base), transparent);\n border-color: color-mix(in oklch, var(--_theme-border) 45%, transparent);\n color: var(--_theme-content);\n border: var(--border) solid color-mix(in oklch, var(--_theme-border) 45%, transparent);\n backdrop-filter: blur(var(--blur-2xl)) saturate(220%) brightness(1.15);\n -webkit-backdrop-filter: blur(var(--blur-2xl)) saturate(220%) brightness(1.15);\n text-shadow: var(--text-shadow-xs);\n filter: brightness(1.05);\n }\n\n /* Frost color without elevation: use halo shadow */\n :host([variant='frost'][color]:not([elevation])) ${selector} {\n box-shadow: var(--_theme-halo);\n }\n\n /* Frost color with elevation: combine halo with elevation shadow */\n :host([variant='frost'][color][elevation]) ${selector} {\n box-shadow: var(--_theme-halo), var(--_shadow);\n }\n\n :host([variant='frost']:not([color])) ${selector}:hover {\n backdrop-filter: blur(var(--blur-2xl)) saturate(220%) brightness(1.15);\n -webkit-backdrop-filter: blur(var(--blur-2xl)) saturate(220%) brightness(1.15);\n }\n\n :host([variant='frost'][color]) ${selector}:hover {\n backdrop-filter: blur(var(--blur-3xl)) saturate(240%) brightness(1.2);\n -webkit-backdrop-filter: blur(var(--blur-3xl)) saturate(240%) brightness(1.2);\n }\n`;\n","import { css } from '@vielzeug/ore';\n\n/**\n * Table Base Mixin\n *\n * Shared structural foundation for table-like components (`ore-table`, `ore-datagrid`).\n * Covers only the `:host` shell, `.scroll-container`, and the bare `table` element.\n * Each consumer component owns all cell, row, head, and footer styles itself.\n *\n * Token naming:\n * - `--_accent` Primary interactive accent (sort icons, selection borders, focus rings).\n * Defaults to `--color-primary-focus`. Override via `--{prefix}-accent`.\n *\n * @param prefix CSS custom-property namespace, e.g. `'table'` or `'datagrid'`\n *\n * @example\n * ```ts\n * // ore-table\n * styles: [tableBaseMixin('table'), componentStyles]\n *\n * // ore-datagrid\n * styles: [tableBaseMixin('datagrid'), componentStyles]\n * ```\n */\nexport const tableBaseMixin = (prefix: string) => css`\n @layer refine.base {\n :host {\n /* ── Public token API ─────────────────────────────────────────────── */\n --_bg: var(--${prefix}-bg, var(--color-canvas));\n --_border-color: var(--${prefix}-border-color, var(--color-contrast-200));\n --_radius: var(--${prefix}-radius, var(--rounded-xl));\n --_header-bg: var(--${prefix}-header-bg, var(--color-contrast-50));\n --_accent: var(--${prefix}-accent, var(--color-neutral-focus));\n --_row-hover-bg: var(--${prefix}-row-hover-bg, color-mix(in oklch, var(--_accent) 6%, transparent));\n --_stripe-bg: var(--${prefix}-stripe-bg, color-mix(in oklch, var(--color-contrast-900) 3%, transparent));\n --_cell-padding-x: var(--${prefix}-cell-padding-x, var(--size-3));\n --_cell-padding-y: var(--${prefix}-cell-padding-y, var(--size-2-5));\n --_font-size: var(--${prefix}-font-size, var(--text-sm));\n\n display: block;\n overflow: hidden;\n background: var(--_bg);\n border: var(--border) solid var(--_border-color);\n border-radius: var(--_radius);\n box-shadow: var(--${prefix}-shadow, var(--shadow-sm));\n }\n\n /* ── Scroll wrapper ─────────────────────────────────────────────────── */\n\n .scroll-container {\n overflow: auto;\n max-height: var(--${prefix}-max-height, none);\n }\n\n /* ── Native table ───────────────────────────────────────────────────── */\n\n table {\n width: 100%;\n font-size: var(--_font-size);\n table-layout: auto;\n border-collapse: collapse;\n background: var(--_bg);\n }\n\n /* ── Loading state ──────────────────────────────────────────────────── */\n\n :host([loading]) .scroll-container {\n opacity: 0.5;\n pointer-events: none;\n cursor: wait;\n }\n }\n\n @layer refine.variants {\n /* Bordered */\n :host([bordered]) {\n overflow: hidden;\n border: var(--border) solid var(--_border-color);\n border-radius: var(--_radius);\n box-shadow: var(--shadow-xs);\n }\n\n :host([bordered]) .scroll-container {\n border-radius: inherit;\n clip-path: inset(0 round var(--_radius));\n }\n\n /* Sticky header */\n :host([sticky]) .scroll-container {\n max-height: var(--${prefix}-sticky-max-height, 24rem);\n overflow-y: auto;\n }\n }\n\n @layer refine.density {\n :host([density='compact']) {\n --_cell-padding-x: var(--size-2);\n --_cell-padding-y: var(--size-1-5);\n }\n\n :host([density='cozy']) {\n --_cell-padding-x: var(--size-3);\n --_cell-padding-y: var(--size-2-5);\n }\n\n :host([density='comfortable']) {\n --_cell-padding-x: var(--size-4);\n --_cell-padding-y: var(--size-3-5);\n }\n }\n\n @layer refine.overrides {\n :host([fullwidth]) {\n width: 100%;\n }\n }\n`;\n","/**\n * Shared Mixins & Effects\n *\n * Reusable CSS mixins for common component patterns.\n */\n\nimport { coarsePointerMixin, reducedMotionMixin } from './mixins/accessibility.css';\nimport { paddingMixin, roundedVariantMixin } from './mixins/shape.css';\nimport { disabledLoadingMixin } from './mixins/states.css';\nimport { colorThemeMixin, elevationMixin } from './mixins/theme.css';\n\n// Accessibility Mixins\nexport { coarsePointerMixin, reducedMotionMixin, SR_ONLY_INLINE_STYLE, srOnlyMixin } from './mixins/accessibility.css';\n// Effects\nexport {\n rainbowEffectMixin,\n registerRainbowProperty,\n registerShineProperty,\n shineEffectMixin,\n} from './mixins/animation.css';\n// Shape Mixins (padding, rounded, size)\nexport { paddingMixin, roundedVariantMixin, sizeVariantMixin } from './mixins/shape.css';\n// State Mixins\nexport { disabledLoadingMixin, disabledStateMixin, loadingStateMixin } from './mixins/states.css';\n// Theme Mixins (color, elevation, forced-colors)\nexport {\n colorThemeMixin,\n elevationMixin,\n forcedColorsFocusMixin,\n forcedColorsFormControlMixin,\n forcedColorsMixin,\n} from './mixins/theme.css';\n// Frost Mixin\nexport { frostVariantMixin } from './mixins/variants.css';\n// Table Base Mixin\nexport { tableBaseMixin } from './mixins/table-base.css';\n\n// ── Preset Arrays ─────────────────────────────────────────────────────────────\n\n/**\n * Base mixins for elevated surface components (box, card).\n * Covers theming, elevation shadows, padding, and border radius.\n *\n * @example\n * ```ts\n * styles: [...surfaceMixins, frostVariantMixin('.box'), componentStyles]\n * ```\n */\nexport const surfaceMixins = [colorThemeMixin, elevationMixin, paddingMixin, roundedVariantMixin] as const;\n\n/**\n * Base mixins shared by every text input component (input, textarea, file-input).\n * Covers theming, coarse-pointer targets, reduced-motion, border radius, and\n * disabled/loading states.\n *\n * **Required additions** (component-specific arguments, so not included here):\n * - `sizeVariantMixin(YOUR_PRESET)` — supply the component's size config.\n * - `forcedColorsFocusMixin(selector)` — **mandatory** for WCAG forced-colors\n * compliance. Pass the CSS selector for the component's focusable inner\n * element (e.g. `'input'`, `'textarea'`, `'.dropzone'`). Omitting this\n * removes the focus ring in Windows High Contrast mode.\n *\n * @example\n * ```ts\n * styles: [...fieldMixins, sizeVariantMixin(FIELD_SIZE_PRESET), forcedColorsFocusMixin('input'), componentStyles]\n * ```\n */\nexport const fieldMixins = [\n colorThemeMixin,\n coarsePointerMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n disabledLoadingMixin,\n] as const;\n","const isDev = !(globalThis as { __REFINE_PROD__?: boolean }).__REFINE_PROD__;\n\n/**\n * Emits a `console.warn` in development builds only.\n * @internal\n * @security Messages may include user-supplied attribute values or element content.\n * Never pass PII or secrets as component attributes.\n */\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/refine] ${msg}`);\n}\n","@layer refine.base {\n :host {\n display: inline-flex;\n line-height: 0;\n vertical-align: middle;\n color: inherit;\n }\n\n :host([hidden]) {\n display: none;\n }\n\n svg {\n display: block;\n width: 100%;\n height: 100%;\n }\n}\n\n/* Unlayered: always wins over any @layer rule, including refine.overrides */\n:host {\n width: var(--ore-icon-size, var(--_size-px));\n height: var(--ore-icon-size, var(--_size-px));\n}\n","import { define, html, prop } from '@vielzeug/ore';\nimport { raw } from '@vielzeug/ore/directives';\nimport { computed } from '@vielzeug/ripple';\nimport * as lucideModule from 'lucide';\n\nimport { warn } from '../../_dev';\nimport styles from './icon.css?inline';\n\nexport type IconNode = Array<[string, Record<string, string | number | undefined>]>;\n\nconst DEFAULT_SIZE = 16;\nconst DEFAULT_STROKE_WIDTH = 2;\nconst LUCIDE_VIEWBOX_SIZE = 24;\n\n/**\n * Allowlisted SVG shape/structure element names. Only these tags are permitted\n * when building the SVG markup from an IconNode, preventing arbitrary element\n * injection (e.g. <script>, event-handler-bearing elements).\n */\nconst ALLOWED_SVG_TAGS = new Set([\n 'circle',\n 'clipPath',\n 'defs',\n 'ellipse',\n 'g',\n 'line',\n 'linearGradient',\n 'mask',\n 'path',\n 'polygon',\n 'polyline',\n 'radialGradient',\n 'rect',\n 'stop',\n 'symbol',\n 'use',\n]);\n\n/**\n * Allowlisted SVG presentation / structural attribute names.\n * Event handler attributes (on*) and \"xlink:href\" are excluded.\n */\nconst ATTR_KEY_RE = /^[a-zA-Z][a-zA-Z0-9:_-]*$/;\nconst BLOCKED_ATTR_RE = /^(on|xlink:|xml:|href$)/i;\n\n// Sync registry seeded from lucide at module load; extend at any time via registerIcons()\nconst registry = new Map<string, IconNode>(\n Object.entries((lucideModule as unknown as { icons: Record<string, IconNode> }).icons),\n);\n\n/**\n * Register additional icons (or override existing ones) by name.\n * Keys may be kebab-case or PascalCase — both are accepted by `ore-icon`.\n */\nexport function registerIcons(icons: Record<string, IconNode>): void {\n for (const [name, node] of Object.entries(icons)) {\n registry.set(name, node);\n }\n}\n\nconst toAttrString = (attrs: Record<string, string | number>): string =>\n Object.entries(attrs)\n .filter(([k]) => ATTR_KEY_RE.test(k) && !BLOCKED_ATTR_RE.test(k))\n .map(\n ([k, v]) =>\n `${k}=\"${String(v).replace(/&/g, '&').replace(/\"/g, '"').replace(/</g, '<').replace(/>/g, '>')}\"`,\n )\n .join(' ');\n\nconst toPascalCase = (value: string): string =>\n value\n .replace(/([a-z0-9])([A-Z])/g, '$1-$2')\n .split(/[^a-zA-Z0-9]+/)\n .filter(Boolean)\n .map((p) => p.charAt(0).toUpperCase() + p.slice(1).toLowerCase())\n .join('');\n\nconst parseSize = (value: string | null): number | string => {\n if (value == null || value === '') return DEFAULT_SIZE;\n\n const n = Number(value);\n\n return Number.isFinite(n) && n > 0 && /^\\d+(\\.\\d+)?$/.test(value.trim()) ? n : value;\n};\n\n/** Icon component properties */\nexport type OreIconProps = {\n /** Keep stroke width visually consistent when icon size changes */\n absoluteStrokeWidth?: boolean;\n /** Accessible text label. Decorative icons should omit this. */\n label?: string;\n /** Lucide icon name, e.g. `search` or `chevron-right` */\n name?: string;\n /** Icon width/height in px by default. Accepts CSS lengths. */\n size?: number | string;\n /** Render as a filled/solid shape instead of a stroked outline */\n solid?: boolean;\n /** SVG stroke width */\n strokeWidth?: number;\n};\n\n/**\n * Icon wrapper for consistent Lucide rendering across Block.\n *\n * @element ore-icon\n *\n * @attr {string} name - Lucide icon name, e.g. `search` or `chevron-right`\n * @attr {number|string} size - Width/height (default: 16)\n * @attr {number} stroke-width - SVG stroke width (default: 2)\n * @attr {boolean} absolute-stroke-width - Keep stroke width visually stable across icon sizes\n * @attr {boolean} solid - Render as filled shape instead of stroked outline\n * @attr {string} label - Accessible label; when omitted the icon is decorative\n *\n * @csspart svg - Internal SVG element\n *\n * @example\n * ```html\n * <ore-icon name=\"search\"></ore-icon>\n * <ore-icon name=\"chevron-right\" size=\"18\"></ore-icon>\n * <ore-icon name=\"trash-2\" label=\"Delete\"></ore-icon>\n * <ore-icon name=\"star\" solid></ore-icon>\n * ```\n */\nexport const ICON_TAG = 'ore-icon' as const;\ndefine<OreIconProps>(ICON_TAG, {\n props: {\n absoluteStrokeWidth: prop.bool(),\n label: prop.string(),\n name: prop.string(),\n size: { default: DEFAULT_SIZE as number | string, parse: parseSize, reflect: false },\n solid: prop.bool(),\n strokeWidth: prop.number(DEFAULT_STROKE_WIDTH),\n },\n setup(props, { bind }) {\n bind({\n attr: {\n 'aria-hidden': () => ((props.label.value ?? '').trim() ? null : 'true'),\n 'aria-label': () => (props.label.value ?? '').trim() || null,\n role: () => ((props.label.value ?? '').trim() ? 'img' : null),\n },\n style: {\n '--_size-px': () => {\n const s = props.size.value;\n\n return typeof s === 'number' ? `${s}px` : String(s);\n },\n },\n });\n\n const markup = computed(() => {\n const name = (props.name.value ?? '').trim();\n\n if (!name) return '';\n\n const iconNode = registry.get(name) ?? registry.get(toPascalCase(name));\n\n if (!iconNode) {\n warn(`ore-icon: icon not found: \"${String(name).slice(0, 64)}\"`);\n\n return '';\n }\n\n const size = props.size.value;\n const numericSize = typeof size === 'number' ? size : LUCIDE_VIEWBOX_SIZE;\n\n const strokeWidth =\n props.absoluteStrokeWidth.value && !props.solid.value\n ? props.strokeWidth.value! * (LUCIDE_VIEWBOX_SIZE / numericSize)\n : props.strokeWidth.value!;\n\n const nodes = iconNode\n .filter(([tag]) => ALLOWED_SVG_TAGS.has(tag))\n .map(([tag, tagAttrs]) => {\n const attrs: Record<string, string | number> = {};\n\n for (const [k, v] of Object.entries(tagAttrs)) {\n if (v !== undefined) attrs[k] = v;\n }\n\n return `<${tag} ${toAttrString(attrs)} />`;\n })\n .join('');\n\n const svgAttrs = toAttrString({\n fill: props.solid.value ? 'currentColor' : 'none',\n part: 'svg',\n stroke: props.solid.value ? 'none' : 'currentColor',\n 'stroke-linecap': 'round',\n 'stroke-linejoin': 'round',\n 'stroke-width': props.solid.value ? 0 : strokeWidth,\n style: `width:100%;height:100%`,\n viewBox: '0 0 24 24',\n xmlns: 'http://www.w3.org/2000/svg',\n });\n\n return `<svg ${svgAttrs}>${nodes}</svg>`;\n });\n\n return html`${raw(markup)}`;\n },\n styles: [styles],\n});\n","@layer refine.base {\n :host {\n --_bg: var(--copy-command-bg, var(--color-contrast-100));\n --_color: var(--copy-command-color, var(--text-color-body));\n --_border-color: var(--copy-command-border-color, var(--color-contrast-300));\n --_radius: var(--copy-command-radius, var(--rounded-md));\n --_padding: var(--copy-command-padding, var(--size-2) var(--size-3));\n --_font-size: var(--copy-command-font-size, var(--text-sm));\n --_icon-color: var(--copy-command-icon-color, var(--text-color-secondary));\n --_hover-bg: var(--copy-command-hover-bg, var(--color-contrast-200));\n\n display: inline-block;\n }\n\n :host([hidden]) {\n display: none;\n }\n\n /* ── rounded attribute → CSS variable ───────────────────── */\n\n :host([rounded='none']) {\n --_radius: var(--rounded-none, 0);\n }\n\n :host([rounded='sm']) {\n --_radius: var(--rounded-sm);\n }\n\n :host([rounded='md']) {\n --_radius: var(--rounded-md);\n }\n\n :host([rounded='lg']) {\n --_radius: var(--rounded-lg);\n }\n\n :host([rounded='xl']) {\n --_radius: var(--rounded-xl);\n }\n\n :host([rounded='2xl']) {\n --_radius: var(--rounded-2xl);\n }\n\n :host([rounded='3xl']) {\n --_radius: var(--rounded-3xl);\n }\n\n :host([rounded='full']) {\n --_radius: var(--rounded-full);\n }\n\n /* ── size variants ───────────────────────────────────────── */\n\n :host([size='sm']) {\n --_padding: var(--copy-command-padding, var(--size-1) var(--size-2));\n --_font-size: var(--copy-command-font-size, var(--text-xs));\n }\n\n :host([size='lg']) {\n --_padding: var(--copy-command-padding, var(--size-2-5) var(--size-4));\n --_font-size: var(--copy-command-font-size, var(--text-base));\n }\n\n /* ── visual variants ─────────────────────────────────────── */\n\n :host([variant='bordered']) {\n --_bg: var(--copy-command-bg, transparent);\n --_border-color: var(--copy-command-border-color, var(--color-contrast-400));\n }\n\n :host([variant='ghost']) {\n --_bg: var(--copy-command-bg, transparent);\n --_border-color: var(--copy-command-border-color, transparent);\n --_hover-bg: var(--copy-command-hover-bg, var(--color-contrast-100));\n }\n\n /* ── layout ──────────────────────────────────────────────── */\n\n .wrapper {\n display: inline-flex;\n align-items: stretch;\n overflow: hidden;\n background: var(--_bg);\n border: var(--border) solid var(--_border-color);\n border-radius: var(--_radius);\n transition:\n border-color var(--transition-normal),\n background var(--transition-normal);\n }\n\n /* ── command button ──────────────────────────────────────── */\n\n .command {\n display: inline-flex;\n flex: 1;\n gap: var(--size-2);\n align-items: center;\n padding: var(--_padding);\n font-family: var(--font-mono);\n font-size: var(--_font-size);\n color: var(--_color);\n text-align: start;\n cursor: pointer;\n background: transparent;\n border: none;\n transition: background var(--transition-normal);\n }\n\n .command:hover {\n background: var(--_hover-bg);\n }\n\n .command:focus-visible {\n outline: 2px solid var(--color-primary);\n outline-offset: -2px;\n border-radius: calc(var(--_radius) - 1px);\n }\n\n /* ── command text ────────────────────────────────────────── */\n\n .command-text {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n font-family: inherit;\n font-size: inherit;\n color: inherit;\n white-space: nowrap;\n background: transparent;\n }\n\n /* ── copy icon ───────────────────────────────────────────── */\n\n .copy-icon {\n display: inline-flex;\n flex-shrink: 0;\n align-items: center;\n color: var(--_icon-color);\n transition: color var(--transition-normal);\n }\n\n .icon-copied {\n color: var(--color-success, oklch(64% 0.17 142deg));\n }\n\n .icon-failed {\n color: var(--color-danger, oklch(63% 0.21 25deg));\n }\n\n /* ── suffix slot ─────────────────────────────────────────── */\n\n .suffix {\n display: flex;\n align-items: stretch;\n border-inline-start: var(--border) solid var(--_border-color);\n }\n\n .suffix[hidden] {\n display: none;\n }\n\n ::slotted([slot='suffix']) {\n display: flex;\n align-items: center;\n }\n\n /* .sr-only is provided by the shared srOnlyMixin (see styles: [...] in copy-command.ts) */\n}\n","import { define, html, prop } from '@vielzeug/ore';\nimport { computed, signal } from '@vielzeug/ripple';\n\nimport type { ComponentSize, RoundedSize } from '../../types';\n\nimport { srOnlyMixin } from '../../styles';\nimport '../icon/icon';\nimport componentStyles from './copy-command.css?inline';\n\n/** Copy command component properties */\nexport type OreCopyCommandProps = {\n /** Border radius size */\n rounded?: RoundedSize;\n /** Component size */\n size?: ComponentSize;\n /** The command string to display and copy to clipboard */\n value?: string;\n /** Visual style variant */\n variant?: 'flat' | 'bordered' | 'ghost';\n};\n\n/** Copy command component events */\nexport type OreCopyCommandEvents = {\n /** Emitted when the command is successfully copied to the clipboard */\n copy: { value: string };\n};\n\n/**\n * A styled, copy-to-clipboard command display component.\n * Shows a command string in a monospace code block with a copy button.\n * Clicking the component copies the value to the clipboard, shows a transient\n * check-mark confirmation, and emits a `copy` event.\n *\n * @element ore-copy-command\n *\n * @attr {string} value - The command string to display and copy\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} variant - Visual style: 'flat' | 'bordered' | 'ghost'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n *\n * @fires copy - Emitted on successful clipboard write. detail: { value: string }\n *\n * @slot suffix - Optional controls appended after the copy button (e.g. a cycle button)\n *\n * @cssprop --copy-command-bg - Background color of the command block\n * @cssprop --copy-command-color - Text color of the command string\n * @cssprop --copy-command-border-color - Border color\n * @cssprop --copy-command-radius - Border radius (overrides the `rounded` attribute)\n * @cssprop --copy-command-padding - Inner padding of the command button\n * @cssprop --copy-command-font-size - Font size of the command string\n * @cssprop --copy-command-icon-color - Color of the copy/check icon\n * @cssprop --copy-command-hover-bg - Background on hover\n *\n * @part wrapper - Outer flex container\n * @part command - The copy button element\n * @part command-text - The `<code>` element displaying the command string\n * @part copy-icon - The icon wrapper span\n * @part suffix - Suffix slot container\n *\n * @example\n * ```html\n * <ore-copy-command value=\"npm install @vielzeug/ripple\"></ore-copy-command>\n *\n * <ore-copy-command value=\"npx -y @vielzeug/codex\" size=\"sm\" variant=\"bordered\"></ore-copy-command>\n *\n * <!-- With a suffix slot (e.g. a cycle button) -->\n * <ore-copy-command value=\"npm install @vielzeug/ripple\">\n * <button slot=\"suffix\" type=\"button\" aria-label=\"Next package\">›</button>\n * </ore-copy-command>\n * ```\n */\nexport const COPY_COMMAND_TAG = 'ore-copy-command' as const;\n\ndefine<OreCopyCommandProps, OreCopyCommandEvents>(COPY_COMMAND_TAG, {\n props: {\n rounded: prop.string<RoundedSize>('md'),\n size: prop.string<ComponentSize>('md'),\n value: prop.string(''),\n variant: prop.string<'flat' | 'bordered' | 'ghost'>('flat'),\n },\n\n setup(props, { emit, onCleanup, slots }) {\n const copied = signal(false);\n const copyFailed = signal(false);\n let resetTimer: ReturnType<typeof setTimeout> | null = null;\n\n onCleanup(() => {\n if (resetTimer !== null) clearTimeout(resetTimer);\n });\n\n const handleCopy = async () => {\n const text = props.value.value ?? '';\n\n if (!text) return;\n\n if (resetTimer !== null) clearTimeout(resetTimer);\n\n try {\n await navigator.clipboard.writeText(text);\n copied.value = true;\n copyFailed.value = false;\n emit('copy', { value: text });\n } catch {\n // Clipboard access denied or unavailable (e.g. insecure context) — surface it instead of failing silently\n copied.value = false;\n copyFailed.value = true;\n }\n\n resetTimer = setTimeout(() => {\n copied.value = false;\n copyFailed.value = false;\n resetTimer = null;\n }, 2000);\n };\n\n const hasSuffix = computed(() => slots.has('suffix').value);\n const btnLabel = computed(() => {\n if (copied.value) return 'Copied!';\n\n if (copyFailed.value) return 'Copy failed — press to try again';\n\n return `Copy: ${props.value.value ?? ''}`;\n });\n\n return html`\n <div class=\"wrapper\" part=\"wrapper\">\n <button class=\"command\" part=\"command\" type=\"button\" :aria-label=\"${btnLabel}\" @click=${handleCopy}>\n <code class=\"command-text\" part=\"command-text\">${props.value}</code>\n <span class=\"copy-icon\" part=\"copy-icon\" aria-hidden=\"true\">\n ${() => {\n if (copied.value)\n return html`<ore-icon name=\"check\" size=\"14\" class=\"icon-copied\" aria-hidden=\"true\"></ore-icon>`;\n\n if (copyFailed.value)\n return html`<ore-icon name=\"circle-alert\" size=\"14\" class=\"icon-failed\" aria-hidden=\"true\"></ore-icon>`;\n\n return html`<ore-icon name=\"copy\" size=\"14\" aria-hidden=\"true\"></ore-icon>`;\n }}\n </span>\n </button>\n <div class=\"suffix\" part=\"suffix\" ?hidden=\"${() => !hasSuffix.value}\">\n <slot name=\"suffix\"></slot>\n </div>\n </div>\n <div role=\"status\" class=\"sr-only\">\n ${() => {\n if (copied.value) return 'Copied to clipboard.';\n\n if (copyFailed.value) return 'Copy failed. Select the command text and copy it manually.';\n\n return '';\n }}\n </div>\n `;\n },\n\n styles: [srOnlyMixin, componentStyles],\n});\n","import { prop } from '@vielzeug/ore';\n\nimport type { ComponentSize, ElevationLevel, RoundedSize, ThemeColor } from './types';\n\n/** Prop bundle for components that support a theme colour. */\nexport const themableBundle = {\n color: prop.string<ThemeColor>(),\n};\n\n/** Prop bundle for components with discrete size variants. */\nexport const sizableBundle = {\n size: prop.string<ComponentSize>(),\n};\n\n/** Prop bundle for interactive components that can be disabled. */\nexport const disablableBundle = {\n disabled: prop.bool(false),\n};\n\n/** Prop bundle for components with a loading / busy state. */\nexport const loadableBundle = {\n loading: prop.bool(false),\n};\n\n/** Prop bundle for components with configurable border-radius. */\nexport const roundableBundle = {\n rounded: prop.string<RoundedSize>(),\n};\n\n/** Prop bundle for components with an elevation / box-shadow. */\nexport const elevatableBundle = {\n elevation: prop.number<ElevationLevel>(),\n};\n\n/**\n * Convenience bundle combining the five most common interactive-component props:\n * `color`, `size`, `disabled`, `loading`, and `rounded`.\n *\n * Use this single spread instead of five separate bundle spreads when a\n * component needs all of them.\n *\n * @example\n * ```ts\n * props: { ...commonProps, href: prop.string() }\n * ```\n */\nexport const commonProps = {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n ...loadableBundle,\n ...roundableBundle,\n};\n","import type { SizeConfig } from '../styles/mixins/shape.css';\nimport type { ComponentSize } from './types';\n\n/** A preset with an entry for every ComponentSize key. */\ntype FullSizePreset = Record<ComponentSize, SizeConfig>;\n\n/** A preset that may omit some ComponentSize keys (sizeVariantMixin fills the gaps with its defaults). */\ntype PartialSizePreset = Partial<Record<ComponentSize, SizeConfig>>;\n\nexport const FIELD_SIZE_PRESET = {\n lg: {\n '--_field-height': 'var(--size-12)',\n '--_padding': 'var(--size-2-5) var(--size-3-5)',\n fontSize: 'var(--text-base)',\n gap: 'var(--size-2-5)',\n },\n md: {\n '--_field-height': 'var(--size-10)',\n '--_padding': 'var(--size-1-5) var(--size-3)',\n fontSize: 'var(--text-sm)',\n gap: 'var(--size-2)',\n },\n sm: {\n '--_field-height': 'var(--size-8)',\n '--_padding': 'var(--size-1) var(--size-2)',\n fontSize: 'var(--text-xs)',\n gap: 'var(--size-1-5)',\n },\n} satisfies FullSizePreset;\n\nexport const TEXTAREA_SIZE_PRESET = {\n lg: {\n '--_padding': 'var(--size-2-5) var(--size-3-5)',\n fontSize: 'var(--text-base)',\n gap: 'var(--size-2-5)',\n },\n md: {\n '--_padding': 'var(--size-1-5) var(--size-3)',\n fontSize: 'var(--text-sm)',\n gap: 'var(--size-2)',\n },\n sm: {\n '--_padding': 'var(--size-1) var(--size-2)',\n fontSize: 'var(--text-xs)',\n gap: 'var(--size-1-5)',\n },\n} satisfies FullSizePreset;\n\n/** Shared size preset for checkbox and radio (icon + label layout). */\nexport const CONTROL_SIZE_PRESET = {\n lg: {\n fontSize: 'var(--text-base)',\n gap: 'var(--size-2-5)',\n size: 'var(--size-6)',\n },\n sm: {\n fontSize: 'var(--text-xs)',\n gap: 'var(--size-1-5)',\n size: 'var(--size-4)',\n },\n} satisfies PartialSizePreset;\n\n/** Shared size preset for the switch toggle control. */\nexport const SWITCH_SIZE_PRESET = {\n lg: {\n fontSize: 'var(--text-base)',\n gap: 'var(--size-3)',\n height: 'var(--size-7)',\n thumbSize: 'var(--size-6)',\n width: 'var(--size-14)',\n },\n sm: {\n fontSize: 'var(--text-xs)',\n gap: 'var(--size-2)',\n height: 'var(--size-5)',\n thumbSize: 'var(--size-4)',\n width: 'var(--size-9)',\n },\n} satisfies PartialSizePreset;\n\n/** Shared size preset for the slider track/thumb. */\nexport const SLIDER_SIZE_PRESET = {\n lg: {\n fontSize: 'var(--text-base)',\n height: 'calc(var(--size-5) - var(--size-1))',\n size: 'var(--size-5)',\n },\n md: {\n fontSize: 'var(--text-base)',\n height: 'var(--size-3)',\n size: 'var(--size-5)',\n },\n sm: {\n fontSize: 'var(--text-xs)',\n height: 'var(--size-2)',\n size: 'var(--size-4)',\n },\n} satisfies FullSizePreset;\n\n/** Shared size preset for the file-input dropzone. */\nexport const FILE_INPUT_SIZE_PRESET = {\n lg: {\n '--_min-height': 'var(--size-40)',\n fontSize: 'var(--text-base)',\n },\n md: {\n '--_min-height': 'var(--size-32)',\n fontSize: 'var(--text-sm)',\n },\n sm: {\n '--_min-height': 'var(--size-28)',\n fontSize: 'var(--text-xs)',\n },\n} satisfies FullSizePreset;\n","@layer refine.base {\n :host {\n --_height: var(--progress-height, var(--size-2, 0.5rem));\n --_radius: var(--progress-radius, var(--rounded-lg));\n --_circle-size: var(--progress-circle-size, 6rem);\n --_circular-label-size: var(--progress-circular-label-size, var(--text-xl, 1.25rem));\n --_circular-title-size: var(--progress-circular-title-size, var(--text-xs, 0.75rem));\n\n display: block;\n\n /* Stretch to fill the parent container (matches native <progress> behaviour).\n The host's width is set against its parent, so % widths inside shadow DOM\n (.track, .fill) resolve correctly in any flex/grid/block context. */\n width: 100%;\n }\n\n /* ========================================\n Linear Bar\n ======================================== */\n\n .track {\n width: 100%;\n height: var(--_height);\n overflow: hidden;\n\n /* contrast-300 (88% lightness) gives a visible groove in light mode */\n background: var(--progress-track-bg, var(--color-contrast-300, #ddd));\n border-radius: var(--_radius);\n }\n\n .fill {\n width: var(--_percent, 0%);\n height: 100%;\n background: var(--progress-fill, var(--_theme-base, #3b82f6));\n border-radius: inherit;\n transform-origin: left;\n transition: var(--_motion-transition, width var(--transition-normal));\n }\n\n /* In RTL the fill grows from the inline-end (physical right) side */\n :host(:dir(rtl)) .fill {\n transform-origin: right;\n }\n\n /* Indeterminate: sliding bar */\n @keyframes ore-progress-slide {\n 0% {\n transform: translateX(-150%) scaleX(0.6);\n }\n\n 50% {\n transform: translateX(50%) scaleX(1);\n }\n\n 100% {\n transform: translateX(300%) scaleX(0.6);\n }\n }\n\n :host([indeterminate]) .fill {\n width: 40%;\n animation: var(--_motion-animation, ore-progress-slide var(--duration-1500) var(--ease-linear) infinite);\n }\n\n /* In RTL the indeterminate bar sweeps right-to-left */\n :host(:dir(rtl)[indeterminate]) .fill {\n animation-direction: reverse;\n }\n\n /* ========================================\n Vertical Bar\n ======================================== */\n\n :host([type='vertical']) {\n --_width: var(--progress-width, var(--size-2, 0.5rem));\n\n display: inline-flex;\n width: auto;\n }\n\n :host([type='vertical']) .wrapper {\n flex-direction: row;\n gap: var(--progress-label-gap, var(--space-1, 0.25rem));\n width: auto;\n height: 100%;\n }\n\n :host([type='vertical']) .track {\n width: var(--_width);\n height: 100%;\n overflow: hidden;\n }\n\n :host([type='vertical']) .fill {\n width: 100%;\n height: var(--_percent, 0%);\n transform-origin: bottom;\n transition: var(--_motion-transition, height var(--transition-normal));\n }\n\n :host([type='vertical'][indeterminate]) .fill {\n height: 40%;\n animation: var(--_motion-animation, ore-progress-slide-v var(--duration-1500) var(--ease-linear) infinite);\n }\n\n @keyframes ore-progress-slide-v {\n 0% {\n transform: translateY(150%) scaleY(0.6);\n }\n\n 50% {\n transform: translateY(-50%) scaleY(1);\n }\n\n 100% {\n transform: translateY(-300%) scaleY(0.6);\n }\n }\n\n .bar-row-vertical {\n display: flex;\n flex-direction: column;\n align-items: center;\n height: 100%;\n }\n\n :host([type='vertical']) .track-outer {\n display: flex;\n flex: 1 1 0%;\n align-items: stretch;\n justify-content: center;\n width: auto;\n height: 100%;\n }\n\n /* ========================================\n Wrapper / Label / Title / Floating label\n ======================================== */\n\n /* Flex-column shell for the linear variant */\n .wrapper {\n display: flex;\n flex-direction: column;\n gap: var(--progress-label-gap, var(--space-1, 0.25rem));\n width: 100%;\n }\n\n /* Header row ─ visible only when [title] is present */\n .header {\n display: none;\n gap: var(--space-2, 0.5rem);\n align-items: baseline;\n justify-content: space-between;\n }\n\n :host([title]) .header {\n display: flex;\n }\n\n .progress-title {\n font-size: var(--text-sm, 0.875rem);\n font-weight: var(--font-weight-medium, 500);\n line-height: 1.25;\n color: var(--progress-title-color, currentColor);\n }\n\n /* Label inside the header ─ only when both [title] and [label] are set */\n .header-label {\n display: none;\n }\n\n :host([title][label]) .header-label {\n display: inline;\n }\n\n /* Bar row ─ transparent wrapper by default; becomes a flex row when\n [label] is present without [title] so the label sits beside the bar */\n .bar-row {\n display: contents;\n }\n\n :host([label]:not([title])) .bar-row {\n display: flex;\n gap: var(--progress-label-gap, var(--space-2, 0.5rem));\n align-items: center;\n width: 100%;\n }\n\n /* Outer track container ─ always position:relative for floating-label */\n .track-outer {\n position: relative;\n width: 100%;\n }\n\n :host([label]:not([title])) .track-outer {\n flex: 1 1 0%;\n width: auto;\n min-width: 0;\n }\n\n /* Shared label typography */\n .end-label {\n flex-shrink: 0;\n font-size: var(--text-sm, 0.875rem);\n line-height: 1.25;\n color: var(--progress-label-color, currentColor);\n white-space: nowrap;\n }\n\n /* Trailing end label ─ shown only when [label] is present without [title] */\n .row-label {\n display: none;\n }\n\n :host([label]:not([title])) .row-label {\n display: inline;\n }\n\n /* Floating label chip ─────────────────────────────────────────────────\n Positioned above the fill endpoint.\n Formula: left = X% (fill width) − Y (half chip width)\n Implemented as: left: var(--_percent); transform: translateX(-50%) */\n .floating-label {\n position: absolute;\n bottom: calc(100% + var(--space-1, 0.25rem));\n left: var(--_percent, 0%);\n display: none;\n padding: var(--space-0-5, 0.125rem) var(--space-2, 0.5rem);\n font-size: var(--text-xs, 0.75rem);\n font-weight: var(--font-weight-medium, 500);\n line-height: 1;\n color: var(--color-white, #fff);\n white-space: nowrap;\n pointer-events: none;\n user-select: none;\n background: var(--progress-fill, var(--_theme-base, #3b82f6));\n border-radius: var(--rounded-md, 0.375rem);\n transform: translateX(-50%);\n }\n\n :host([floating-label]:not([indeterminate])) .floating-label {\n display: block;\n }\n\n /* Reserve vertical space above the track so the chip does not clip */\n :host([floating-label]:not([indeterminate])) .wrapper {\n padding-top: calc(var(--text-xs, 0.75rem) + var(--space-1, 0.25rem) * 3);\n }\n\n /* ========================================\n Circular variant\n ======================================== */\n\n .circular-track {\n position: relative; /* anchor the inner text overlay */\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--_circle-size);\n height: var(--_circle-size);\n }\n\n .circular-track svg {\n width: 100%;\n height: 100%;\n overflow: visible;\n transform: rotate(-90deg);\n }\n\n /* Inner overlay — label + title stacked and centered inside the ring */\n .circular-inner {\n position: absolute;\n inset: 0;\n display: flex;\n flex-direction: column;\n gap: var(--space-0-5, 0.125rem);\n align-items: center;\n justify-content: center;\n\n /* Inset from the stroke edge so text stays clear of the ring */\n padding: calc(8% + var(--_height));\n overflow: hidden;\n text-align: center;\n pointer-events: none;\n }\n\n .circular-label {\n max-width: 100%;\n overflow: hidden;\n text-overflow: ellipsis;\n font-size: var(--_circular-label-size);\n font-weight: var(--font-weight-semibold, 600);\n line-height: 1;\n color: var(--progress-label-color, currentColor);\n white-space: nowrap;\n }\n\n .circular-title {\n max-width: 100%;\n overflow: hidden;\n text-overflow: ellipsis;\n font-size: var(--_circular-title-size);\n line-height: 1.25;\n color: var(--progress-title-color, var(--color-contrast-500, #6b7280));\n white-space: nowrap;\n }\n\n /* Hide empty inner text nodes so flexbox gap doesn't create phantom space */\n .circular-label:empty,\n .circular-title:empty {\n display: none;\n }\n\n .circle-bg {\n fill: none;\n stroke: var(--progress-track-bg, var(--color-contrast-300, #ddd));\n stroke-width: var(--progress-stroke-width, calc(var(--_height) * 1.2));\n }\n\n .circle-fill {\n fill: none;\n stroke: var(--progress-fill, var(--_theme-base, #3b82f6));\n stroke-width: var(--progress-stroke-width, calc(var(--_height) * 1.2));\n stroke-linecap: round;\n transition: var(--_motion-transition, stroke-dashoffset var(--transition-normal));\n }\n\n @keyframes ore-progress-spin {\n from {\n transform: rotate(-90deg);\n }\n\n to {\n transform: rotate(270deg);\n }\n }\n\n @keyframes ore-progress-dash {\n 0% {\n stroke-dasharray: 1px var(--_circ);\n stroke-dashoffset: var(--_circ);\n }\n\n 40% {\n stroke-dasharray: calc(var(--_circ) * 0.75) var(--_circ);\n stroke-dashoffset: calc(var(--_circ) * -0.1);\n }\n\n 60% {\n stroke-dasharray: calc(var(--_circ) * 0.75) var(--_circ);\n stroke-dashoffset: calc(var(--_circ) * -0.1);\n }\n\n 100% {\n stroke-dasharray: 1px var(--_circ);\n stroke-dashoffset: calc(var(--_circ) * -0.9);\n }\n }\n\n :host([indeterminate]) .circular-track svg {\n animation: var(--_motion-animation, ore-progress-spin var(--duration-1400) var(--ease-linear) infinite);\n }\n\n :host([indeterminate]) .circle-fill {\n animation: var(--_motion-animation, ore-progress-dash var(--duration-1400) var(--ease-in-out) infinite);\n }\n}\n\n@layer refine.utilities {\n :host([size='sm']) {\n --_height: var(--size-1, 0.25rem);\n --_circle-size: 4rem;\n --_circular-label-size: var(--text-sm, 0.875rem);\n --_circular-title-size: var(--text-2xs, 0.625rem);\n }\n\n :host([size='md']) {\n --_height: var(--size-2, 0.5rem);\n --_circle-size: 6rem;\n }\n\n :host([size='lg']) {\n --_height: var(--size-3-5, 0.875rem);\n --_circle-size: 9rem;\n --_circular-label-size: var(--text-3xl);\n --_circular-title-size: var(--text-sm, 0.875rem);\n }\n}\n\n/* Extra indeterminate state overrides — cannot be expressed via CSS variables alone */\n@media (prefers-reduced-motion: reduce) {\n :host([indeterminate]) .fill {\n width: 100%;\n opacity: 0.6;\n }\n\n :host([indeterminate]) .circle-fill {\n stroke-dasharray: none;\n }\n\n :host([type='vertical'][indeterminate]) .fill {\n height: 100%;\n opacity: 0.6;\n }\n}\n","import { define, html, prop } from '@vielzeug/ore';\nimport { styleMap } from '@vielzeug/ore/directives';\nimport { computed } from '@vielzeug/ripple';\n\nimport type { ComponentSize, ThemeColor } from '../../types';\n\nimport { sizableBundle, themableBundle } from '../../shared';\nimport { colorThemeMixin, forcedColorsMixin, reducedMotionMixin } from '../../styles';\nimport componentStyles from './progress.css?inline';\n\n/** Progress bar component properties */\nexport type OreProgressProps = {\n /** Theme color for the fill bar */\n color?: ThemeColor;\n /** Floating chip centered above the fill endpoint (linear only). Hidden in indeterminate mode. Position formula: left = fill% − half chip width (CSS: left:X%; transform:translateX(−50%)). */\n 'floating-label'?: string;\n /** When true, shows an infinite animation — use when progress is unknown. */\n indeterminate?: boolean;\n /** Accessible name AND visible text label.\n * - Linear without `title`: rendered at the end of the bar.\n * - Linear with `title`: moved into the header row above the bar.\n * - Circular: large text centered inside the ring. */\n label?: string;\n /** Maximum value. Defaults to 100. */\n max?: number;\n /** Size variant controlling bar height */\n size?: ComponentSize;\n /** Title text.\n * - Linear: displayed as a header above the bar; moves `label` into the header row.\n * - Circular: smaller text displayed below the `label` inside the ring. */\n title?: string;\n /** 'linear' (default), 'circular', or 'vertical' */\n type?: 'linear' | 'circular' | 'vertical';\n /** Current progress value (0 to `max`). Ignored when `indeterminate`. */\n value?: number;\n /** Human-readable value text for screen readers (e.g. \"Step 2 of 5\", \"75%\"). Overrides the raw aria-valuenow when set. */\n 'value-text'?: string;\n};\n\n/**\n * A linear progress bar for conveying operation progress.\n * Supports determinate (known value) and indeterminate (unknown duration) modes.\n *\n * @element ore-progress\n *\n * @attr {number} value - Current value (0–max). Defaults to 0.\n * @attr {number} max - Maximum value. Defaults to 100.\n * @attr {boolean} indeterminate - Show infinite animation (ignores value/max).\n * @attr {string} color - Theme color: 'primary' | 'success' | 'warning' | 'error' | …\n * @attr {string} size - Bar height/width: 'sm' | 'md' | 'lg'\n * @attr {string} type - 'linear' (default) | 'circular' | 'vertical'\n *\n * @cssprop --progress-width - Bar width override (vertical only)\n * @attr {string} label - Visible text label + accessible name. Linear: at bar end (or header row with title). Circular: large text centered inside the ring.\n * @attr {string} title - Title text. Linear: header above the bar (moves label to header row). Circular: smaller text below the label inside the ring.\n * @attr {string} floating-label - Floating chip centered above the fill endpoint (linear only); hidden when indeterminate.\n *\n * @cssprop --progress-height - Bar height override\n * @cssprop --progress-track-bg - Track background color\n * @cssprop --progress-fill - Fill bar color\n * @cssprop --progress-radius - Border radius\n * @cssprop --progress-label-gap - Gap between header/bar row and between bar and trailing label (default 0.25 rem)\n * @cssprop --progress-title-color - Title text color (defaults to currentColor)\n * @cssprop --progress-label-color - Label text color (defaults to currentColor)\n * @cssprop --progress-circle-size - Circular indicator diameter (default 6rem)\n * @cssprop --progress-circular-label-size - Font size of the label inside the ring (default --text-xl)\n * @cssprop --progress-circular-title-size - Font size of the title inside the ring (default --text-xs)\n *\n * @part fill - Progress fill element.\n * @example\n * ```html\n * <ore-progress value=\"45\"></ore-progress>\n * <ore-progress value=\"75\" max=\"100\" color=\"success\" size=\"lg\"></ore-progress>\n * <ore-progress indeterminate color=\"primary\" label=\"Loading…\"></ore-progress>\n * ```\n */\nexport const PROGRESS_TAG = 'ore-progress' as const;\ndefine<OreProgressProps>(PROGRESS_TAG, {\n props: {\n ...themableBundle,\n ...sizableBundle,\n 'floating-label': prop.string(),\n indeterminate: prop.bool(false),\n label: prop.string(),\n max: prop.number(100),\n title: prop.string(),\n type: prop.oneOf(['linear', 'circular', 'vertical'] as const, 'linear'),\n value: prop.number(0),\n 'value-text': prop.string(),\n },\n\n setup(props, { el, watch }) {\n // The SVG circle circumference for a radius of 45 (viewBox 0 0 100 100)\n const RADIUS = 45;\n const CIRC = 2 * Math.PI * RADIUS; // ~282.7\n\n const percent = computed(() => {\n const v = Math.max(0, Math.min(Number(props.value.value), Number(props.max.value)));\n const m = Math.max(1, Number(props.max.value));\n\n return `${(v / m) * 100}%`;\n });\n\n const dashoffset = computed(() => {\n const v = Math.max(0, Math.min(Number(props.value.value), Number(props.max.value)));\n const m = Math.max(1, Number(props.max.value));\n\n return CIRC - (v / m) * CIRC;\n });\n\n const ariaValueNow = () => (props.indeterminate.value ? null : String(props.value.value));\n const ariaLabel = () => props.label.value ?? props.title.value ?? 'Progress';\n const circularStyle = styleMap({ '--_circ': `${CIRC}px` });\n const strokeDasharray = () => (props.indeterminate.value ? undefined : `${CIRC}px`);\n const strokeDashoffset = () => (props.indeterminate.value ? undefined : `${dashoffset.value}px`);\n const isVertical = computed(() => props.type.value === 'vertical');\n const linearFillStyle = styleMap({\n height: () => (!props.indeterminate.value && isVertical.value ? percent.value : null),\n width: () => (!props.indeterminate.value && !isVertical.value ? percent.value : null),\n });\n\n watch(() => {\n el.style.setProperty('--_percent', props.indeterminate.value ? '0%' : percent.value);\n });\n\n const circularTemplate = () =>\n html` <div\n class=\"circular-track\"\n role=\"progressbar\"\n :aria-valuenow=\"${ariaValueNow}\"\n aria-valuemin=\"0\"\n :aria-valuemax=\"${props.max}\"\n :aria-label=\"${ariaLabel}\"\n :aria-valuetext=\"${props['value-text']}\"\n :style=\"${circularStyle}\">\n <svg viewBox=\"0 0 100 100\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle class=\"circle-bg\" cx=\"50\" cy=\"50\" r=\"${RADIUS}\"></circle>\n <circle\n class=\"circle-fill\"\n cx=\"50\"\n cy=\"50\"\n r=\"${RADIUS}\"\n :stroke-dasharray=\"${strokeDasharray}\"\n :stroke-dashoffset=\"${strokeDashoffset}\"></circle>\n </svg>\n <div class=\"circular-inner\">\n <span class=\"circular-label\">${() => props.label.value ?? ''}</span>\n <span class=\"circular-title\">${() => props.title.value ?? ''}</span>\n </div>\n </div>`;\n\n const barTemplate = () =>\n html` <div class=\"wrapper\">\n <div class=\"header\">\n <span class=\"progress-title\">${() => props.title.value ?? ''}</span>\n <span class=\"end-label header-label\">${() => props.label.value ?? ''}</span>\n </div>\n <div :class=${() => `bar-row${isVertical.value ? ' bar-row-vertical' : ''}`}>\n <div class=\"track-outer\">\n <div\n class=\"track\"\n role=\"progressbar\"\n :aria-valuenow=\"${ariaValueNow}\"\n aria-valuemin=\"0\"\n :aria-valuemax=\"${props.max}\"\n :aria-label=\"${ariaLabel}\"\n :aria-valuetext=\"${props['value-text']}\">\n <div class=\"fill\" part=\"fill\" :style=\"${linearFillStyle}\"></div>\n </div>\n ${() => (!isVertical.value ? html`<span class=\"floating-label\">${props['floating-label']}</span>` : null)}\n </div>\n <span class=\"end-label row-label\">${() => props.label.value ?? ''}</span>\n </div>\n </div>`;\n\n return html` ${() => (props.type.value === 'circular' ? circularTemplate() : barTemplate())} `;\n },\n\n styles: [colorThemeMixin, forcedColorsMixin, reducedMotionMixin, componentStyles],\n});\n","// ── Ore adapter ─────────────────────────────────────────────────────────────\n// Utilities that bridge Ore's component lifecycle with the headless\n// primitives' `AbortSignal`-based lifecycle contract.\n\n/**\n * Creates an `AbortSignal` tied to the component's Ore lifecycle.\n *\n * Call once at the top of a `setup()` function and pass the resulting signal\n * as the required `signal` option to any stateful headless primitive\n * (`createTextField`, `createCheckable`, `createOptionList`, etc.).\n *\n * When Ore disconnects the component, `onCleanup` fires, aborting the\n * signal and triggering cleanup in every primitive that received it.\n *\n * @example\n * ```ts\n * setup(props, { el }) {\n * const signal = lifecycleSignal(onCleanup);\n * const tf = createTextField({ ..., signal });\n * }\n * ```\n */\nexport const lifecycleSignal = (onCleanup: (fn: () => void) => void): AbortSignal => {\n const controller = new AbortController();\n\n onCleanup(() => controller.abort());\n\n return controller.signal;\n};\n","import { createStableId } from '@vielzeug/ore';\nimport { computed, type Readable } from '@vielzeug/ripple';\n\n// ── Validation / context types ────────────────────────────────────────────────\n\nexport type ValidationTrigger = 'blur' | 'change' | 'input' | 'submit';\nexport type ControlValidationMode = ValidationTrigger | undefined;\n\n// ── Field options + handle ───────────────────────────────────────────────────\n\n/** Options shared by both `createTextField` and `createChoiceField`. */\nexport type FieldOptions = {\n disabled?: Readable<boolean | undefined>;\n error?: Readable<string | undefined>;\n /**\n * Returns the underlying form field object used for validation triggering.\n * Called lazily — safe to return `null` before the first render.\n */\n getFormField?: () => { reportValidity(): void } | null;\n /**\n * Override for label visibility that takes precedence over deriving it from\n * the `label` text signal. Pass a computed signal that checks both prop and\n * slot presence to enable slot-first composition.\n *\n * @example\n * ```ts\n * const hasLabel = computed(() => !!props.label.value || slots.has('label').value);\n * const field = createField({ ...options, hasLabel });\n * ```\n */\n hasLabel?: Readable<boolean>;\n helper?: Readable<string | undefined>;\n /**\n * When provided, used directly as `fieldId` instead of generating one via\n * `createStableId`. Useful in tests for deterministic ID assertions.\n */\n id?: string;\n /**\n * Label text signal. When provided, `labelVisible` and `ariaLabelledBy` are\n * computed reactively from this value (see `hasLabel` for the slot-first override).\n */\n label?: Readable<string | undefined>;\n /**\n * Label placement signal. Defaults to `'inset'`.\n *\n * Not currently consumed by `createField()` itself — visibility is driven\n * solely by `hasLabel`/`label`. Threaded through so component authors can\n * apply placement-specific styling (`label-placement` attribute) without a\n * second prop; if placement-dependent visibility is ever needed, wire it\n * into `labelVisible$` in `createField()` instead of adding a new option.\n */\n labelPlacement?: Readable<LabelPlacement>;\n prefix?: string;\n validateOn?: Readable<ControlValidationMode>;\n};\n\n// ── Error/helper assistive state ──────────────────────────────────────────────\n\nexport type ErrorHelperState = {\n errorText: string;\n helperText: string;\n};\n\nexport type ErrorHelperOptions = {\n error?: Readable<string | undefined>;\n helper?: Readable<string | undefined>;\n};\n\nexport const createErrorHelperState = (options: ErrorHelperOptions): Readable<ErrorHelperState> =>\n computed(() => ({\n errorText: options.error?.value ?? '',\n helperText: options.helper?.value ?? '',\n }));\n\n// ── Counter state (opt-in) ─────────────────────────────────────────────────────\n\n/** Counter state for text fields with `maxLength`. */\nexport type CounterState = {\n counterAtLimit: boolean;\n counterNearLimit: boolean;\n counterText: string;\n};\n\nexport type CounterOptions = {\n maxLength?: Readable<number | undefined>;\n value: Readable<string | undefined>;\n};\n\n/**\n * Creates a reactive counter state signal for text fields with `maxLength`.\n * Only call this when `maxLength` may be set — the state is genuinely opt-in.\n *\n * @example\n * ```ts\n * const counter = createCounterState({ value: tf.value, maxLength: props.maxlength });\n * ```\n */\nexport const createCounterState = (options: CounterOptions): Readable<CounterState> =>\n computed<CounterState>(() => {\n const value = options.value?.value ?? '';\n const maxLength = options.maxLength?.value;\n const parsedMaxLength = Number(maxLength);\n const validMaxLength = Number.isFinite(parsedMaxLength) && parsedMaxLength > 0 ? parsedMaxLength : null;\n const hasCounter = validMaxLength !== null;\n const counterText = hasCounter ? `${value.length} / ${validMaxLength}` : '';\n const ratio = hasCounter ? value.length / validMaxLength : 0;\n\n return {\n counterAtLimit: hasCounter ? ratio >= 1 : false,\n counterNearLimit: hasCounter ? ratio >= 0.9 && ratio < 1 : false,\n counterText,\n };\n });\n\n// ── Label placement ───────────────────────────────────────────────────────────\n\nexport type LabelPlacement = 'inset' | 'outside' | undefined;\n\n// ── Field handle ──────────────────────────────────────────────────────────────\n\n/**\n * Common handle returned by `createField` — the base for both `TextFieldHandle`\n * and `ChoiceFieldHandle`.\n *\n * ARIA signals and label state are flat on the handle — no nested `aria` or\n * `label` sub-objects.\n *\n * @example\n * ```html\n * <label id=\"${labelId}\" ?hidden=\"${() => !labelVisible.value}\">...</label>\n * <input\n * :aria-labelledby=\"${ariaLabelledBy}\"\n * :aria-describedby=\"${ariaDescribedBy}\"\n * :aria-invalid=\"${ariaInvalid}\" />\n * ```\n */\n/** Flat ARIA attribute bag ready to spread into a template bind call. */\nexport type AriaProps = {\n 'aria-describedby': string | null;\n 'aria-errormessage': string | null;\n 'aria-invalid': 'true' | null;\n 'aria-labelledby': string | null;\n};\n\nexport type FieldHandle = {\n /** `aria-describedby` value. Non-null when helper or error text is present. */\n ariaDescribedBy: Readable<string | null>;\n /** `aria-errormessage` value. Non-null when error text is present. */\n ariaErrorMessage: Readable<string | null>;\n /** `aria-invalid` value. `'true'` when error text is present, otherwise `null`. */\n ariaInvalid: Readable<'true' | null>;\n /** `aria-labelledby` value. Non-null when a label is visible. */\n ariaLabelledBy: Readable<string | null>;\n /**\n * Returns a snapshot of the four ARIA attributes as a plain object.\n * Spread into a template bind call to avoid repeating each signal individually.\n *\n * @example\n * ```ts\n * bind(inputEl, { attr: field.ariaProps() });\n * ```\n */\n ariaProps(): AriaProps;\n /**\n * The stable `id` used for `aria-describedby` on the input. Points at the\n * assistive-text region (covers both helper text and error text per WAI-ARIA).\n */\n assistiveId: string;\n disabled: Readable<boolean>;\n /** Stable `id` for the inline error message element (`aria-errormessage`). */\n errorId: string;\n /** Reactive error text. Empty string when no error is set. */\n errorText: Readable<string>;\n fieldId: string;\n /** Reactive helper text. Empty string when no helper is set. */\n helperText: Readable<string>;\n /** Stable `id` for the label element. Stamp this on your `<label id=\"...\">`. */\n labelId: string;\n /** Whether the label should be visible. Use to toggle `hidden` on the `<label>`. */\n labelVisible: Readable<boolean>;\n triggerValidation: (on: Extract<ValidationTrigger, 'blur' | 'change'>) => void;\n};\n\n/**\n * Composes the field triad — IDs, assistive state, and label state — into a\n * single `FieldHandle`. Both `createTextField` and `createChoiceField` build\n * on top of this.\n */\nexport const createField = (options: FieldOptions): FieldHandle => {\n // ── Core ──────────────────────────────────────────────────────────────────\n const disabled = computed(() => Boolean(options.disabled?.value));\n const validateOn = options.validateOn;\n const fieldId = options.id ?? createStableId(options.prefix ?? 'field');\n const assistiveId = createStableId('helper');\n\n const triggerValidation = (on: Extract<ValidationTrigger, 'blur' | 'change'>): void => {\n if (validateOn?.value === on) options.getFormField?.()?.reportValidity();\n };\n\n // ── Label + ARIA state ────────────────────────────────────────────────────\n const labelId = createStableId('label');\n const errorId = createStableId('error');\n\n const label$ = options.label ?? computed(() => undefined);\n\n // Slot-first composition: if the caller provides `hasLabel`, use it instead\n // of deriving visibility purely from the label text signal. This allows\n // components with a `<slot name=\"label\">` to stay visible even when the\n // `label` prop is empty but a slotted label element is present.\n const labelVisible$ = options.hasLabel ?? computed(() => Boolean(label$.value));\n\n const resolvedAssistive = createErrorHelperState({ error: options.error, helper: options.helper });\n\n const ariaDescribedBy = computed(() =>\n resolvedAssistive.value.errorText || resolvedAssistive.value.helperText ? assistiveId : null,\n );\n const ariaErrorMessage = computed(() => (resolvedAssistive.value.errorText ? errorId : null));\n const ariaInvalid = computed<'true' | null>(() => (resolvedAssistive.value.errorText ? 'true' : null));\n const ariaLabelledBy = computed(() => (labelVisible$.value ? labelId : null));\n\n return {\n ariaDescribedBy,\n ariaErrorMessage,\n ariaInvalid,\n ariaLabelledBy,\n ariaProps: () => ({\n 'aria-describedby': ariaDescribedBy.value,\n 'aria-errormessage': ariaErrorMessage.value,\n 'aria-invalid': ariaInvalid.value,\n 'aria-labelledby': ariaLabelledBy.value,\n }),\n assistiveId,\n disabled,\n errorId,\n errorText: computed(() => resolvedAssistive.value.errorText),\n fieldId,\n helperText: computed(() => resolvedAssistive.value.helperText),\n labelId,\n labelVisible: labelVisible$,\n triggerValidation,\n };\n};\n","import { type Readable, signal, type Signal, untrack, watch } from '@vielzeug/ripple';\n\n// ── syncedSignal ──────────────────────────────────────────────────────────────\n\n/**\n * Creates a local writable `Signal<T>` that stays in sync with an external\n * `Reactive<T>`. When `abortSignal` is provided the watcher subscription\n * is disposed automatically on abort; otherwise the caller is responsible for\n * disposal.\n *\n * Initialised synchronously via `untrack` so the first render never reads a\n * stale value. The optional `transform` coerces each incoming value (e.g.\n * `Boolean`, `String`).\n *\n * @example\n * ```ts\n * const value = syncedSignal(options.value, options.signal, (v) => String(v ?? ''));\n * // Without lifecycle signal (test / non-component context):\n * const value = syncedSignal(source);\n * ```\n */\nexport const syncedSignal = <TIn, TOut = TIn>(\n source: Readable<TIn>,\n abortSignal?: AbortSignal,\n transform: (value: TIn) => TOut = (v) => v as unknown as TOut,\n): Signal<TOut> => {\n const local = signal<TOut>(untrack(() => transform(source.value)));\n const sub = watch(source, (v) => {\n local.value = transform(v);\n });\n\n if (abortSignal) {\n abortSignal.addEventListener('abort', () => sub.dispose(), { once: true });\n }\n\n return local;\n};\n","import { type Readable, type Signal } from '@vielzeug/ripple';\n\nimport { type CounterState, createCounterState, createField, type FieldHandle, type FieldOptions } from './field-base';\nimport { syncedSignal } from './signals';\n\n// ── Text field ────────────────────────────────────────────────────────────────\n\n/** Detach function returned by `wire()`. Call to remove element listeners. */\nexport type TextFieldDetach = () => void;\n\nexport type TextFieldOptions = FieldOptions & {\n maxLength?: Readable<number | undefined>;\n /**\n * Called synchronously before value extraction on every input event.\n * Use only for DOM side-effects (e.g. auto-resize measurement) that must\n * run before the reactive value is updated.\n */\n onBeforeInput?: (event: Event) => void;\n onBlur?: (event: FocusEvent) => void;\n onChange?: (event: Event, value: string) => void;\n onFocus?: (event: FocusEvent) => void;\n onInput?: (event: Event, value: string) => void;\n /** `AbortSignal` from the component lifecycle. The internal value-sync watcher is disposed on abort. */\n signal: AbortSignal;\n value: Readable<string | undefined>;\n};\n\nexport type TextFieldHandle = FieldHandle & {\n /** Clears the field value and fires synthetic input/change events. */\n clear: (event?: Event) => void;\n /**\n * Reactive counter state. Non-null when `maxLength` was provided; `null` otherwise.\n * Components should only render a counter element when this is non-null.\n */\n counter: Readable<CounterState> | null;\n /** The local mutable field value (two-way bound to the input element via `wire()`). */\n value: Signal<string>;\n /**\n * Attaches event listeners to the underlying input or textarea element.\n *\n * When `signal` is provided, the listeners are detached automatically when\n * the signal's controller calls `abort()`. Without a signal the returned\n * `TextFieldDetach` must be called manually.\n *\n * Safe to call multiple times — each call attaches a fresh set of listeners\n * and returns a distinct detach function. Calling detach multiple times is\n * a no-op (guarded internally).\n */\n wire: (el: HTMLInputElement | HTMLTextAreaElement, signal?: AbortSignal) => TextFieldDetach;\n};\n\nexport const createTextField = (options: TextFieldOptions): TextFieldHandle => {\n const value = syncedSignal(options.value, options.signal, (v) => String(v ?? ''));\n\n const field = createField(options);\n const counter = options.maxLength ? createCounterState({ maxLength: options.maxLength, value }) : null;\n\n const clear = (event?: Event): void => {\n event?.preventDefault?.();\n value.value = '';\n options.onInput?.(event ?? new InputEvent('input', { bubbles: true }), '');\n options.onChange?.(event ?? new Event('change', { bubbles: true }), '');\n field.triggerValidation('change');\n };\n\n const wire = (element: HTMLInputElement | HTMLTextAreaElement, signal?: AbortSignal): TextFieldDetach => {\n const cleanups: Array<() => void> = [];\n const on = (type: string, handler: EventListener): void => {\n element.addEventListener(type, handler);\n cleanups.push(() => element.removeEventListener(type, handler));\n };\n\n if (options.onFocus) {\n on('focus', (e) => options.onFocus!(e as FocusEvent));\n }\n\n on('input', (e) => {\n e.stopPropagation();\n options.onBeforeInput?.(e);\n value.value = element.value;\n options.onInput?.(e, element.value);\n });\n\n on('change', (e) => {\n e.stopPropagation();\n value.value = element.value;\n options.onChange?.(e, element.value);\n field.triggerValidation('change');\n });\n\n on('blur', (e) => {\n options.onBlur?.(e as FocusEvent);\n field.triggerValidation('blur');\n });\n\n let detached = false;\n const detach = (): void => {\n if (detached) return;\n\n detached = true;\n for (const dispose of cleanups) dispose();\n };\n\n signal?.addEventListener('abort', detach, { once: true });\n\n return detach;\n };\n\n return { ...field, clear, counter, value, wire };\n};\n","import { computed, type Readable, signal, watch } from '@vielzeug/ripple';\n\nimport { createField, type FieldHandle, type FieldOptions } from './field-base';\n\n// ── Choice change event payload ──────────────────────────────────────────────────────────────\n\nexport type ChoiceChangeDetail = {\n labels: string[];\n originalEvent?: Event;\n values: string[];\n};\n\n// ── Choice field ──────────────────────────────────────────────────────────────────────\n\nexport type ChoiceFieldOptions = FieldOptions & {\n multiple?: Readable<boolean | undefined>;\n /** `AbortSignal` from the component lifecycle. All internal subscriptions are disposed on abort. */\n signal: AbortSignal;\n /**\n * Current selection value(s). Accepts a comma-separated string\n * (legacy/single-select form serialisation) or a `string[]` array.\n * The field normalises both formats internally via `parseChoiceValues`.\n */\n value: Readable<string | string[] | undefined>;\n};\n\nexport type ChoiceFieldHandle = FieldHandle & {\n clear: () => void;\n formValue: Readable<string>;\n removeValue: (value: string) => void;\n selectedValue: Readable<string | undefined>;\n selectedValues: Readable<string[]>;\n selectValue: (value: string) => void;\n setValues: (values: string[]) => void;\n /**\n * Toggles `value` in the selection.\n * - **Multiple mode**: adds if absent, removes if present.\n * - **Single mode**: always selects `value` (acts like `selectValue` — cannot\n * deselect; use `clear()` to reset a single-select field).\n */\n toggleValue: (value: string) => void;\n};\n\nconst parseChoiceValues = (raw: string | string[] | undefined): string[] => {\n if (!raw) return [];\n\n if (Array.isArray(raw)) return raw.filter(Boolean);\n\n return raw\n .split(',')\n .map((entry) => entry.trim())\n .filter(Boolean);\n};\n\nexport const createChoiceField = (options: ChoiceFieldOptions): ChoiceFieldHandle => {\n const selectedValues = signal<string[]>([]);\n const isMultiple = computed(() => Boolean(options.multiple?.value));\n const formValue = computed(() =>\n isMultiple.value ? selectedValues.value.join(',') : (selectedValues.value[0] ?? ''),\n );\n\n const normalizeValues = (values: string[]): string[] => {\n const normalized = isMultiple.value ? values : values.slice(0, 1);\n\n return [...new Set(normalized.filter(Boolean))];\n };\n\n const setValues = (values: string[]): void => {\n selectedValues.value = normalizeValues(values);\n };\n const clear = (): void => setValues([]);\n const removeValue = (value: string): void => {\n selectedValues.value = selectedValues.value.filter((v) => v !== value);\n };\n\n const selectValue = (value: string): void => {\n if (isMultiple.value) {\n if (!selectedValues.value.includes(value)) setValues([...selectedValues.value, value]);\n\n return;\n }\n\n setValues([value]);\n };\n\n const toggleValue = (value: string): void => {\n if (isMultiple.value) {\n if (selectedValues.value.includes(value)) removeValue(value);\n else selectValue(value);\n } else {\n selectValue(value);\n }\n };\n\n const syncFromProp = (nextValue: string | string[] | undefined): void => {\n setValues(parseChoiceValues(nextValue));\n };\n\n const field = createField(options);\n\n const valueSub = watch(options.value, syncFromProp, { immediate: true });\n\n options.signal.addEventListener('abort', () => valueSub.dispose(), { once: true });\n\n if (options.multiple) {\n const multipleSub = watch(options.multiple, () => syncFromProp(options.value.value));\n\n options.signal.addEventListener('abort', () => multipleSub.dispose(), { once: true });\n }\n\n return {\n ...field,\n clear,\n formValue,\n removeValue,\n selectedValue: computed(() => selectedValues.value[0]),\n selectedValues,\n selectValue,\n setValues,\n toggleValue,\n };\n};\n","import type { Readable } from '@vielzeug/ripple';\n\n// ── Keyboard dispatch ─────────────────────────────────────────────────────────\n\nexport type KeyboardDispatchOptions = {\n disabled?: Readable<boolean | undefined>;\n keymap: Record<string, (event: KeyboardEvent) => boolean | void>;\n preventDefault?: 'after' | 'before' | false;\n};\n\nexport const dispatchKeyboardAction = (event: KeyboardEvent, options: KeyboardDispatchOptions): boolean => {\n if (options.disabled?.value) return false;\n\n // `event.key` is attacker-influenceable on a synthetic KeyboardEvent (e.g. `new\n // KeyboardEvent('keydown', { key: '__proto__' })`). Guard with `Object.hasOwn` so a\n // crafted key name can never resolve to an inherited `Object.prototype` member\n // (`__proto__`, `constructor`, `toString`, …) instead of `undefined`.\n const action = Object.hasOwn(options.keymap, event.key) ? options.keymap[event.key] : undefined;\n\n if (!action) return false;\n\n const preventDefaultMode = options.preventDefault ?? 'before';\n\n if (preventDefaultMode === 'before') event.preventDefault();\n\n const handled = action(event) !== false;\n\n if (preventDefaultMode === 'after' && handled) event.preventDefault();\n\n return handled;\n};\n\n// ── Press control / Interaction ───────────────────────────────────────────────\n\nexport type PressTrigger = 'keyboard' | 'pointer';\n\n/**\n * Options for `createInteraction` — a unified press + focus/blur interaction\n * handler for accessible interactive elements.\n */\nexport type InteractionOptions = {\n /** `true` when the element is disabled. All handlers become no-ops. */\n disabled?: Readable<boolean | undefined>;\n /** Keys that trigger a press. Defaults to `['Enter', ' ']`. */\n keys?: string[];\n /** Called when the element loses focus. */\n onBlur?: (event: FocusEvent) => void;\n /** Called when the element receives focus. */\n onFocus?: (event: FocusEvent) => void;\n /** Called when the element is pressed via keyboard or pointer. */\n onPress?: (event: KeyboardEvent | MouseEvent, trigger: PressTrigger) => void;\n};\n\nexport type Interaction = {\n handleBlur: (event: FocusEvent) => void;\n handleClick: (event: MouseEvent) => boolean;\n handleFocus: (event: FocusEvent) => void;\n handleKeydown: (event: KeyboardEvent) => boolean;\n};\n\n/**\n * Creates a set of event handlers for an interactive element that responds to\n * keyboard and pointer presses, and optionally focus/blur events.\n *\n * @example\n * ```ts\n * const interaction = createInteraction({\n * disabled: props.disabled,\n * onPress: (event, trigger) => toggle(event),\n * onFocus: (event) => setFocused(true),\n * onBlur: (event) => setFocused(false),\n * });\n *\n * // In template:\n * // @click=\"${interaction.handleClick}\"\n * // @keydown=\"${interaction.handleKeydown}\"\n * // @focus=\"${interaction.handleFocus}\"\n * // @blur=\"${interaction.handleBlur}\"\n * ```\n */\nexport const createInteraction = (options: InteractionOptions): Interaction => {\n const isDisabled = (): boolean => Boolean(options.disabled?.value);\n const keyboardKeys = options.keys ?? ['Enter', ' '];\n const keymap = Object.fromEntries(\n keyboardKeys.map((key) => [key, (keyboardEvent: KeyboardEvent) => options.onPress?.(keyboardEvent, 'keyboard')]),\n );\n\n return {\n handleBlur: (event: FocusEvent): void => {\n if (!isDisabled()) options.onBlur?.(event);\n },\n handleClick: (event: MouseEvent): boolean => {\n if (isDisabled()) return false;\n\n options.onPress?.(event, 'pointer');\n\n return true;\n },\n handleFocus: (event: FocusEvent): void => {\n if (!isDisabled()) options.onFocus?.(event);\n },\n handleKeydown: (event: KeyboardEvent): boolean =>\n dispatchKeyboardAction(event, { disabled: options.disabled, keymap }),\n };\n};\n","import { computed, type Readable, type Signal, signal } from '@vielzeug/ripple';\n\nimport { createField, type ControlValidationMode, type FieldHandle } from './field-base';\nimport { createInteraction } from './keyboard';\nimport { syncedSignal } from './signals';\n\n// ── Checkable control ─────────────────────────────────────────────────────────\n\nexport type CheckableChangePayload = {\n checked: boolean;\n originalEvent?: Event;\n value: string;\n};\n\nexport type CheckableOptions = {\n checked: Readable<boolean | undefined>;\n clearIndeterminateFirst?: boolean;\n disabled?: Readable<boolean | undefined>;\n error?: Readable<string | undefined>;\n /**\n * Returns the underlying form field object used for validation triggering.\n * Called lazily — safe to return `null` before the first render.\n */\n getFormField?: () => { reportValidity(): void } | null;\n group?: { toggle: (value: string, originalEvent?: Event) => void };\n helper?: Readable<string | undefined>;\n indeterminate?: Readable<boolean | undefined>;\n onToggle?: (payload: CheckableChangePayload) => void;\n prefix?: string;\n /** `AbortSignal` from the component lifecycle. All reactive subscriptions are torn down on abort. */\n signal: AbortSignal;\n validateOn?: Readable<ControlValidationMode>;\n value: Readable<string | undefined>;\n};\n\nexport type CheckableHandle = FieldHandle & {\n /** The form submission value: null when unchecked/indeterminate, the value string when checked. */\n checkableFormValue: Readable<string | null>;\n checked: Signal<boolean>;\n handleClick: (event: MouseEvent) => boolean;\n handleKeydown: (event: KeyboardEvent) => boolean;\n indeterminate: Signal<boolean>;\n toggle: (event: Event) => void;\n};\n\nexport const createCheckable = (options: CheckableOptions): CheckableHandle => {\n const checked = syncedSignal(options.checked, options.signal, Boolean);\n const indeterminate = options.indeterminate\n ? syncedSignal(options.indeterminate, options.signal, Boolean)\n : signal(false);\n\n const checkableFormValue = computed<string | null>(() =>\n indeterminate.value ? null : checked.value ? (options.value.value ?? '') : null,\n );\n\n const field = createField(options);\n\n const createPayload = (event: Event): CheckableChangePayload => ({\n checked: checked.value,\n originalEvent: event,\n value: options.value.value ?? '',\n });\n\n const toggle = (event: Event): void => {\n if (field.disabled.value) return;\n\n if (options.group) {\n indeterminate.value = false;\n options.group.toggle(options.value.value ?? '', event);\n options.onToggle?.(createPayload(event));\n\n return;\n }\n\n if (options.clearIndeterminateFirst && indeterminate.value) {\n indeterminate.value = false;\n } else {\n checked.value = !checked.value;\n indeterminate.value = false;\n }\n\n options.onToggle?.(createPayload(event));\n };\n\n const interaction = createInteraction({\n disabled: field.disabled,\n onPress: (event) => toggle(event),\n });\n\n return {\n ...field,\n checkableFormValue,\n checked,\n handleClick: interaction.handleClick,\n handleKeydown: interaction.handleKeydown,\n indeterminate,\n toggle,\n };\n};\n","/** Base class for all refine errors. Use `instanceof RefineError` to catch any refine-originated error. */\nexport class RefineError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is RefineError {\n return err instanceof RefineError;\n }\n}\n\n/** Thrown when a refine component receives an invalid or unsupported configuration. */\nexport class RefineConfigError extends RefineError {}\n","// ── Typeahead ─────────────────────────────────────────────────────────────────\n// Standalone typeahead primitive: accumulates printable keystrokes, then finds\n// the first enabled item whose label starts with the buffer.\n//\n// Extracted from nav.ts so it can be reused independently (e.g. combobox input).\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport type TypeaheadOptions<T> = {\n /**\n * Milliseconds of inactivity before the buffer resets.\n * ARIA APG recommended window. Default: `500`.\n */\n delay?: number;\n /** Returns the current focused index (used to search forward from current + 1). */\n getIndex: () => number;\n /** Returns a plain-text label for the item at `index`. */\n getItemLabel: (item: T, index: number) => string;\n /** Returns all items in the current list. */\n getItems: () => T[];\n /** Returns `true` for items that should be skipped during typeahead search. */\n isItemDisabled?: (item: T, index: number) => boolean;\n /** Called when typeahead navigation lands on an item. */\n onNavigate: (index: number, event: KeyboardEvent) => void;\n /**\n * When provided, the pending reset timer is cancelled automatically when the\n * signal aborts (e.g. when the owning component disconnects).\n */\n signal?: AbortSignal;\n};\n\nexport type Typeahead = {\n /**\n * Process a keyboard event. Returns `true` if the event was consumed by\n * typeahead (a printable character matched or was buffered).\n */\n handleKeydown(event: KeyboardEvent): boolean;\n /** Reset the buffer immediately. Call on list close to clear stale input. */\n reset(): void;\n};\n\n// ── Implementation ────────────────────────────────────────────────────────────\n\n/**\n * Creates a standalone typeahead handler for keyboard-navigable lists.\n *\n * Accumulates printable keystrokes into a buffer; on each keystroke searches\n * for the first enabled item whose label starts with the buffer. Cycles past\n * the current item on repeated same-character presses. Buffer resets after\n * `delay` ms of inactivity (default 500 — the ARIA APG recommended window).\n *\n * @example\n * ```ts\n * const typeahead = createTypeahead({\n * getIndex: () => focusedIndex,\n * getItemLabel: (item) => item.label,\n * getItems: () => items,\n * onNavigate: (index) => { focusedIndex = index; },\n * });\n *\n * listEl.addEventListener('keydown', (e) => typeahead.handleKeydown(e));\n * ```\n */\nexport const createTypeahead = <T>(options: TypeaheadOptions<T>): Typeahead => {\n const delay = options.delay ?? 500;\n let _buffer = '';\n let _timer: ReturnType<typeof setTimeout> | null = null;\n\n const reset = (): void => {\n _buffer = '';\n\n if (_timer !== null) {\n clearTimeout(_timer);\n _timer = null;\n }\n };\n\n options.signal?.addEventListener('abort', reset, { once: true });\n\n const handleKeydown = (event: KeyboardEvent): boolean => {\n // Single printable character only; exclude modifier combos.\n if (event.key.length !== 1 || event.ctrlKey || event.altKey || event.metaKey) return false;\n\n _buffer += event.key.toLowerCase();\n\n if (_timer !== null) clearTimeout(_timer);\n\n _timer = setTimeout(reset, delay);\n\n const items = options.getItems();\n const current = options.getIndex();\n const startAfter = current >= 0 ? current + 1 : 0;\n\n for (let n = 0; n < items.length; n++) {\n const i = (startAfter + n) % items.length;\n\n if (options.isItemDisabled?.(items[i], i)) continue;\n\n if (options.getItemLabel(items[i], i).toLowerCase().startsWith(_buffer)) {\n options.onNavigate(i, event);\n\n return true;\n }\n }\n\n return false;\n };\n\n return { handleKeydown, reset };\n};\n","import { type Readable, signal } from '@vielzeug/ripple';\n\nimport { dispatchKeyboardAction } from './keyboard';\nimport { createTypeahead } from './typeahead';\n\n// ── Private array search helpers ────────────────────────────────────────────\nconst findForward = <T>(items: T[], start: number, predicate: (item: T, index: number) => boolean): number => {\n for (let idx = start; idx < items.length; idx++) {\n if (predicate(items[idx], idx)) return idx;\n }\n\n return -1;\n};\n\nconst findBackward = <T>(items: T[], start: number, predicate: (item: T, index: number) => boolean): number => {\n for (let idx = start; idx >= 0; idx--) {\n if (predicate(items[idx], idx)) return idx;\n }\n\n return -1;\n};\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\n/**\n * Arrow-key and Home/End navigation actions. Separate from `ListKeyAction` so\n * keymap declarations never need `Exclude<ListKeyAction, 'typeahead'>`.\n */\nexport type ListNavigationAction = 'first' | 'last' | 'next' | 'prev';\n\n/**\n * All possible navigation action names, including `'typeahead'` (character-key\n * search). Used in `onNavigate` callbacks where both nav and typeahead are valid.\n */\nexport type ListKeyAction = ListNavigationAction | 'typeahead';\n\n/**\n * Orientation-aware default key bindings for list navigation.\n * - `'vertical'` (default): Up/Down arrows, Home/End\n * - `'horizontal'`: Left/Right arrows, Home/End\n * - `'both'`: all four arrow keys + Home/End\n */\nconst DEFAULT_KEYS: Record<'both' | 'horizontal' | 'vertical', Record<ListNavigationAction, string[]>> = {\n both: { first: ['Home'], last: ['End'], next: ['ArrowDown', 'ArrowRight'], prev: ['ArrowUp', 'ArrowLeft'] },\n horizontal: { first: ['Home'], last: ['End'], next: ['ArrowRight'], prev: ['ArrowLeft'] },\n vertical: { first: ['Home'], last: ['End'], next: ['ArrowDown'], prev: ['ArrowUp'] },\n};\n\nexport type ListNavigationOptions<T> = {\n disabled?: Readable<boolean | undefined>;\n /**\n * Returns a plain-text label for an item used by typeahead search.\n * When provided, pressing a printable character key jumps to the first enabled\n * item whose label starts with the accumulated type buffer (500 ms reset window).\n * Omit for contexts where the host element is a text input (e.g. combobox).\n */\n getItemLabel?: (item: T, index: number) => string;\n getItems: () => T[];\n isItemDisabled?: (item: T, index: number) => boolean;\n /** Override default key bindings for navigation actions. */\n keys?: Partial<Record<ListNavigationAction, string[]>>;\n loop?: boolean;\n /**\n * Called when navigation lands on a new index.\n * `event` is the originating `KeyboardEvent`, or `undefined` for programmatic navigation.\n * Use to sync side-effects such as focusing a DOM element.\n */\n onNavigate?: (action: ListKeyAction, index: number, event?: KeyboardEvent) => void;\n /**\n * Axis the list navigates along. Controls which arrow keys are treated as\n * `next`/`prev` when no explicit `keys` override is provided.\n * Pass a getter function for dynamic/reactive orientation (e.g. driven by a prop signal).\n *\n * - `'vertical'` (default): ↑↓ arrows\n * - `'horizontal'`: ←→ arrows\n * - `'both'`: all four arrow keys\n */\n orientation?: 'both' | 'horizontal' | 'vertical' | (() => 'both' | 'horizontal' | 'vertical');\n /** `AbortSignal` from the component lifecycle. Disposes typeahead timer on abort. */\n signal?: AbortSignal;\n};\n\nexport type ListControl<T> = {\n [Symbol.dispose](): void;\n /** Current focused index. `-1` when nothing is focused. */\n readonly focusedIndex: Readable<number>;\n getActiveItem(): T | undefined;\n handleKeydown(event: KeyboardEvent): boolean;\n /**\n * Programmatically navigate to a named position.\n * Always fires `onNavigate` — consistent with keyboard navigation.\n * Returns the resolved index, or `-1` if no enabled item was found.\n */\n navigate(action: ListNavigationAction): number;\n /** Reset focused index to `-1`. */\n reset(): void;\n /**\n * Set focus to the item at `index`. Returns the resolved index.\n * Pass a negative index to clear focus (same as `reset()`).\n */\n set(index: number): number;\n};\n\nconst hasDisabledProp = (item: unknown): item is { disabled: boolean } =>\n typeof item === 'object' && item !== null && 'disabled' in item;\n\nexport const createListControl = <T>(options: ListNavigationOptions<T>): ListControl<T> => {\n const _index = signal(-1);\n\n const isItemDisabled = (item: T, index: number): boolean =>\n options.isItemDisabled?.(item, index) ?? (hasDisabledProp(item) ? item.disabled : false);\n\n const commitIndex = (idx: number, action: ListKeyAction, event?: KeyboardEvent): number => {\n if (idx >= 0) {\n _index.value = idx;\n options.onNavigate?.(action, idx, event);\n }\n\n return idx;\n };\n\n const findEnabledIndex = (items: T[], start: number, direction: 'forward' | 'backward'): number => {\n if (direction === 'forward') return findForward(items, start, (item, i) => !isItemDisabled(item, i));\n\n return findBackward(items, start, (item, i) => !isItemDisabled(item, i));\n };\n\n const set = (index: number): number => {\n if (index < 0) {\n reset();\n\n return -1;\n }\n\n const items = options.getItems();\n\n if (!items.length) return -1;\n\n const clamped = Math.min(index, items.length - 1);\n\n if (isItemDisabled(items[clamped], clamped)) return -1;\n\n _index.value = clamped;\n\n return clamped;\n };\n\n const move = (direction: 'forward' | 'backward', event?: KeyboardEvent): number => {\n const items = options.getItems();\n const current = _index.value;\n\n if (!items.length) return -1;\n\n const start: number =\n current < 0\n ? direction === 'forward'\n ? 0\n : items.length - 1\n : direction === 'forward'\n ? current + 1\n : current - 1;\n const idx = findEnabledIndex(items, start, direction);\n const action: ListNavigationAction = direction === 'forward' ? 'next' : 'prev';\n\n if (idx >= 0) return commitIndex(idx, action, event);\n\n if (options.loop) {\n const wrapStart = direction === 'forward' ? 0 : items.length - 1;\n const wrapped = findEnabledIndex(items, wrapStart, direction);\n\n if (wrapped >= 0) return commitIndex(wrapped, action, event);\n }\n\n return current;\n };\n\n const navigate = (action: ListNavigationAction): number => {\n const items = options.getItems();\n\n if (!items.length) return -1;\n\n if (action === 'first') {\n const idx = findEnabledIndex(items, 0, 'forward');\n\n return commitIndex(idx, 'first');\n }\n\n if (action === 'last') {\n const idx = findEnabledIndex(items, items.length - 1, 'backward');\n\n return commitIndex(idx, 'last');\n }\n\n return move(action === 'next' ? 'forward' : 'backward');\n };\n\n const getActiveItem = (): T | undefined => {\n const items = options.getItems();\n const index = _index.value;\n\n return index >= 0 && index < items.length ? items[index] : undefined;\n };\n\n const reset = (): void => {\n _index.value = -1;\n };\n\n // ── Keyboard handling ──────────────────────────────────────────────────────\n\n const isKeyDisabled = (): boolean => Boolean(options.disabled?.value);\n\n const resolveOrientation = (): 'both' | 'horizontal' | 'vertical' =>\n typeof options.orientation === 'function' ? options.orientation() : (options.orientation ?? 'vertical');\n\n const buildKeymap = (): Record<string, (keyboardEvent: KeyboardEvent) => void> => {\n const keys = options.keys;\n const orientationDefaults = DEFAULT_KEYS[resolveOrientation()];\n const resolved = {\n first: keys?.first ?? orientationDefaults.first,\n last: keys?.last ?? orientationDefaults.last,\n next: keys?.next ?? orientationDefaults.next,\n prev: keys?.prev ?? orientationDefaults.prev,\n };\n const km: Record<string, (keyboardEvent: KeyboardEvent) => void> = {};\n\n for (const action of ['next', 'prev', 'first', 'last'] as const) {\n for (const key of resolved[action]) {\n km[key] = (keyboardEvent: KeyboardEvent) => {\n if (action === 'first' || action === 'last') {\n const items = options.getItems();\n\n if (!items.length) return;\n\n const idx =\n action === 'first'\n ? findEnabledIndex(items, 0, 'forward')\n : findEnabledIndex(items, items.length - 1, 'backward');\n\n commitIndex(idx, action, keyboardEvent);\n } else {\n move(action === 'next' ? 'forward' : 'backward', keyboardEvent);\n }\n };\n }\n }\n\n return km;\n };\n\n // ── Typeahead ──────────────────────────────────────────────────────────────\n\n const typeahead = options.getItemLabel\n ? createTypeahead({\n getIndex: () => _index.value,\n getItemLabel: options.getItemLabel,\n getItems: options.getItems,\n isItemDisabled: (item, index) => isItemDisabled(item, index),\n onNavigate: (index, event) => {\n if (!isKeyDisabled()) {\n _index.value = index;\n options.onNavigate?.('typeahead', index, event);\n }\n },\n })\n : null;\n\n const _staticKeymap: Record<string, (e: KeyboardEvent) => void> | null =\n typeof options.orientation === 'function' ? null : buildKeymap();\n\n const handleKeydown = (event: KeyboardEvent): boolean => {\n const km = _staticKeymap ?? buildKeymap();\n\n if (dispatchKeyboardAction(event, { disabled: options.disabled, keymap: km })) return true;\n\n return typeahead?.handleKeydown(event) ?? false;\n };\n\n const dispose = (): void => {\n typeahead?.reset();\n };\n\n if (options.signal) {\n options.signal.addEventListener('abort', dispose, { once: true });\n }\n\n return {\n focusedIndex: _index,\n getActiveItem,\n handleKeydown,\n navigate,\n reset,\n set,\n [Symbol.dispose]: dispose,\n };\n};\n","import type { OverlayPositioner } from './positioner';\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\n/**\n * Why an overlay was opened.\n * - `'click'` — user clicked the trigger element\n * - `'focus'` — focus entered the trigger (tooltip, popover)\n * - `'hover'` — pointer entered the trigger (tooltip)\n * - `'keyboard'` — keyboard shortcut or Enter/Space on a trigger\n * - `'programmatic'` — opened via the JS API without a user gesture\n * - `'trigger'` — opened via the Invoker Commands API (`command=\"show-modal\"`)\n */\nexport type OverlayOpenReason = 'click' | 'focus' | 'hover' | 'keyboard' | 'programmatic' | 'trigger';\n\n/** Close reasons valid for modal dialogs (includes 'swipe' for drawer). */\nexport type DialogCloseReason = 'escape' | 'outsideClick' | 'programmatic' | 'swipe' | 'trigger';\n/** Close reasons valid for dropdown overlays (no swipe). */\nexport type DropdownCloseReason = Exclude<DialogCloseReason, 'swipe'>;\n\n/** Detail shape for overlay open events emitted by components. */\nexport type OverlayOpenDetail = { reason: OverlayOpenReason };\n/** Detail shape for overlay close events emitted by components. */\nexport type OverlayCloseDetail = { reason: DialogCloseReason };\n\nexport type { OverlayPositioner };\n\nexport type OverlayControlOptions = {\n getBoundary: () => HTMLElement | null;\n getPanel?: () => HTMLElement | null;\n getTrigger?: () => HTMLElement | null;\n isDisabled?: () => boolean;\n isOpen: () => boolean;\n onClose?: (reason: DialogCloseReason) => void;\n onOpen?: (reason: OverlayOpenReason) => void;\n positioner?: OverlayPositioner;\n restoreFocus?: boolean | (() => boolean);\n setOpen: (next: boolean, reason: OverlayOpenReason | DialogCloseReason) => void;\n /** `AbortSignal` from the component lifecycle. `dispose()` is called automatically on abort. */\n signal: AbortSignal;\n};\n\nexport type OverlayControl = {\n [Symbol.dispose](): void;\n /**\n * Closes the overlay.\n * @param reason — why it's closing (default `'programmatic'`)\n * @param restoreFocus — override per-call focus restoration (default: uses `restoreFocus` option)\n */\n close(reason?: DialogCloseReason, restoreFocus?: boolean): void;\n /** Tears down the overlay: closes silently and removes all event listeners. */\n dispose(): void;\n /**\n * Opens the overlay.\n * @param reason — why it's opening (default `'programmatic'`)\n */\n open(reason?: OverlayOpenReason): void;\n /**\n * Toggles open state.\n * - Opens with `openReason` (default `'click'`).\n * - Closes with `closeReason` (default `'trigger'`).\n */\n toggle(openReason?: OverlayOpenReason, closeReason?: DialogCloseReason): void;\n};\n\n// ── Factory ───────────────────────────────────────────────────────────────────\nexport const createOverlayControl = (options: OverlayControlOptions): OverlayControl => {\n let positionerCleanup: (() => void) | null = null;\n\n const shouldRestoreFocus = (): boolean => {\n if (typeof options.restoreFocus === 'function') return options.restoreFocus();\n\n return options.restoreFocus ?? true;\n };\n\n // Per-instance outside-pointer listener registered directly on document.\n // Uses 'pointerdown' instead of 'click' so that tapping empty/non-interactive\n // areas on iOS Safari (which does not synthesize 'click' for those targets)\n // still dismisses the overlay.\n // No shared multiplexer needed — max ~3 overlays can be open concurrently.\n const clickListener = (event: Event): void => {\n if (!options.isOpen()) return;\n\n const path = (event as Event & { composedPath?: () => EventTarget[] }).composedPath?.() ?? [];\n const boundary = options.getBoundary();\n const panel = options.getPanel?.() ?? null;\n const target = (path[0] ?? event.target) as EventTarget | null;\n const nodeTarget = target instanceof Node ? target : null;\n const insideByPath = path.some((entry) => entry === boundary || entry === panel);\n const insideByContainment = nodeTarget\n ? (boundary?.contains(nodeTarget) ?? false) || (panel?.contains(nodeTarget) ?? false)\n : false;\n\n if (!insideByPath && !insideByContainment) close('outsideClick');\n };\n\n const registerClickListener = (active: boolean): void => {\n if (active) {\n document.addEventListener('pointerdown', clickListener, { capture: true });\n } else {\n document.removeEventListener('pointerdown', clickListener, { capture: true });\n }\n };\n\n const open = (reason: OverlayOpenReason = 'programmatic'): void => {\n if (options.isDisabled?.() || options.isOpen()) return;\n\n options.setOpen(true, reason);\n registerClickListener(true);\n\n if (options.positioner) {\n options.positioner.update();\n positionerCleanup = options.positioner.startAutoUpdate?.() ?? null;\n }\n\n options.onOpen?.(reason);\n };\n\n const close = (reason: DialogCloseReason = 'programmatic', restoreFocus?: boolean, silent = false): void => {\n if (!options.isOpen()) return;\n\n options.setOpen(false, reason);\n registerClickListener(false);\n\n if (positionerCleanup) {\n positionerCleanup();\n positionerCleanup = null;\n }\n\n const restore = restoreFocus ?? shouldRestoreFocus();\n\n if (restore) options.getTrigger?.()?.focus();\n\n if (!silent) options.onClose?.(reason);\n };\n\n const toggle = (openReason: OverlayOpenReason = 'click', closeReason: DialogCloseReason = 'trigger'): void => {\n if (options.isOpen()) {\n close(closeReason);\n } else {\n open(openReason);\n }\n };\n\n const dispose = (): void => {\n // Close silently — teardown should not fire onClose callbacks.\n if (options.isOpen()) close('programmatic', false, true);\n\n registerClickListener(false);\n\n if (positionerCleanup) {\n positionerCleanup();\n positionerCleanup = null;\n }\n };\n\n options.signal.addEventListener('abort', dispose, { once: true });\n\n return { close, dispose, open, [Symbol.dispose]: dispose, toggle };\n};\n","/**\n * Resolves the effective text direction for an element.\n *\n * The closest ancestor with an explicit `dir=\"ltr\"` or `dir=\"rtl\"` attribute wins — this\n * supports locally-scoped RTL sections (e.g. a single `dir=\"rtl\"` panel inside an otherwise\n * LTR page). When no explicit `dir` attribute is found up the tree, falls back to the\n * computed `direction` CSS property (e.g. set via a `direction: rtl` style rule with no\n * `dir` attribute). Defaults to `'ltr'` when `el` is `null`.\n */\nexport function elementDirection(el: Element | null): 'ltr' | 'rtl' {\n let node: Element | null = el;\n\n while (node) {\n const dir = node.getAttribute('dir');\n\n if (dir === 'rtl' || dir === 'ltr') return dir;\n\n node = node.parentElement;\n }\n\n return el !== null && getComputedStyle(el).direction === 'rtl' ? 'rtl' : 'ltr';\n}\n","import { autoUpdate, computePosition, flip, offset, type Placement, shift, size } from '@vielzeug/orbit';\n\nimport { elementDirection } from './direction';\n\n// ── Overlay positioner contract ──────────────────────────────────────────────\n\nexport type OverlayPositioner = {\n floating: () => HTMLElement | null;\n reference: () => HTMLElement | null;\n /** Start continuous position auto-updates. Returns a stop function. */\n startAutoUpdate?: () => () => void;\n update: () => void;\n};\n\n// ── Dropdown positioner ───────────────────────────────────────────────────────\n\nexport type DropdownPositionerOptions = {\n /**\n * Returns the text direction used for placement mirroring. Defaults to the resolved\n * direction of the reference element (nearest `dir=\"ltr\"|\"rtl\"` ancestor, falling back to\n * computed style) — most callers never need to pass this explicitly.\n */\n getDir?: () => 'ltr' | 'rtl';\n /** Getter for the floating (dropdown panel) element. */\n getFloating: () => HTMLElement | null;\n /** Getter for the current placement. Defaults to 'bottom-start' (RTL-aware: flips to 'bottom-end'). */\n getPlacement?: () => Placement;\n /** Getter for the reference (trigger) element. */\n getReference: () => HTMLElement | null;\n /** Whether to match the floating element width to the reference. Default: true */\n matchWidth?: boolean;\n /** Additional offset in pixels between reference and floating element. Default: 0 */\n offsetPx?: number;\n /** Padding (px) used by flip, shift, and size middleware. Default: 6 */\n padding?: number;\n};\n\n/** Mirrors a start/end placement for RTL layouts. */\nconst rtlPlacement = (p: Placement): Placement => {\n if (p.endsWith('-start')) return p.replace('-start', '-end') as Placement;\n\n if (p.endsWith('-end')) return p.replace('-end', '-start') as Placement;\n\n return p;\n};\n\n/**\n * Creates an Orbit-powered positioner for dropdown overlays (select, combobox, menu).\n *\n * Uses flip + shift + optional width-matching middleware. Supports continuous\n * auto-update for repositioning on scroll or resize.\n *\n * RTL-aware: start/end placements are automatically mirrored so dropdowns open on the\n * correct side, based on `getDir` (or the reference element's resolved direction when\n * `getDir` is omitted).\n */\nexport function createDropdownPositioner({\n getDir,\n getFloating,\n getPlacement,\n getReference,\n matchWidth = true,\n offsetPx = 0,\n padding = 6,\n}: DropdownPositionerOptions): OverlayPositioner {\n function resolvedPlacement(): Placement {\n const base = getPlacement?.() ?? 'bottom-start';\n const dir = getDir?.() ?? elementDirection(getReference());\n\n return dir === 'rtl' ? rtlPlacement(base) : base;\n }\n\n function updatePosition(): void {\n const ref = getReference();\n const floating = getFloating();\n\n if (!ref || !floating) return;\n\n const placement = resolvedPlacement();\n\n const result = computePosition(ref, floating, {\n middleware: [\n ...(offsetPx ? [offset(offsetPx)] : []),\n flip({ padding }),\n shift({ padding }),\n ...(matchWidth ? [size({ padding })] : []),\n ],\n placement,\n });\n\n floating.style.left = `${result.x}px`;\n floating.style.top = `${result.y}px`;\n\n if (matchWidth) {\n floating.style.width = `${ref.getBoundingClientRect().width}px`;\n }\n }\n\n function startAutoUpdate(): () => void {\n const ref = getReference();\n const floating = getFloating();\n\n if (!ref || !floating) return () => {};\n\n return autoUpdate(ref, floating, updatePosition);\n }\n\n return { floating: getFloating, reference: getReference, startAutoUpdate, update: updatePosition };\n}\n","import { computed, type Readable, signal } from '@vielzeug/ripple';\n\nimport { RefineConfigError } from '../errors';\nimport { createListControl, type ListKeyAction, type ListNavigationAction } from './nav';\nimport { createOverlayControl, type DialogCloseReason, type OverlayOpenReason } from './overlay';\nimport { createDropdownPositioner, type DropdownPositionerOptions } from './positioner';\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport type BaseOptionItem = object;\n\n/** Placement-only options for the dropdown positioner (getFloating/getReference are injected from the option-list). */\nexport type PlacementOptions = Omit<DropdownPositionerOptions, 'getFloating' | 'getReference'>;\n\nexport type OptionListOptions<T extends BaseOptionItem> = {\n /** Returns the element used as the outside-click boundary. */\n getBoundary: () => HTMLElement | null;\n /**\n * Returns the currently focused option element for scroll-into-view.\n * When omitted, `scrollFocusedIntoView()` is a no-op.\n */\n getFocusedOptionElement?: () => HTMLElement | null;\n /**\n * Returns a plain-text label for the item at `index`.\n * When provided, the list control supports typeahead.\n */\n getItemLabel?: (item: T, index: number) => string;\n /** Returns the current list items. */\n getItems: () => T[];\n /**\n * Derives a stable `id` for the option at `index`.\n * When provided, `aria-activedescendant` is reactively set on the trigger element\n * to reflect the currently focused option (WAI-ARIA listbox / combobox pattern).\n */\n getOptionId?: (index: number) => string;\n /** Returns the floating panel element. */\n getPanel: () => HTMLElement | null;\n /** Returns the reference (trigger anchor) element for positioning. */\n getReference: () => HTMLElement | null;\n /** Returns the trigger element. Focus is restored here on close. */\n getTrigger?: () => HTMLElement | null;\n /** Returns `true` when all interactions should be suppressed (e.g. the host is disabled). */\n isDisabled?: () => boolean;\n isItemDisabled?: (item: T, index: number) => boolean;\n /** Override default keyboard bindings for navigation actions. */\n keys?: Partial<Record<ListNavigationAction, string[]>>;\n /** Whether list navigation wraps around at the first/last item. Default: `true`. */\n loop?: boolean;\n /** Called when the list closes. */\n onClose?: (reason: DialogCloseReason) => void;\n /**\n * Called when keyboard navigation lands on an item.\n * `event` is the originating `KeyboardEvent`, or `undefined` for programmatic navigation.\n */\n onNavigate?: (action: ListKeyAction, index: number, event?: KeyboardEvent) => void;\n /** Called when the list opens. */\n onOpen?: (reason: OverlayOpenReason) => void;\n /**\n * Restricts keyboard navigation direction for the option list.\n * Defaults to `'vertical'` when omitted (up/down arrow keys).\n */\n orientation?: 'both' | 'horizontal' | 'vertical';\n /** Placement and sizing options for the floating dropdown. */\n positioning?: PlacementOptions;\n /** Whether focus is restored to the trigger on close. Default: inferred from `restoreFocus`. */\n restoreFocus?: boolean | (() => boolean);\n /** `AbortSignal` from the component lifecycle. Disposes subscriptions and removes event listeners on abort. */\n signal: AbortSignal;\n};\n\nexport type OptionListHandle<T extends BaseOptionItem> = {\n /** Reactive `aria-activedescendant` value. `null` when no option is focused or the list is closed. */\n readonly ariaActiveDescendant: Readable<string | null>;\n /** Reactive `aria-expanded` value as string (`'true'` / `'false'`). */\n readonly ariaExpanded: Readable<string>;\n close(reason?: DialogCloseReason): void;\n /**\n * Focused item index (read-only). Write via `set(index)` to update through\n * the list control — this ensures scroll-into-view and disabled-item checks.\n */\n readonly focusedIndex: Readable<number>;\n getActiveItem(): T | undefined;\n handleKeydown(event: KeyboardEvent): boolean;\n /** Open state (read-only). Mutate via `open()`, `close()`, or `toggle()`. */\n readonly isOpen: Readable<boolean>;\n /**\n * Programmatically navigate to a named position. Always fires `onNavigate`\n * (scroll-into-view, aria-activedescendant update).\n * Returns the resolved index, or `-1` if no enabled item was found.\n */\n navigate(action: ListNavigationAction): number;\n open(reason?: OverlayOpenReason): void;\n scrollFocusedIntoView(): void;\n /**\n * Set focus to the item at `index`. Returns the resolved index.\n * Pass a negative index to clear focus (same as `reset()`).\n */\n set(index: number): number;\n /**\n * Toggles open state.\n * - Opens with `openReason` (default `'click'`).\n * - Closes with `closeReason` (default `'trigger'`).\n */\n toggle(openReason?: OverlayOpenReason, closeReason?: DialogCloseReason): void;\n /** Imperatively re-run dropdown positioning (e.g. after filter changes list height). */\n updatePosition(): void;\n};\n\n// ── Factory ───────────────────────────────────────────────────────────────────\n\n/**\n * Shared headless primitive for dropdown option lists (select, combobox, menu).\n *\n * Owns `isOpen`, `focusedIndex`, the dropdown positioner, list navigation, and\n * overlay wiring. Composes overlay.ts + nav.ts into a single complete API.\n */\nexport const createOptionList = <T extends BaseOptionItem>(options: OptionListOptions<T>): OptionListHandle<T> => {\n if (typeof options.getBoundary !== 'function') {\n throw new RefineConfigError('createOptionList: getBoundary is required');\n }\n\n if (typeof options.getPanel !== 'function') {\n throw new RefineConfigError('createOptionList: getPanel is required');\n }\n\n if (typeof options.getReference !== 'function') {\n throw new RefineConfigError('createOptionList: getReference is required');\n }\n\n const isOpen = signal(false);\n\n const ariaExpanded = computed(() => String(isOpen.value));\n\n const positioner = createDropdownPositioner({\n ...options.positioning,\n getFloating: options.getPanel,\n getReference: options.getReference,\n });\n\n const scrollFocusedIntoView = (): void => {\n options.getFocusedOptionElement?.()?.scrollIntoView({ block: 'nearest' });\n };\n\n const list = createListControl<T>({\n disabled: computed(() => !isOpen.value),\n getItemLabel: options.getItemLabel,\n getItems: options.getItems,\n isItemDisabled: options.isItemDisabled,\n keys: options.keys,\n loop: options.loop ?? true,\n onNavigate: (action, index, event) => {\n scrollFocusedIntoView();\n\n if (index >= 0) options.onNavigate?.(action, index, event);\n },\n orientation: options.orientation,\n signal: options.signal,\n });\n\n const ariaActiveDescendant = computed<string | null>(() => {\n const idx = list.focusedIndex.value;\n\n return options.getOptionId && isOpen.value && idx >= 0 ? options.getOptionId(idx) : null;\n });\n\n const overlay = createOverlayControl({\n getBoundary: options.getBoundary,\n getPanel: options.getPanel,\n getTrigger: options.getTrigger,\n isDisabled: options.isDisabled,\n isOpen: () => isOpen.value,\n onClose: options.onClose,\n onOpen: options.onOpen,\n positioner,\n restoreFocus: options.restoreFocus,\n setOpen: (next) => {\n isOpen.value = next;\n\n if (!next) list.reset();\n },\n signal: options.signal,\n });\n\n // Built-in Escape key handling: prevents each consumer from duplicating the\n // close-on-escape pattern. Fires only when the list is open; returns `true`\n // so callers know the event was handled and can stop further processing.\n const handleKeydown = (event: KeyboardEvent): boolean => {\n if (!isOpen.value) return false;\n\n if (event.key === 'Escape') {\n event.preventDefault();\n overlay.close('escape');\n\n return true;\n }\n\n return list.handleKeydown(event);\n };\n\n return {\n ariaActiveDescendant,\n ariaExpanded,\n close: (reason) => overlay.close(reason),\n focusedIndex: list.focusedIndex,\n getActiveItem: list.getActiveItem,\n handleKeydown,\n isOpen,\n navigate: list.navigate,\n open: (reason) => overlay.open(reason),\n scrollFocusedIntoView,\n set: list.set,\n toggle: (openReason, closeReason) => overlay.toggle(openReason, closeReason),\n updatePosition: positioner.update,\n };\n};\n","import { computed, type Readable, signal } from '@vielzeug/ripple';\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport type PaginatedListOptions<T> = {\n /** All items to paginate. Can be a reactive signal accessor. */\n getItems: () => T[];\n /** Number of items per page. Defaults to 10. */\n pageSize?: Readable<number> | number;\n};\n\nexport type PaginatedListHandle<T> = {\n /** Navigate to an absolute page index (clamped). */\n goTo(index: number): void;\n /** Whether there is a next page. */\n readonly hasNext: Readable<boolean>;\n /** Whether there is a previous page. */\n readonly hasPrev: Readable<boolean>;\n\n /** Navigate to the next page. No-op on last page. */\n next(): void;\n /** Total number of pages. */\n readonly pageCount: Readable<number>;\n /** Current 0-based page index. */\n readonly pageIndex: Readable<number>;\n /** Items visible on the current page. */\n readonly pageItems: Readable<T[]>;\n /** Navigate to the previous page. No-op on first page. */\n prev(): void;\n /** Reset to the first page. */\n reset(): void;\n};\n\n// ── Implementation ────────────────────────────────────────────────────────────\n\n/**\n * Reactive pagination state for a list of items.\n *\n * Decoupled from option rendering so it can be used with any sorted/filtered\n * item array (e.g., the `filteredOptions` signal in combobox).\n *\n * @example\n * ```ts\n * const paged = createPaginatedList({ getItems: () => allOptions.value, pageSize: 20 });\n * // render paged.pageItems.value\n * // navigation: paged.next(), paged.prev(), paged.goTo(0)\n * ```\n */\nexport const createPaginatedList = <T>(options: PaginatedListOptions<T>): PaginatedListHandle<T> => {\n const pageIndex = signal(0);\n const resolvedPageSize = (): number => {\n const ps = options.pageSize;\n\n if (ps === undefined) return 10;\n\n return typeof ps === 'number' ? ps : (ps.value ?? 10);\n };\n\n const pageCount = computed(() => Math.ceil(options.getItems().length / resolvedPageSize()));\n\n // Clamp page index when total page count shrinks (e.g. after filter change).\n // When pageCount is 0 (empty list), safePage returns -1 to signal no valid page.\n const safePage = computed(() => (pageCount.value === 0 ? -1 : Math.min(pageIndex.value, pageCount.value - 1)));\n\n const pageItems = computed(() => {\n const pg = safePage.value;\n const size = resolvedPageSize();\n const start = pg * size;\n\n return options.getItems().slice(start, start + size);\n });\n\n const goTo = (index: number): void => {\n // Lower-bound guard only — safePage handles the upper-bound clamp reactively\n // so that any subsequent pageCount reduction is also handled automatically.\n // Guard against NaN/Infinity (e.g. parseInt() failures) which Math.max propagates silently.\n if (!Number.isFinite(index)) return;\n\n pageIndex.value = Math.max(0, index);\n };\n\n const next = (): void => {\n if (pageCount.value > 0 && safePage.value < pageCount.value - 1) pageIndex.value = safePage.value + 1;\n };\n\n const prev = (): void => {\n if (safePage.value > 0) pageIndex.value = safePage.value - 1;\n };\n\n const reset = (): void => {\n pageIndex.value = 0;\n };\n\n const hasNext = computed(() => pageCount.value > 0 && safePage.value < pageCount.value - 1);\n const hasPrev = computed(() => safePage.value > 0);\n\n return {\n goTo,\n hasNext,\n hasPrev,\n next,\n pageCount,\n pageIndex: safePage,\n pageItems,\n prev,\n reset,\n };\n};\n","// ── Number helpers ────────────────────────────────────────────────────────────\n\n/**\n * Coerces `value` via `Number()` and returns it when finite, `undefined` otherwise.\n *\n * Caveat: `null` and `''` both coerce to `0` in JavaScript (`Number(null) === 0`,\n * `Number('') === 0`) and are therefore returned as the finite number `0`, not\n * `undefined` — this function does not treat \"absent\" values specially. Only\n * genuinely non-numeric input (`undefined`, `NaN`, non-numeric strings) yields\n * `undefined`. Callers that mean \"no bound set\" should pass `undefined`\n * explicitly rather than `null` or `''`.\n */\nexport const toFiniteNumber = (value: unknown): number | undefined => {\n const parsed = Number(value);\n\n return Number.isFinite(parsed) ? parsed : undefined;\n};\n\nexport const toFiniteNumberOr = (value: unknown, fallback: number): number => {\n return toFiniteNumber(value) ?? fallback;\n};\n\nexport const toPositiveStep = (value: unknown, fallback: number): number => {\n return Math.abs(toFiniteNumberOr(value, fallback)) || fallback;\n};\n","import type { Readable } from '@vielzeug/ripple';\n\nimport { clamp as clampRange } from '@vielzeug/arsenal';\n\nimport { dispatchKeyboardAction } from './keyboard';\nimport { toFiniteNumber, toPositiveStep } from './numbers';\n\nexport type SpinnerControlOptions = {\n commit: (value: number | null, originalEvent?: Event) => void;\n disabled?: Readable<boolean | undefined>;\n largeStep?: Readable<number | string | undefined>;\n max?: Readable<number | string | undefined>;\n min?: Readable<number | string | undefined>;\n parse: () => number | null;\n readonly?: Readable<boolean | undefined>;\n step?: Readable<number | string | undefined>;\n};\n\nexport type SpinnerControl = {\n atMax: () => boolean;\n atMin: () => boolean;\n handleKeydown: (event: KeyboardEvent) => boolean;\n incrementBy: (delta: number, originalEvent?: Event) => void;\n};\n\nexport const createSpinnerControl = (options: SpinnerControlOptions): SpinnerControl => {\n const isBlocked = (): boolean => Boolean(options.disabled?.value) || Boolean(options.readonly?.value);\n\n const min = (): number | undefined => {\n return toFiniteNumber(options.min?.value);\n };\n\n const max = (): number | undefined => {\n return toFiniteNumber(options.max?.value);\n };\n\n const clamp = (value: number): number => {\n return clampRange(value, min(), max());\n };\n\n const step = (): number => toPositiveStep(options.step?.value, 1);\n\n const largeStep = (): number => {\n const s = step();\n\n return toPositiveStep(options.largeStep?.value, s * 10);\n };\n\n const currentOrFallback = (): number => {\n const parsed = options.parse();\n\n if (parsed != null) return parsed;\n\n const minValue = min();\n\n if (minValue != null) return minValue;\n\n return 0;\n };\n\n const commit = (value: number | null, originalEvent?: Event): void => {\n if (value == null) {\n options.commit(null, originalEvent);\n\n return;\n }\n\n options.commit(clamp(value), originalEvent);\n };\n\n const incrementBy = (delta: number, originalEvent?: Event): void => {\n if (isBlocked()) return;\n\n commit(currentOrFallback() + delta, originalEvent);\n };\n\n const atMin = (): boolean => {\n const parsed = options.parse();\n const minValue = min();\n\n return parsed != null && minValue != null && parsed <= minValue;\n };\n\n const atMax = (): boolean => {\n const parsed = options.parse();\n const maxValue = max();\n\n return parsed != null && maxValue != null && parsed >= maxValue;\n };\n\n const handleKeydown = (event: KeyboardEvent): boolean => {\n if (isBlocked()) return false;\n\n return dispatchKeyboardAction(event, {\n keymap: {\n ArrowDown: () => incrementBy(-step(), event),\n ArrowUp: () => incrementBy(step(), event),\n End: () => {\n const maxValue = max();\n\n if (maxValue == null) return false;\n\n commit(maxValue, event);\n },\n Home: () => {\n const minValue = min();\n\n if (minValue == null) return false;\n\n commit(minValue, event);\n },\n PageDown: () => incrementBy(-largeStep(), event),\n PageUp: () => incrementBy(largeStep(), event),\n },\n preventDefault: 'after',\n });\n };\n\n return {\n atMax,\n atMin,\n handleKeydown,\n incrementBy,\n };\n};\n","import type { Readable } from '@vielzeug/ripple';\n\nimport { clamp as clampRange } from '@vielzeug/arsenal';\n\nimport { toFiniteNumberOr, toPositiveStep } from './numbers';\n\n// ── Slider control ────────────────────────────────────────────────────────────\n\nexport type SliderControlOptions = {\n disabled?: Readable<boolean | undefined>;\n max?: Readable<number | string | undefined>;\n min?: Readable<number | string | undefined>;\n readonly?: Readable<boolean | undefined>;\n step?: Readable<number | string | undefined>;\n};\n\nexport type SliderControl = {\n clamp: (value: number) => number;\n fromClientX: (clientX: number, rect: { left: number; width: number }) => number;\n /**\n * Handles keyboard navigation for a slider input.\n * When the slider is disabled or readonly, the event is ignored and `false` is returned.\n * @returns `true` when the event was handled and `onCommit` was called, `false` otherwise.\n */\n handleKeydown: (event: KeyboardEvent, currentValue: number, onCommit: (value: number) => void) => boolean;\n max: () => number;\n min: () => number;\n nextFromKey: (key: string, current: number) => number | null;\n snap: (value: number) => number;\n toPercent: (value: number) => number;\n};\n\nexport const createSliderControl = (options: SliderControlOptions): SliderControl => {\n const min = (): number => toFiniteNumberOr(options.min?.value, 0);\n const max = (): number => toFiniteNumberOr(options.max?.value, 100);\n const step = (): number => toPositiveStep(options.step?.value, 1);\n\n const clamp = (value: number): number => {\n const minValue = min();\n const maxValue = max();\n\n return clampRange(toFiniteNumberOr(value, minValue), minValue, maxValue);\n };\n\n const snap = (value: number): number => {\n const minValue = min();\n\n return clamp(Math.round(toFiniteNumberOr(value, minValue) / step()) * step());\n };\n\n const toPercent = (value: number): number => {\n const minValue = min();\n const maxValue = max();\n const normalized = toFiniteNumberOr(value, minValue);\n\n if (maxValue <= minValue) return 0;\n\n return ((normalized - minValue) / (maxValue - minValue)) * 100;\n };\n\n const fromClientX = (clientX: number, rect: { left: number; width: number }): number => {\n if (rect.width <= 0) return snap(min());\n\n const pct = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));\n const minValue = min();\n const maxValue = max();\n\n return snap(minValue + pct * (maxValue - minValue));\n };\n\n const nextFromKey = (key: string, current: number): number | null => {\n const normalized = toFiniteNumberOr(current, min());\n\n if (key === 'ArrowRight' || key === 'ArrowUp') return clamp(normalized + step());\n\n if (key === 'ArrowLeft' || key === 'ArrowDown') return clamp(normalized - step());\n\n if (key === 'Home') return min();\n\n if (key === 'End') return max();\n\n return null;\n };\n\n const handleKeydown = (event: KeyboardEvent, currentValue: number, onCommit: (value: number) => void): boolean => {\n if (options.disabled?.value || options.readonly?.value) return false;\n\n const next = nextFromKey(event.key, currentValue);\n\n if (next === null) return false;\n\n event.preventDefault();\n onCommit(next);\n\n return true;\n };\n\n return { clamp, fromClientX, handleKeydown, max, min, nextFromKey, snap, toPercent };\n};\n","import type { Readable } from '@vielzeug/ripple';\n\nexport type SwipeAxis = 'x' | 'y';\n\nexport type SwipeControlDetail = {\n axis: SwipeAxis;\n current: number;\n distance: number;\n event: PointerEvent;\n pointerId: number;\n progress: number;\n start: number;\n threshold: number;\n};\n\nexport type SwipeControlOptions = {\n axis?: () => SwipeAxis;\n captureTarget?: (event: PointerEvent) => HTMLElement | null;\n disabled?: Readable<boolean | undefined>;\n /** Called when the platform interrupts an in-flight swipe (`pointercancel`). */\n onCancel?: (detail: SwipeControlDetail) => void;\n onCommit?: (detail: SwipeControlDetail) => void;\n onMove?: (detail: SwipeControlDetail) => void;\n /** Called when the pointer is released (`pointerup`) without crossing the commit threshold. */\n onRelease?: (detail: SwipeControlDetail) => void;\n onStart?: (detail: SwipeControlDetail) => void;\n shouldCommit?: (detail: SwipeControlDetail) => boolean;\n threshold?: () => number;\n};\n\nexport type SwipeControl = {\n [Symbol.dispose](): void;\n /** Cancel any in-flight swipe and clean up internal state. */\n dispose: () => void;\n handlePointerCancel: (event: PointerEvent) => boolean;\n handlePointerDown: (event: PointerEvent) => boolean;\n handlePointerMove: (event: PointerEvent) => boolean;\n handlePointerUp: (event: PointerEvent) => boolean;\n isActive: () => boolean;\n};\n\ntype ActiveSwipe = {\n axis: SwipeAxis;\n pointerId: number;\n start: number;\n threshold: number;\n};\n\nconst resolveAxis = (options: SwipeControlOptions): SwipeAxis => options.axis?.() ?? 'x';\n\nconst resolveThreshold = (options: SwipeControlOptions): number => {\n const threshold = options.threshold?.() ?? 48;\n\n return Number.isFinite(threshold) && threshold > 0 ? threshold : 1;\n};\n\nconst getCoordinate = (event: PointerEvent, axis: SwipeAxis): number => {\n return axis === 'x' ? event.clientX : event.clientY;\n};\n\nconst defaultCaptureTarget = (event: PointerEvent): HTMLElement | null => {\n if (event.currentTarget instanceof HTMLElement) return event.currentTarget;\n\n if (event.target instanceof HTMLElement) return event.target;\n\n return null;\n};\n\nexport const createSwipeControl = (options: SwipeControlOptions): SwipeControl => {\n let active: ActiveSwipe | null = null;\n\n const isDisabled = (): boolean => Boolean(options.disabled?.value);\n\n const reset = (): void => {\n active = null;\n };\n\n const matchesPointer = (event: PointerEvent): boolean => {\n return active?.pointerId === event.pointerId;\n };\n\n const createDetail = (event: PointerEvent): SwipeControlDetail | null => {\n if (!active) return null;\n\n const current = getCoordinate(event, active.axis);\n const distance = current - active.start;\n\n return {\n axis: active.axis,\n current,\n distance,\n event,\n pointerId: active.pointerId,\n progress: Math.min(Math.abs(distance) / active.threshold, 1),\n start: active.start,\n threshold: active.threshold,\n };\n };\n\n const handlePointerDown = (event: PointerEvent): boolean => {\n if (active || isDisabled()) return false;\n\n const axis = resolveAxis(options);\n\n active = {\n axis,\n pointerId: event.pointerId,\n start: getCoordinate(event, axis),\n threshold: resolveThreshold(options),\n };\n\n const captureTarget =\n typeof options.captureTarget === 'function' ? options.captureTarget(event) : defaultCaptureTarget(event);\n\n captureTarget?.setPointerCapture?.(event.pointerId);\n\n const detail = createDetail(event);\n\n if (detail) options.onStart?.(detail);\n\n return true;\n };\n\n const handlePointerMove = (event: PointerEvent): boolean => {\n if (!active || !matchesPointer(event)) return false;\n\n const detail = createDetail(event);\n\n if (!detail) return false;\n\n options.onMove?.(detail);\n\n const shouldCommit = options.shouldCommit?.(detail) ?? Math.abs(detail.distance) >= detail.threshold;\n\n if (!shouldCommit) return true;\n\n reset();\n options.onCommit?.(detail);\n\n return true;\n };\n\n const handlePointerUp = (event: PointerEvent): boolean => {\n if (!active || !matchesPointer(event)) return false;\n\n const detail = createDetail(event);\n\n reset();\n\n if (detail) options.onRelease?.(detail);\n\n return true;\n };\n\n const handlePointerCancel = (event: PointerEvent): boolean => {\n if (!active || !matchesPointer(event)) return false;\n\n const detail = createDetail(event);\n\n reset();\n\n if (detail) options.onCancel?.(detail);\n\n return true;\n };\n\n return {\n dispose: reset,\n handlePointerCancel,\n handlePointerDown,\n handlePointerMove,\n handlePointerUp,\n isActive: () => active != null,\n [Symbol.dispose]: reset,\n };\n};\n","// ── Live-Region Announcer ─────────────────────────────────────────────────────\n// Programmatic announcements to screen readers without requiring a visible\n// DOM element. Used for status messages, selection feedback, and count updates\n// that live in components where the visible element is hidden or absent.\n//\n// Two visually-hidden live regions are lazily created in `<body>` — one polite,\n// one assertive. The clear-then-set pattern forces AT to re-read even identical\n// consecutive messages.\n//\n// Usage:\n// ```ts\n// import { announce } from './announcer';\n// announce(`${selectedCount} items selected`);\n// announce('Error: field is required', { politeness: 'assertive' });\n// ```\n\nimport { SR_ONLY_INLINE_STYLE } from '../styles';\n\n// ── Visually-hidden style ─────────────────────────────────────────────────────\n// Shared with the CSS-side `.sr-only` mixin — see `src/styles/mixins/accessibility.css.ts`.\n\n// ── Per-document live regions (WeakMap for automatic GC + test isolation) ────\n\ntype DocumentRegions = { assertive?: HTMLElement; polite?: HTMLElement };\n\nconst _regions = new WeakMap<Document, DocumentRegions>();\nconst _timers = new WeakMap<HTMLElement, ReturnType<typeof setTimeout>>();\n\n/** Creates and mounts a visually-hidden live region with the given politeness. */\nconst createRegion = (politeness: 'assertive' | 'polite', doc: Document): HTMLElement => {\n const el = doc.createElement('div');\n\n el.setAttribute('aria-live', politeness);\n el.setAttribute('aria-atomic', 'true');\n el.setAttribute('data-block-announcer', politeness);\n el.style.cssText = SR_ONLY_INLINE_STYLE;\n\n doc.body.appendChild(el);\n\n return el;\n};\n\n/**\n * Returns the live region for the requested politeness in the given document,\n * creating it on first access. Returns `null` outside a browser context.\n */\nconst getRegion = (politeness: 'assertive' | 'polite', doc: Document): HTMLElement | null => {\n let regions = _regions.get(doc);\n\n // Re-create if this specific region was removed from the DOM (e.g. by test teardown).\n if (regions?.[politeness] && !doc.body.contains(regions[politeness])) {\n regions[politeness] = undefined;\n }\n\n if (!regions?.[politeness]) {\n if (!regions) {\n regions = {};\n _regions.set(doc, regions);\n }\n\n regions[politeness] = createRegion(politeness, doc);\n }\n\n return regions[politeness] ?? null;\n};\n\n// ── Public API ────────────────────────────────────────────────────────────────\n\nexport type AnnouncePoliteness = 'assertive' | 'polite';\n\nexport type AnnounceOptions = {\n /**\n * `'polite'` — queues the announcement; does not interrupt ongoing speech.\n * `'assertive'` — interrupts immediately. Use sparingly; reserve for errors.\n *\n * Default: `'polite'`.\n */\n politeness?: AnnouncePoliteness;\n};\n\n/**\n * Announces a message to screen readers via a singleton visually-hidden\n * live region. Safe to call outside a component lifecycle (no cleanup needed).\n *\n * The clear-then-set pattern (50 ms delay) forces AT to re-read even when the\n * message text hasn't changed.\n *\n * @example\n * ```ts\n * announce('3 results found');\n * announce('Session expired', { politeness: 'assertive' });\n * ```\n */\nexport const announce = (message: string, options: AnnounceOptions = {}): void => {\n if (typeof document === 'undefined') return;\n\n const politeness = options.politeness ?? 'polite';\n const region = getRegion(politeness, document);\n\n if (!region) return;\n\n // Clear immediately so AT registers a content change, then set after a short\n // delay. The 50 ms window is the established minimum for most AT/browser combos.\n region.textContent = '';\n\n // Use a per-element timer so concurrent polite + assertive announcements don't\n // clobber each other's pending writes.\n const existing = _timers.get(region);\n\n if (existing !== undefined) clearTimeout(existing);\n\n const timer = setTimeout(() => {\n region.textContent = message;\n _timers.delete(region);\n }, 50);\n\n _timers.set(region, timer);\n};\n","import { Temporal, format, parsePlainDate } from '@vielzeug/tempo';\n\n// ── Public ISO helpers (single source of truth for both components) ───────────\n\n/**\n * Parses an ISO 8601 date string (`yyyy-MM-dd`) into a `Temporal.PlainDate`.\n * Returns `null` for any invalid / empty input — never throws.\n */\nexport function parseIso(iso: string | undefined | null): Temporal.PlainDate | null {\n if (!iso) return null;\n\n try {\n return parsePlainDate(iso);\n } catch {\n return null;\n }\n}\n\n/**\n * Serialises a `Temporal.PlainDate` (or `null`) to an ISO 8601 string (`yyyy-MM-dd`).\n * Returns `null` when the input is `null`.\n */\nexport function toIsoString(date: Temporal.PlainDate | null): string | null {\n return date ? date.toString() : null;\n}\n\n/**\n * Formats a `Temporal.PlainDate` for display in a given locale.\n * e.g. \"15 Jun 2025\" (default medium pattern).\n */\nexport function formatDisplayDate(date: Temporal.PlainDate, locale: string): string {\n return format(date, { intl: { day: 'numeric', month: 'short', year: 'numeric' }, locale, tz: 'UTC' });\n}\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport type DatePickerView = 'day' | 'month' | 'year';\n\nexport type DateCell = {\n /** Day-of-month number (1–31) */\n day: number;\n isDisabled: boolean;\n /** ISO date string yyyy-MM-dd — stable key for rendering */\n iso: string;\n isOutsideMonth: boolean;\n isSelected: boolean;\n isToday: boolean;\n plain: Temporal.PlainDate;\n};\n\nexport type MonthCell = {\n isDisabled: boolean;\n isSelected: boolean;\n label: string;\n /** 1-based month number (Temporal convention: 1 = January … 12 = December) */\n month: number;\n shortLabel: string;\n};\n\nexport type YearCell = {\n isDisabled: boolean;\n isSelected: boolean;\n year: number;\n};\n\nexport type DatePickerControlOptions = {\n /** Locale for day/month names, defaults to `navigator.language` or `'en'` */\n locale?: string;\n /** Maximum selectable date (inclusive) */\n max?: Temporal.PlainDate | null;\n /** Minimum selectable date (inclusive) */\n min?: Temporal.PlainDate | null;\n /** Called when a date is committed by the user */\n onChange: (date: Temporal.PlainDate | null) => void;\n /** Currently selected date */\n value?: Temporal.PlainDate | null;\n /**\n * Which days of the week to disable (0 = Sunday … 6 = Saturday).\n * @example [0, 6] disables weekends\n */\n weekendDays?: number[];\n};\n\nexport type DatePickerControl = {\n /** Ordered day cells for the visible month grid (includes leading/trailing days) */\n dayCells(): DateCell[];\n /** Month currently shown in the header (1-indexed, Temporal convention) */\n displayMonth(): number;\n /** Year currently shown in the header */\n displayYear(): number;\n /** Jump to a specific display month/year without selecting */\n goTo(year: number, month: number): void;\n /** All 12 month cells */\n monthCells(): MonthCell[];\n /** Move display month forward by one */\n nextMonth(): void;\n /** Move display year forward by one */\n nextYear(): void;\n /** Move display month backward by one */\n prevMonth(): void;\n /** Move display year backward by one */\n prevYear(): void;\n /** Select a date. Pass null to clear. */\n select(date: Temporal.PlainDate | null): void;\n /** The currently selected date, or null */\n selected(): Temporal.PlainDate | null;\n /** Switch the calendar view */\n setView(view: DatePickerView): void;\n /** Currently rendered calendar view */\n view(): DatePickerView;\n /** Short week-day labels in locale order e.g. [\"Su\",\"Mo\",…] */\n weekdayLabels(): string[];\n /** Year cells for the visible decade window */\n yearCells(): YearCell[];\n};\n\n// ── Internal helpers ──────────────────────────────────────────────────────────\n\n/**\n * Returns today as a `Temporal.PlainDate` in the ISO calendar.\n * @internal\n */\nfunction todayPlain(): Temporal.PlainDate {\n return Temporal.Now.plainDateISO();\n}\n\n/**\n * Converts a `Temporal.PlainDate.dayOfWeek` value (1=Mon…7=Sun) to the\n * 0-based weekday index (0=Sun…6=Sat) used in the `weekendDays` prop.\n * @internal\n */\nfunction temporalDowToIndex(dow: number): number {\n // Temporal: 1=Mon, 2=Tue, …, 7=Sun → 0=Sun, 1=Mon, …, 6=Sat\n return dow % 7;\n}\n\n// ── Factory ───────────────────────────────────────────────────────────────────\n\n/**\n * Pure, framework-agnostic date-picker state machine backed by `Temporal.PlainDate`.\n *\n * All state is held in plain mutable variables — suitable for wrapping in any\n * reactive layer (ore `signal`, Vue ref, etc.). The factory returns a stable\n * handle object; callers are responsible for reactivity.\n *\n * Options with getter-based live bindings (e.g. `get min() { ... }`) are read\n * on every call so the control always reflects the latest reactive state.\n *\n * @example\n * ```ts\n * const ctrl = createDatePickerControl({\n * value: Temporal.PlainDate.from('2025-06-15'),\n * locale: 'en-US',\n * onChange: (date) => console.log(date?.toString()),\n * });\n *\n * ctrl.nextMonth();\n * ctrl.select(Temporal.PlainDate.from('2025-07-04'));\n * ```\n */\nexport function createDatePickerControl(options: DatePickerControlOptions): DatePickerControl {\n // ── Mutable state ─────────────────────────────────────────────────────────\n\n let _selected: Temporal.PlainDate | null = options.value ?? null;\n let _view: DatePickerView = 'day';\n\n const initial = _selected ?? todayPlain();\n\n let _displayYear = initial.year;\n let _displayMonth = initial.month; // 1-indexed (Temporal convention)\n\n // ── Live option accessors (always read from options for reactive compat) ───\n\n function locale(): string {\n return options.locale ?? (typeof navigator !== 'undefined' ? navigator.language : 'en');\n }\n\n function weekendDays(): number[] {\n return options.weekendDays ?? [];\n }\n\n // ── Range / disabled helpers ───────────────────────────────────────────────\n\n function isOutOfRange(date: Temporal.PlainDate): boolean {\n if (options.min && Temporal.PlainDate.compare(date, options.min) < 0) return true;\n\n if (options.max && Temporal.PlainDate.compare(date, options.max) > 0) return true;\n\n return false;\n }\n\n function isDayDisabled(date: Temporal.PlainDate): boolean {\n if (isOutOfRange(date)) return true;\n\n if (weekendDays().includes(temporalDowToIndex(date.dayOfWeek))) return true;\n\n return false;\n }\n\n // ── Grid builders ─────────────────────────────────────────────────────────\n\n function buildDayCells(): DateCell[] {\n const todayDate = todayPlain();\n const firstOfMonth = Temporal.PlainDate.from({ day: 1, month: _displayMonth, year: _displayYear });\n\n // Sunday-start grid: Temporal dayOfWeek is 1=Mon…7=Sun, convert to 0=Sun offset\n const startOffset = temporalDowToIndex(firstOfMonth.dayOfWeek);\n const cells: DateCell[] = [];\n\n // Leading days from previous month\n for (let i = startOffset - 1; i >= 0; i--) {\n const d = firstOfMonth.subtract({ days: i + 1 });\n\n cells.push({\n day: d.day,\n isDisabled: isDayDisabled(d),\n iso: d.toString(),\n isOutsideMonth: true,\n isSelected: _selected !== null && Temporal.PlainDate.compare(d, _selected) === 0,\n isToday: Temporal.PlainDate.compare(d, todayDate) === 0,\n plain: d,\n });\n }\n\n // Days in current month\n const daysInMonth = firstOfMonth.daysInMonth;\n\n for (let day = 1; day <= daysInMonth; day++) {\n const d = Temporal.PlainDate.from({ day, month: _displayMonth, year: _displayYear });\n\n cells.push({\n day,\n isDisabled: isDayDisabled(d),\n iso: d.toString(),\n isOutsideMonth: false,\n isSelected: _selected !== null && Temporal.PlainDate.compare(d, _selected) === 0,\n isToday: Temporal.PlainDate.compare(d, todayDate) === 0,\n plain: d,\n });\n }\n\n // Trailing days to fill last row (always end at multiple of 7)\n const remaining = (7 - (cells.length % 7)) % 7;\n const firstOfNext = firstOfMonth.add({ months: 1 });\n\n for (let i = 0; i < remaining; i++) {\n const d = firstOfNext.add({ days: i });\n\n cells.push({\n day: d.day,\n isDisabled: isDayDisabled(d),\n iso: d.toString(),\n isOutsideMonth: true,\n isSelected: _selected !== null && Temporal.PlainDate.compare(d, _selected) === 0,\n isToday: Temporal.PlainDate.compare(d, todayDate) === 0,\n plain: d,\n });\n }\n\n return cells;\n }\n\n function buildMonthCells(): MonthCell[] {\n const cells: MonthCell[] = [];\n const loc = locale();\n\n for (let m = 1; m <= 12; m++) {\n const plain = Temporal.PlainDate.from({ day: 1, month: m, year: _displayYear });\n const lastOfMonth = plain.with({ day: plain.daysInMonth });\n\n const isDisabled =\n (options.min !== null && options.min !== undefined\n ? Temporal.PlainDate.compare(lastOfMonth, options.min) < 0\n : false) ||\n (options.max !== null && options.max !== undefined\n ? Temporal.PlainDate.compare(plain, options.max) > 0\n : false);\n\n cells.push({\n isDisabled,\n isSelected: _selected !== null && _selected.year === _displayYear && _selected.month === m,\n label: format(plain, { intl: { month: 'long' }, locale: loc, tz: 'UTC' }),\n month: m,\n shortLabel: format(plain, { intl: { month: 'short' }, locale: loc, tz: 'UTC' }),\n });\n }\n\n return cells;\n }\n\n function buildYearCells(): YearCell[] {\n const decadeStart = Math.floor(_displayYear / 10) * 10;\n const cells: YearCell[] = [];\n\n for (let y = decadeStart; y < decadeStart + 12; y++) {\n const firstOfYear = Temporal.PlainDate.from({ day: 1, month: 1, year: y });\n const lastOfYear = Temporal.PlainDate.from({ day: 31, month: 12, year: y });\n\n const isDisabled =\n (options.min !== null && options.min !== undefined\n ? Temporal.PlainDate.compare(lastOfYear, options.min) < 0\n : false) ||\n (options.max !== null && options.max !== undefined\n ? Temporal.PlainDate.compare(firstOfYear, options.max) > 0\n : false);\n\n cells.push({\n isDisabled,\n isSelected: _selected !== null && _selected.year === y,\n year: y,\n });\n }\n\n return cells;\n }\n\n function buildWeekdayLabels(): string[] {\n // 2024-01-07 is a Sunday — use it as the Sunday anchor\n const sunday = parsePlainDate('2024-01-07');\n const loc = locale();\n\n return Array.from({ length: 7 }, (_, i) =>\n format(sunday.add({ days: i }), { intl: { weekday: 'short' }, locale: loc, tz: 'UTC' }),\n );\n }\n\n // ── Handle ────────────────────────────────────────────────────────────────\n\n return {\n dayCells: buildDayCells,\n displayMonth: () => _displayMonth,\n displayYear: () => _displayYear,\n\n goTo(year: number, month: number): void {\n if (!Number.isFinite(year)) return;\n\n _displayYear = year;\n _displayMonth = Math.max(1, Math.min(12, month));\n },\n\n monthCells: buildMonthCells,\n\n nextMonth(): void {\n if (_displayMonth === 12) {\n _displayMonth = 1;\n _displayYear++;\n } else {\n _displayMonth++;\n }\n },\n\n nextYear(): void {\n _displayYear++;\n },\n\n prevMonth(): void {\n if (_displayMonth === 1) {\n _displayMonth = 12;\n _displayYear--;\n } else {\n _displayMonth--;\n }\n },\n\n prevYear(): void {\n _displayYear--;\n },\n\n select(date: Temporal.PlainDate | null): void {\n if (date !== null && isDayDisabled(date)) return;\n\n _selected = date;\n\n if (_selected) {\n _displayYear = _selected.year;\n _displayMonth = _selected.month;\n }\n\n options.onChange(_selected);\n },\n\n selected: () => _selected,\n\n setView(view: DatePickerView): void {\n _view = view;\n },\n\n view: () => _view,\n\n weekdayLabels: buildWeekdayLabels,\n\n yearCells: buildYearCells,\n };\n}\n","// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport type FocusManagerOptions = {\n /**\n * Returns the CSS selector for the element that should receive focus on open.\n *\n * **Security note:** this value is passed directly to `querySelector`. It must\n * come from trusted developer-controlled configuration, never from raw user input.\n */\n getInitialFocusSelector: () => string | undefined;\n /**\n * Returns whether focus should be restored to the previously focused element\n * on close. `undefined` or `true` means restore; `false` means skip.\n */\n getReturnFocus: () => boolean | undefined;\n /** Host element used for `querySelector` when resolving the initial focus target. */\n host: HTMLElement;\n};\n\nexport type FocusManager = {\n /** Move focus to the element matching `getInitialFocusSelector` (deferred one frame). */\n applyInitialFocus: () => void;\n /** Cancel a pending `applyInitialFocus` rAF, if any. */\n cancelInitialFocus: () => void;\n /** Capture the currently focused element so it can be restored later. */\n captureReturnFocus: () => void;\n /** Restore focus to the element captured by `captureReturnFocus`. */\n restoreFocus: () => void;\n};\n\n// ── Factory ───────────────────────────────────────────────────────────────────\n\n/**\n * Encapsulates the three-step focus lifecycle used by dialogs and drawers:\n * 1. Capture the element that triggered the open.\n * 2. Move focus inside the overlay (optionally to a specific element).\n * 3. Restore focus when the overlay closes.\n */\nexport function createFocusManager(options: FocusManagerOptions): FocusManager {\n let returnFocusEl: HTMLElement | null = null;\n let rafHandle: ReturnType<typeof requestAnimationFrame> | null = null;\n\n return {\n applyInitialFocus() {\n if (rafHandle !== null) {\n cancelAnimationFrame(rafHandle);\n rafHandle = null;\n }\n\n const selector = options.getInitialFocusSelector();\n\n if (selector) {\n // Query the shadow root first (all refine components render into Shadow DOM),\n // falling back to the host's light-DOM tree for non-Shadow contexts.\n const root = options.host.shadowRoot ?? options.host;\n\n let target: HTMLElement | null = null;\n\n try {\n target = root.querySelector<HTMLElement>(selector);\n } catch {\n // Malformed selector (SyntaxError) — skip initial focus rather than throw.\n return;\n }\n\n if (target) {\n rafHandle = requestAnimationFrame(() => {\n rafHandle = null;\n target.focus();\n });\n }\n }\n },\n\n cancelInitialFocus() {\n if (rafHandle !== null) {\n cancelAnimationFrame(rafHandle);\n rafHandle = null;\n }\n },\n\n captureReturnFocus() {\n returnFocusEl = document.activeElement as HTMLElement;\n },\n\n restoreFocus() {\n if (options.getReturnFocus() !== false && returnFocusEl) {\n returnFocusEl.focus();\n returnFocusEl = null;\n }\n },\n };\n}\n","// ── Slot / light-DOM query helpers ────────────────────────────────────────────\n// Utilities for querying slotted light-DOM children and resolving labels from\n// option elements. Used by group components (checkbox-group, radio-group) and\n// choice-field components (select, combobox).\n\n/**\n * Returns all light-DOM descendants matching `tag` inside `host`.\n * Uses `getElementsByTagName` on the host's light DOM \\u2014 not Shadow DOM slot assignment.\n */\nexport const getLightChildrenByTag = (host: HTMLElement, tag: string): HTMLElement[] =>\n Array.from(host.getElementsByTagName(tag)) as HTMLElement[];\n\n/**\n * Returns the `textContent` of the item whose `value` attribute matches `value`,\n * falling back to `value` itself when no match is found.\n * Used by choice-field components to derive labels for emitted change events.\n */\nexport const getChoiceLabel = (items: HTMLElement[], value: string): string => {\n const item = items.find((el) => (el.getAttribute('value') ?? '') === value);\n\n return item?.textContent?.replace(/\\s+/g, ' ').trim() || value;\n};\n","import { computed, type Readable, signal } from '@vielzeug/ripple';\n\nimport type { SelectionMode } from './datagrid';\n\n// ── Selection control ─────────────────────────────────────────────────────────\n\nexport type SelectionControlOptions<T> = {\n /** Returns a unique string key for each row item. */\n getRowKey: (item: T) => string;\n /** Called when selection changes. Receives the full set of selected keys. */\n onSelectionChange?: (keys: Set<string>) => void;\n /** Returns the current page items reactively. */\n pageItems: () => T[];\n /** Returns the current selection mode reactively. */\n selectionMode: () => SelectionMode;\n};\n\nexport type SelectionControl = {\n /** Deselect all rows. */\n clearSelection(): void;\n /** Whether all current-page rows are selected. */\n isAllSelected(): boolean;\n /** Whether a given row key is selected. */\n isSelected(key: string): boolean;\n /** Select (or deselect if already all selected) all rows on the current page. */\n selectAll(): void;\n /** Current selected row keys. Reactive signal. Returns a snapshot copy. */\n readonly selectedKeys: Readable<ReadonlySet<string>>;\n /** Set the selection to an explicit set of keys. */\n setSelection(keys: Set<string>): void;\n /** Toggle selection for a single row. */\n toggleRow(key: string): void;\n};\n\nexport const createSelectionControl = <T>(options: SelectionControlOptions<T>): SelectionControl => {\n const _selectedKeys = signal<Set<string>>(new Set());\n\n const isSelected = (key: string): boolean => _selectedKeys.value.has(key);\n\n const isAllSelected = (): boolean => {\n const page = options.pageItems();\n\n if (!page.length) return false;\n\n return page.every((item) => _selectedKeys.value.has(options.getRowKey(item)));\n };\n\n const _commitSelection = (next: Set<string>): void => {\n _selectedKeys.value = next;\n options.onSelectionChange?.(next);\n };\n\n const toggleRow = (key: string): void => {\n const mode = options.selectionMode();\n\n if (mode === 'none') return;\n\n const next = new Set(_selectedKeys.value);\n\n if (next.has(key)) {\n next.delete(key);\n } else if (mode === 'single') {\n next.clear();\n next.add(key);\n } else {\n next.add(key);\n }\n\n _commitSelection(next);\n };\n\n const selectAll = (): void => {\n if (options.selectionMode() !== 'multi') return;\n\n const page = options.pageItems();\n\n if (isAllSelected()) {\n const next = new Set(_selectedKeys.value);\n\n for (const item of page) next.delete(options.getRowKey(item));\n\n _commitSelection(next);\n } else {\n const next = new Set(_selectedKeys.value);\n\n for (const item of page) next.add(options.getRowKey(item));\n\n _commitSelection(next);\n }\n };\n\n const clearSelection = (): void => {\n _commitSelection(new Set());\n };\n\n const setSelection = (keys: Set<string>): void => {\n _commitSelection(new Set(keys));\n };\n\n return {\n clearSelection,\n isAllSelected,\n isSelected,\n selectAll,\n selectedKeys: computed(() => new Set(_selectedKeys.value)),\n setSelection,\n toggleRow,\n };\n};\n","import { computed, type Readable, signal } from '@vielzeug/ripple';\n\nimport type { DataGridColumn, SortDirection, SortState } from './datagrid';\n\n// ── Sort control ──────────────────────────────────────────────────────────────\n\nexport type SortControlOptions<T> = {\n /** Returns the current column definitions reactively. */\n columns: () => DataGridColumn<T>[];\n /** The reactive list of items to sort. */\n items: Readable<T[]>;\n /** Called when sort state changes. */\n onSortChange?: (sort: SortState) => void;\n};\n\nexport type SortControl<T> = {\n /** Sort by the given column key — cycles asc → desc → none. */\n sortBy(key: string): void;\n /** Sorted version of the provided items. Reactive signal. */\n readonly sortedItems: Readable<T[]>;\n /** Current sort state. Reactive signal. */\n readonly sortState: Readable<SortState>;\n /** Set sort to an explicit key and direction. Passing `'none'` clears the sort. */\n sortTo(key: string, direction: SortDirection): void;\n};\n\nexport const createSortControl = <T>(options: SortControlOptions<T>): SortControl<T> => {\n const items = options.items;\n const _sortKey = signal<string>('');\n const _sortDir = signal<SortDirection>('none');\n\n const sortState = computed<SortState>(() => ({ direction: _sortDir.value, key: _sortKey.value }));\n\n const sortedItems = computed<T[]>(() => {\n const all = items.value;\n const key = _sortKey.value;\n const dir = _sortDir.value;\n\n if (!key || dir === 'none') return all;\n\n const col = options.columns().find((c) => c.key === key);\n\n return all.slice().sort((a, b) => {\n const av = col?.sortValue ? col.sortValue(a) : ((a as Record<string, unknown>)[key] as number | string);\n const bv = col?.sortValue ? col.sortValue(b) : ((b as Record<string, unknown>)[key] as number | string);\n const cmp =\n typeof av === 'number' && typeof bv === 'number' ? av - bv : String(av ?? '').localeCompare(String(bv ?? ''));\n\n return dir === 'asc' ? cmp : -cmp;\n });\n });\n\n const sortBy = (key: string): void => {\n if (_sortKey.value !== key) {\n _sortKey.value = key;\n _sortDir.value = 'asc';\n } else if (_sortDir.value === 'asc') {\n _sortDir.value = 'desc';\n } else if (_sortDir.value === 'desc') {\n _sortKey.value = '';\n _sortDir.value = 'none';\n }\n\n options.onSortChange?.({ direction: _sortDir.value, key: _sortKey.value });\n };\n\n const sortTo = (key: string, direction: SortDirection): void => {\n if (direction === 'none') {\n _sortKey.value = '';\n _sortDir.value = 'none';\n } else {\n _sortKey.value = key;\n _sortDir.value = direction;\n }\n\n options.onSortChange?.({ direction: _sortDir.value, key: _sortKey.value });\n };\n\n return { sortBy, sortedItems, sortState, sortTo };\n};\n","import { computed, type Readable } from '@vielzeug/ripple';\n\nimport { createPaginatedList } from './paginated-list';\nimport { createSelectionControl } from './selection-control';\nimport { createSortControl } from './sort-control';\n\n// ── Types ──────────────────────────────────────────────────────────────────────\n\n/** Sort direction for a column. */\nexport type SortDirection = 'asc' | 'desc' | 'none';\n\n/** Per-column sort state. */\nexport type SortState = {\n /** Current sort direction. */\n direction: SortDirection;\n /** The column key being sorted. Empty string when unsorted. */\n key: string;\n};\n\n/** Column definition for the datagrid. */\nexport type DataGridColumn<T = Record<string, unknown>> = {\n /** Text alignment for the column: `'left'` | `'center'` | `'right'`. Defaults to `'left'`. */\n align?: 'left' | 'center' | 'right';\n /**\n * Custom cell renderer. Receives the row item and returns a string.\n * Use for formatted values (e.g. dates, currency, booleans).\n */\n cell?: (item: T) => string;\n /** Accessible label for the column header. Defaults to `label`. */\n headerLabel?: string;\n /** Column key — must match a property of the row object. */\n key: string;\n /** Display label for the column header. */\n label: string;\n /**\n * Renders the expanded detail panel for a row. When provided on any column,\n * `<ore-datagrid expandable>` shows a toggle button in each row.\n * Receives the full row item and returns an HTML string.\n *\n * @security The returned string is inserted via ore's `raw()` directive — it participates\n * in any sanitizer registered with `setRawSanitizer()`, but if none is registered it is\n * inserted as-is. If any part of the returned markup is derived from untrusted data\n * (row/user content), sanitize it yourself before returning (e.g. with DOMPurify).\n *\n * @example\n * ```js\n * import DOMPurify from 'dompurify';\n *\n * grid.columns = [{\n * key: 'name', label: 'Name',\n * renderExpanded: (row) => DOMPurify.sanitize(`<div class=\"detail\"><b>${row.name}</b>: ${row.bio}</div>`),\n * }];\n * ```\n */\n renderExpanded?: (item: T) => string;\n /** Whether the column can be resized via a drag handle. Defaults to `false`. */\n resizable?: boolean;\n /** Whether the column is sortable. Defaults to `false`. */\n sortable?: boolean;\n /**\n * Custom sort key extractor for client-side sorting.\n * Return a `number` or `string` for comparison.\n * When omitted, the column's `key` property is used as a plain property lookup.\n *\n * @example\n * ```ts\n * { key: 'createdAt', label: 'Date', sortValue: (row) => new Date(row.createdAt).getTime() }\n * ```\n */\n sortValue?: (item: T) => number | string;\n /** Column width (any valid CSS width value, e.g. `'12rem'`). */\n width?: string;\n};\n\n/** Row selection mode. */\nexport type SelectionMode = 'multi' | 'none' | 'single';\n\nexport type DataGridControlOptions<T = Record<string, unknown>> = {\n /** Returns the current column definitions reactively. */\n columns: () => DataGridColumn<T>[];\n /** Returns a unique string key for each row item. */\n getRowKey: (item: T) => string;\n /**\n * Reactive signal of the current row items.\n *\n * For server-side sorting, pass a signal whose value is the pre-sorted result\n * from your server. For client-side sorting, pass a plain signal wrapping your\n * full dataset — the control will sort it automatically via `sortBy()`.\n */\n items: Readable<T[]>;\n /** Called when selection changes. Receives the full set of selected keys. */\n onSelectionChange?: (keys: Set<string>) => void;\n /** Called when sort state changes. */\n onSortChange?: (sort: SortState) => void;\n /** Returns the current page size reactively. Use `0` to disable pagination. */\n pageSize: () => number;\n /** Returns the current selection mode reactively. */\n selectionMode: () => SelectionMode;\n /** `AbortSignal` from the component lifecycle. */\n signal: AbortSignal;\n};\n\nexport type DataGridControl<T = Record<string, unknown>> = {\n /** Deselect all rows. */\n clearSelection(): void;\n /** Current page items (sorted + paginated). Reactive signal. */\n readonly currentPageItems: Readable<T[]>;\n /** Go to an absolute page index. The index is clamped to the valid page range `[0, pageCount - 1]`. */\n goToPage(index: number): void;\n /** Whether there is a next page. Reactive signal. */\n readonly hasNextPage: Readable<boolean>;\n /** Whether there is a previous page. Reactive signal. */\n readonly hasPrevPage: Readable<boolean>;\n /** Whether all current-page rows are selected. */\n isAllSelected(): boolean;\n /** Whether a given row key is selected. */\n isSelected(key: string): boolean;\n /** Navigate to the next page. */\n nextPage(): void;\n /** Total page count. Reactive signal. */\n readonly pageCount: Readable<number>;\n /** Current 0-based page index. Reactive signal. */\n readonly pageIndex: Readable<number>;\n /** Navigate to the previous page. */\n prevPage(): void;\n /** Select all rows on the current page. */\n selectAll(): void;\n /** Current selected row keys. Reactive signal. Returns a snapshot copy — mutating the returned set has no effect on reactive state; use `toggleRow`, `selectAll`, `setSelection`, or `clearSelection` to update selection. */\n readonly selectedKeys: Readable<ReadonlySet<string>>;\n /** All rows whose keys are in `selectedKeys`. Reactive signal. */\n readonly selectedRows: Readable<T[]>;\n /** Set the selection to an explicit set of keys. */\n setSelection(keys: Set<string>): void;\n /** Sort by the given column key — cycles asc → desc → none. */\n sortBy(key: string): void;\n /** Current sort state. Reactive signal. */\n readonly sortState: Readable<SortState>;\n /** Set sort to an explicit key and direction. Passing `'none'` clears the sort. */\n sortTo(key: string, direction: SortDirection): void;\n /** Toggle selection for a single row. */\n toggleRow(key: string): void;\n /** Total item count across all pages. Reactive signal. */\n readonly totalItems: Readable<number>;\n};\n\n// ── Implementation ─────────────────────────────────────────────────────────────\n\n/**\n * Headless datagrid control — sorting, pagination, and row selection.\n *\n * Composed from three focused primitives:\n * - `createSortControl` — client-side sorting with a cycle (asc → desc → none)\n * - `createPaginatedList` — reactive pagination over the sorted items\n * - `createSelectionControl` — single/multi/none row selection\n *\n * All mutable state is exposed as reactive `Reactive` values so\n * consumers can bind directly in templates without manual invalidation.\n *\n * @example\n * ```ts\n * const rows = signal(myItems);\n * const ctrl = createDataGridControl({\n * columns: () => myColumns,\n * items: rows,\n * getRowKey: (item) => item.id,\n * selectionMode: () => 'multi',\n * pageSize: () => 20,\n * signal: lifecycleSignal(onCleanup),\n * });\n * ```\n */\nexport const createDataGridControl = <T = Record<string, unknown>>(\n options: DataGridControlOptions<T>,\n): DataGridControl<T> => {\n // ── Sort ──────────────────────────────────────────────────────────────────\n const sort = createSortControl<T>({\n columns: options.columns,\n items: options.items,\n onSortChange: options.onSortChange,\n });\n\n // ── Pagination ────────────────────────────────────────────────────────────\n // pageSize 0 means \"disabled\" — pass Number.MAX_SAFE_INTEGER so all items fit on one page.\n const _pageSize = computed(() => {\n const ps = options.pageSize();\n\n return ps <= 0 ? Number.MAX_SAFE_INTEGER : ps;\n });\n\n const pagination = createPaginatedList({\n getItems: () => sort.sortedItems.value,\n pageSize: _pageSize,\n });\n\n const totalItems = computed(() => sort.sortedItems.value.length);\n\n // When pageSize is 0 (disabled), bypass pagination and show all items.\n const currentPageItems = computed<T[]>(() =>\n options.pageSize() <= 0 ? sort.sortedItems.value : pagination.pageItems.value,\n );\n\n // Reset to page 0 whenever sort changes.\n const _sortByAndReset = (key: string): void => {\n sort.sortBy(key);\n pagination.reset();\n };\n\n const _sortToAndReset = (key: string, direction: SortDirection): void => {\n sort.sortTo(key, direction);\n pagination.reset();\n };\n\n // ── Selection ─────────────────────────────────────────────────────────────\n const selection = createSelectionControl<T>({\n getRowKey: options.getRowKey,\n onSelectionChange: options.onSelectionChange,\n pageItems: () => pagination.pageItems.value,\n selectionMode: options.selectionMode,\n });\n\n const selectedRows = computed<T[]>(() =>\n options.items.value.filter((item) => selection.selectedKeys.value.has(options.getRowKey(item))),\n );\n\n return {\n clearSelection: selection.clearSelection,\n currentPageItems,\n goToPage: (index: number) => {\n if (!Number.isFinite(index)) return;\n\n pagination.goTo(Math.max(0, index));\n },\n hasNextPage: pagination.hasNext,\n hasPrevPage: pagination.hasPrev,\n isAllSelected: selection.isAllSelected,\n isSelected: selection.isSelected,\n nextPage: pagination.next,\n pageCount: pagination.pageCount,\n pageIndex: pagination.pageIndex,\n prevPage: pagination.prev,\n selectAll: selection.selectAll,\n selectedKeys: selection.selectedKeys,\n selectedRows,\n setSelection: selection.setSelection,\n sortBy: _sortByAndReset,\n sortState: sort.sortState,\n sortTo: _sortToAndReset,\n toggleRow: selection.toggleRow,\n totalItems,\n };\n};\n","// ── Trigger string parser ─────────────────────────────────────────────────────\n\n/**\n * Parses a comma-separated trigger string into a typed array, filtering against\n * a valid set and falling back to `defaults` when the input is empty or invalid.\n *\n * Used by tooltip and popover to normalise their `trigger` prop values.\n *\n * @example\n * ```ts\n * const VALID = new Set(['click', 'hover', 'focus'] as const);\n * parseStringTriggers('hover,focus', VALID, ['click']); // → ['hover', 'focus']\n * parseStringTriggers('', VALID, ['click']); // → ['click']\n * ```\n */\nexport const parseStringTriggers = <T extends string>(\n value: string | null | undefined,\n valid: ReadonlySet<T>,\n defaults: T[],\n): T[] => {\n const parsed = String(value ?? '')\n .split(',')\n .map((t) => t.trim())\n .filter((t): t is T => valid.has(t as T));\n\n return parsed.length > 0 ? parsed : [...defaults];\n};\n","@layer refine.base {\n :host {\n --_bg: var(--carousel-bg, var(--color-canvas));\n --_radius: var(--carousel-radius, var(--rounded-xl));\n --_dot-bg: var(--carousel-dot-bg, var(--color-contrast-300));\n --_dot-active-bg: var(--carousel-dot-active-bg, var(--color-contrast-700));\n\n position: relative;\n display: flex;\n flex-direction: column;\n width: 100%;\n min-height: var(--carousel-min-height, 240px);\n overflow: hidden;\n touch-action: auto;\n outline: none;\n background: var(--_bg);\n border-radius: var(--_radius);\n }\n\n /* ── Track ──────────────────────────────────────────────────────── */\n\n .track {\n position: relative;\n flex: 1 1 auto;\n width: 100%;\n min-height: 0;\n }\n\n /* ── Controls (prev / next) ────────────────────────────────────────────── */\n\n /* Controls live inside the bottom nav bar, right-aligned via margin-inline-start: auto. */\n\n .controls {\n display: flex;\n gap: var(--size-0-5);\n align-items: center;\n margin-inline-start: auto;\n pointer-events: none;\n }\n\n /* Controls rendered standalone (no indicators bar) — needs own positioning + backdrop. */\n :host > .controls {\n position: absolute;\n inset-block-end: var(--size-3);\n inset-inline-end: var(--size-3);\n padding: var(--size-1-5) var(--size-2);\n margin-inline-start: 0;\n background: color-mix(in oklch, var(--color-canvas) 55%, transparent);\n border-radius: var(--rounded-full);\n backdrop-filter: blur(6px);\n }\n\n .nav-btn {\n pointer-events: auto;\n }\n\n /* ── Variant-specific track styles ────────────────────────────────────── */\n\n /* Gallery: flex row, fills host, shows active + two thumbnails */\n :host([variant='gallery']) .track {\n position: absolute;\n inset: 0;\n display: flex;\n flex-direction: row;\n gap: var(--carousel-gallery-gap, var(--size-2));\n align-items: stretch;\n overflow: hidden;\n }\n\n :host([variant='gallery'][orientation='vertical']) .track {\n flex-direction: column;\n align-items: stretch;\n }\n\n /* Marquee: anchor top/bottom for definite height; width:max-content for -50% loop.\n Host clips the overflow. */\n :host([variant='marquee']) {\n overflow: hidden;\n }\n\n :host([variant='marquee']) .track {\n position: absolute;\n inset-block: 0;\n inset-inline-start: 0;\n display: flex;\n flex-direction: row;\n gap: var(--carousel-marquee-gap, var(--size-4));\n align-items: stretch;\n width: max-content;\n animation: carousel-marquee var(--_marquee-duration, 0s) linear infinite;\n }\n\n :host([variant='marquee'][orientation='vertical']) .track {\n inset: 0 0 auto;\n flex-direction: column;\n align-items: stretch;\n width: 100%;\n height: max-content;\n animation-name: carousel-marquee-v;\n }\n\n /* Filmstrip: flex row/column with absolute positioning to fill host */\n :host([variant='filmstrip']) .track {\n position: absolute;\n inset: 0;\n display: flex;\n flex-direction: row;\n gap: var(--carousel-filmstrip-gap, var(--size-2));\n align-items: stretch;\n overflow: hidden;\n }\n\n :host([variant='filmstrip'][orientation='vertical']) .track {\n flex-direction: column;\n width: 100%;\n }\n\n /* ── Vertical orientation ──────────────────────────────────────────────── */\n\n :host([orientation='vertical']) {\n --_slide-translate-before: translateY(-100%);\n --_slide-translate-after: translateY(100%);\n }\n\n :host([orientation='vertical']) .indicators {\n inset-block: 50% auto;\n inset-inline: var(--size-3) auto;\n flex-direction: column;\n width: auto;\n height: max-content;\n padding-block: var(--size-6) var(--size-2);\n padding-inline: var(--size-1-5);\n border-radius: var(--rounded-full);\n transform: translateX(0) translateY(-50%);\n }\n\n :host([orientation='vertical']) .controls {\n flex-direction: column;\n margin-block-start: auto;\n margin-inline-start: 0;\n }\n\n :host([orientation='vertical']) > .controls {\n inset-block-end: var(--size-3);\n inset-inline-end: var(--size-3);\n margin-block-start: 0;\n }\n\n :host([orientation='vertical']) .indicator:not(.indicator-active) {\n width: var(--size-2) !important;\n height: var(--size-2) !important;\n }\n\n :host([orientation='vertical']) .indicator-active {\n width: var(--size-1-5) !important;\n height: var(--size-8);\n }\n\n /* animation properties are inherited from .indicator-active ore-progress::part(fill) below */\n\n /* ── Bottom nav bar: indicators + controls ───────────────────────────── */\n\n /* Floats above the bottom edge, shrinks to content width, centered.\n A frosted backdrop keeps it legible over any image. */\n\n .indicators {\n position: absolute;\n inset-block-end: var(--size-3);\n inset-inline: 50%;\n display: flex;\n flex-direction: row;\n gap: var(--size-1-5);\n align-items: center;\n width: max-content;\n padding: var(--size-1-5) var(--size-2) var(--size-1-5) var(--size-6);\n pointer-events: none;\n background: color-mix(in oklch, var(--color-canvas) 55%, transparent);\n border-radius: var(--rounded-full);\n backdrop-filter: blur(6px);\n transform: translateX(-50%);\n }\n\n .indicator {\n display: block;\n flex-shrink: 0;\n padding: 0;\n pointer-events: auto;\n cursor: pointer;\n background: none;\n border: none;\n transition: opacity var(--transition-fast);\n }\n\n .indicator > ore-progress {\n display: block;\n width: 100%;\n height: 100%;\n pointer-events: none;\n }\n\n /* Inactive indicator: small circle */\n .indicator:not(.indicator-active) {\n width: var(--size-2) !important;\n height: var(--size-2) !important;\n overflow: hidden;\n border-radius: var(--rounded-full);\n }\n\n /* Active indicator: wider pill (progress bar) */\n .indicator-active {\n width: var(--size-8) !important;\n\n --progress-track-bg: color-mix(in oklch, var(--_dot-bg) 60%, transparent);\n }\n\n .indicator:focus-visible {\n outline: var(--border) solid currentcolor;\n outline-offset: 2px;\n }\n\n .indicator:hover {\n opacity: 0.8;\n }\n\n .indicator ore-progress::part(fill) {\n transition: width var(--transition-normal);\n }\n\n .indicator-active ore-progress::part(fill) {\n animation-name: var(--carousel-animation-name, none);\n animation-duration: calc(var(--carousel-timeout, 4000) * 1ms);\n animation-timing-function: var(--ease-linear);\n animation-fill-mode: forwards;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n :host {\n --carousel-transition-duration: 0s;\n }\n\n :host([variant='marquee']) .track,\n :host([variant='marquee'][orientation='vertical']) .track {\n animation: none;\n }\n}\n\n@keyframes carousel-fill {\n from {\n width: 0%;\n }\n\n to {\n width: 100%;\n }\n}\n\n@keyframes carousel-fill-v {\n from {\n height: 0%;\n }\n\n to {\n height: 100%;\n }\n}\n\n@keyframes carousel-marquee {\n from {\n transform: translateX(0);\n }\n\n to {\n transform: translateX(-50%);\n }\n}\n\n@keyframes carousel-marquee-v {\n from {\n transform: translateY(0);\n }\n\n to {\n transform: translateY(-50%);\n }\n}\n","/* ── Default: translate in/out ───────────────────────────────────────────── */\n:host {\n position: absolute;\n inset: 0;\n display: block;\n width: 100%;\n height: 100%;\n overflow: hidden;\n pointer-events: none;\n opacity: 0;\n transform: var(--_slide-translate-after, translateX(100%));\n transition:\n transform var(--carousel-transition-duration, 0.35s) var(--ease-move),\n opacity var(--carousel-transition-duration, 0.35s) var(--ease-move);\n}\n\n:host([data-before]) {\n transform: var(--_slide-translate-before, translateX(-100%));\n}\n\n:host([data-active]) {\n pointer-events: auto;\n opacity: 1;\n transform: translate(0, 0);\n}\n\n/* ── Fade variant ────────────────────────────────────────────────────────── */\n:host([data-variant='fade']) {\n transform: none;\n transition: opacity var(--carousel-transition-duration, 0.35s) var(--ease-move);\n}\n\n/* ── Filmstrip variant — shared ──────────────────────────────────────────── */\n:host([data-variant='filmstrip']) {\n position: relative;\n inset: auto;\n flex-shrink: 0;\n align-self: stretch;\n pointer-events: auto;\n border-radius: var(--carousel-radius, var(--rounded-xl));\n opacity: 1;\n transform: none;\n transition:\n flex var(--carousel-transition-duration, 0.35s) var(--ease-move),\n opacity var(--carousel-transition-duration, 0.35s) var(--ease-move);\n}\n\n/* ── Filmstrip variant (horizontal) ──────────────────────────────────────── */\n:host([data-variant='filmstrip'][data-orientation='horizontal']) {\n flex: 0 0 var(--carousel-filmstrip-inactive, var(--size-16));\n width: auto;\n min-width: var(--carousel-filmstrip-inactive, var(--size-16));\n height: 100%;\n}\n\n:host([data-variant='filmstrip'][data-orientation='horizontal'][data-active]) {\n flex: 1 1 0;\n}\n\n/* ── Filmstrip variant (vertical) ────────────────────────────────────────── */\n:host([data-variant='filmstrip'][data-orientation='vertical']) {\n flex: 0 0 var(--carousel-filmstrip-inactive, var(--size-10));\n width: 100%;\n height: auto;\n min-height: var(--carousel-filmstrip-inactive, var(--size-10));\n}\n\n:host([data-variant='filmstrip'][data-orientation='vertical'][data-active]) {\n flex: 1 1 0;\n}\n\n/* ── Gallery variant — shared base ───────────────────────────────────────── */\n:host([data-variant='gallery']) {\n display: none;\n}\n\n:host([data-variant='gallery'][data-gallery-visible]) {\n position: relative;\n inset: auto;\n display: block;\n align-self: stretch;\n overflow: hidden;\n pointer-events: auto;\n border-radius: var(--carousel-radius, var(--rounded-xl));\n opacity: 0.5;\n transform: none;\n transition:\n flex var(--carousel-transition-duration, 0.35s) var(--ease-move),\n opacity var(--carousel-transition-duration, 0.35s) var(--ease-move);\n}\n\n:host([data-variant='gallery'][data-gallery-visible][data-active]) {\n opacity: 1;\n}\n\n/* ── Gallery variant (horizontal) ────────────────────────────────────────── */\n:host([data-variant='gallery'][data-orientation='horizontal'][data-gallery-visible]) {\n flex: 0 0 var(--carousel-gallery-thumbnail, var(--size-24));\n flex-shrink: 0;\n width: auto;\n min-width: var(--carousel-gallery-thumbnail, var(--size-24));\n height: 100%;\n}\n\n:host([data-variant='gallery'][data-orientation='horizontal'][data-gallery-visible][data-active]) {\n flex: 1 1 0;\n}\n\n/* ── Gallery variant (vertical) ──────────────────────────────────────────── */\n:host([data-variant='gallery'][data-orientation='vertical'][data-gallery-visible]) {\n flex: 1 1 0;\n width: 100%;\n height: auto;\n}\n\n:host([data-variant='gallery'][data-orientation='vertical'][data-gallery-visible][data-active]) {\n flex: 4 1 0;\n}\n\n/* ── Marquee variant ─────────────────────────────────────────────────────── */\n:host([data-variant='marquee']) {\n position: relative;\n inset: auto;\n flex: 0 0 auto;\n pointer-events: auto;\n opacity: 1;\n transform: none;\n transition: none;\n}\n\n:host([data-variant='marquee'][data-orientation='horizontal']) {\n width: auto;\n height: 100%;\n}\n\n:host([data-variant='marquee'][data-orientation='vertical']) {\n width: 100%;\n height: auto;\n}\n\n:host([data-variant='marquee'][data-marquee-clone]) {\n pointer-events: none;\n user-select: none;\n}\n\n::slotted(*) {\n max-width: 100%;\n}\n","import { define, html } from '@vielzeug/ore';\n\nimport slideStyles from './carousel-slide.css?inline';\n\nexport const CAROUSEL_SLIDE_TAG = 'ore-carousel-slide' as const;\n\ndefine(CAROUSEL_SLIDE_TAG, {\n props: {},\n setup(_props, { bind }) {\n bind({\n attr: {\n 'aria-roledescription': () => 'slide',\n role: () => 'group',\n },\n });\n\n return html`<slot></slot>`;\n },\n styles: [slideStyles],\n});\n","import { define, html, prop } from '@vielzeug/ore';\nimport { computed, signal, watch } from '@vielzeug/ripple';\n\nimport type { ThemeColor } from '../../types';\n\nimport { warn } from '../../_dev';\nimport '../../content/icon/icon';\nimport '../../feedback/progress/progress';\nimport { announce, createSwipeControl } from '../../headless';\nimport componentStyles from './carousel.css?inline';\nimport './carousel-slide';\n\nexport { CAROUSEL_SLIDE_TAG } from './carousel-slide';\n\n// ── Types ──────────────────────────────────────────────────────────────────────\n\nexport type CarouselOrientation = 'horizontal' | 'vertical';\nexport type CarouselVariant = 'default' | 'fade' | 'filmstrip' | 'gallery' | 'marquee';\n\nexport type OreCarouselEvents = {\n /** Fired when the active slide changes. */\n change: { index: number };\n};\n\nexport type OreCarouselProps = {\n /**\n * Whether to advance slides automatically. Defaults to `false`.\n * Opt in explicitly — autoplay on by default is a WCAG 2.1 SC 2.2.2 violation for many use cases.\n */\n autoplay?: boolean;\n /** Interval in milliseconds between automatic slide advances. Defaults to `5000`. */\n 'autoplay-interval'?: number;\n /** Theme color passed to the prev/next navigation buttons. */\n color?: ThemeColor;\n /** Accessible label for the carousel region. */\n label?: string;\n /**\n * Whether the carousel loops from the last slide back to the first. Defaults to `true`.\n *\n * > **Note for `marquee` variant:** `loop=\"false\"` runs the scroll animation once then stops,\n * > rather than controlling navigation wrap-around (marquee navigation always loops).\n * > If you intend to stop wrapping navigation in another variant, use `loop` there as expected.\n */\n loop?: boolean;\n /**\n * Duration in seconds for one full marquee loop cycle. Defaults to `10`.\n * Shorter values = faster scroll; longer values = slower scroll.\n */\n 'marquee-duration'?: number;\n /** Carousel orientation. Defaults to `'horizontal'`. */\n orientation?: CarouselOrientation;\n /** Show next/prev navigation buttons. Defaults to `true`. */\n 'show-controls'?: boolean;\n /** Show dot/indicator navigation. Defaults to `true`. */\n 'show-indicators'?: boolean;\n /** Index of the currently active slide (zero-based). Defaults to `0`. */\n 'slide-index'?: number;\n /**\n * Layout variant.\n * - `'default'` — slides translate in/out (default)\n * - `'fade'` — slides crossfade; no movement\n * - `'filmstrip'` — all slides visible side-by-side; active expands\n * - `'gallery'` — active slide fills the majority; adjacent slides show as thumbnails\n * - `'marquee'` — continuous auto-scroll ticker; `loop` controls whether it repeats\n */\n variant?: CarouselVariant;\n};\n\n// ── Internal marquee instance type ────────────────────────────────────────────\n\ntype MarqueeInstance = {\n cleanup: () => void;\n seekTo: (index: number, slideSnapshot: HTMLElement[]) => void;\n};\n\n/**\n * An accessible, keyboard-navigable carousel / slideshow with optional\n * autoplay, swipe support, and indicator dots.\n *\n * Place `<ore-carousel-slide>` elements as direct children.\n *\n * @element ore-carousel\n * @element ore-carousel-slide - Child element for individual slides\n *\n * @attr {string} color - Theme color for navigation buttons: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {boolean} autoplay - Advance slides automatically (default false)\n * @attr {number} autoplay-interval - Milliseconds between automatic advances (default 5000)\n * @attr {string} label - Accessible label for the carousel region\n * @attr {boolean} loop - Loop from last slide to first (default true); in marquee mode: repeat vs run-once\n * @attr {string} orientation - 'horizontal' (default) | 'vertical'\n * @attr {string} variant - 'default' | 'fade' | 'filmstrip' | 'gallery' | 'marquee'\n * @attr {boolean} show-controls - Show prev/next buttons (default true)\n * @attr {boolean} show-indicators - Show indicator dots (default true)\n * @attr {number} slide-index - Active slide index (zero-based, default 0)\n * @attr {number} marquee-duration - Loop cycle duration in seconds for marquee variant (default 10)\n *\n * @fires change - Fires when the active slide changes. detail: { index: number }\n *\n * @slot - Place `<ore-carousel-slide>` elements here\n *\n * @cssprop --carousel-bg - Slide area background\n * @cssprop --carousel-radius - Border radius of the carousel\n * @cssprop --carousel-dot-bg - Inactive indicator color (default: var(--color-contrast-300))\n * @cssprop --carousel-dot-active-bg - Active indicator / fill color (default: var(--color-contrast-700))\n * @cssprop --carousel-transition-duration - Slide transition duration (default 0.35s; 0s under prefers-reduced-motion). Also controls marquee seek animation duration.\n * @cssprop --carousel-min-height - Minimum height when no explicit height is set (default 240px)\n * @cssprop --carousel-filmstrip-inactive - Width (horizontal) or height (vertical) of inactive slides in filmstrip mode\n * @cssprop --carousel-filmstrip-gap - Gap between slides in filmstrip mode\n * @cssprop --carousel-gallery-thumbnail - Width (horizontal) or height (vertical) of thumbnail slides in gallery mode (default var(--size-24))\n * @cssprop --carousel-gallery-gap - Gap between slides in gallery mode (default var(--size-2))\n * @cssprop --carousel-marquee-gap - Gap between slides in marquee mode (default var(--size-4))\n *\n * @part track - The scrolling slide track element\n * @part controls - The prev/next button container\n * @part indicators - The indicator dots container\n * @part prev-btn - The previous-slide button\n * @part next-btn - The next-slide button\n *\n * @example\n * ```html\n * <ore-carousel label=\"Product highlights\" loop>\n * <ore-carousel-slide>Slide 1</ore-carousel-slide>\n * <ore-carousel-slide>Slide 2</ore-carousel-slide>\n * <ore-carousel-slide>Slide 3</ore-carousel-slide>\n * </ore-carousel>\n * ```\n */\nexport const CAROUSEL_TAG = 'ore-carousel' as const;\n\n// ── Slide-state sync helpers ──────────────────────────────────────────────────\n// Each function handles exactly one variant's attribute bookkeeping.\n// Called from a dispatch table in syncActiveState.\n\nconst syncDefaultSlides = (slides: HTMLElement[], current: number): void => {\n const count = slides.length;\n\n slides.forEach((slide, i) => {\n const active = i === current;\n\n slide.toggleAttribute('data-active', active);\n slide.setAttribute('aria-hidden', String(!active));\n slide.setAttribute('aria-label', slide.getAttribute('aria-label') ?? `Slide ${i + 1} of ${count}`);\n slide.removeAttribute('data-gallery-visible');\n slide.toggleAttribute('data-before', i < current);\n slide.toggleAttribute('data-after', i > current);\n });\n};\n\nconst syncFilmstripSlides = (slides: HTMLElement[], current: number): void => {\n const count = slides.length;\n\n slides.forEach((slide, i) => {\n const active = i === current;\n\n slide.toggleAttribute('data-active', active);\n slide.setAttribute('aria-hidden', String(!active));\n slide.setAttribute('aria-label', slide.getAttribute('aria-label') ?? `Slide ${i + 1} of ${count}`);\n slide.removeAttribute('data-gallery-visible');\n slide.removeAttribute('data-before');\n slide.removeAttribute('data-after');\n });\n};\n\nconst syncGallerySlides = (slides: HTMLElement[], current: number): void => {\n const count = slides.length;\n\n slides.forEach((slide, i) => {\n const active = i === current;\n const isPrev = current > 0 && i === current - 1;\n const isNext = current < count - 1 && i === current + 1;\n\n slide.toggleAttribute('data-active', active);\n slide.setAttribute('aria-hidden', String(!active));\n slide.setAttribute('aria-label', slide.getAttribute('aria-label') ?? `Slide ${i + 1} of ${count}`);\n slide.removeAttribute('data-before');\n slide.removeAttribute('data-after');\n slide.toggleAttribute('data-gallery-visible', active || isPrev || isNext);\n });\n};\n\nconst syncMarqueeSlides = (slides: HTMLElement[], current: number): void => {\n slides.forEach((slide, i) => {\n slide.toggleAttribute('data-active', i === current);\n slide.setAttribute('aria-hidden', 'false');\n slide.removeAttribute('data-before');\n slide.removeAttribute('data-after');\n slide.removeAttribute('data-gallery-visible');\n });\n};\n\n// ── ore-carousel ──────────────────────────────────────────────────────────────\n\ndefine<OreCarouselProps, OreCarouselEvents>(CAROUSEL_TAG, {\n props: {\n autoplay: prop.bool(false),\n 'autoplay-interval': prop.number(5000),\n color: prop.string<ThemeColor>(),\n label: prop.string('Carousel'),\n loop: prop.bool(true),\n 'marquee-duration': prop.number(10),\n orientation: prop.string<CarouselOrientation>('horizontal'),\n 'show-controls': prop.bool(true),\n 'show-indicators': prop.bool(true),\n 'slide-index': prop.number(0),\n variant: prop.string<CarouselVariant>('default'),\n },\n\n setup(props, { bind, el, emit, onMounted }) {\n // ── State ────────────────────────────────────────────────────────────────\n\n const activeIndex = signal<number>(props['slide-index'].value ?? 0);\n const isMarquee = computed(() => props.variant.value === 'marquee');\n let autoplayTimer: ReturnType<typeof setInterval> | null = null;\n\n // Slide cache — populated immediately, refreshed on slotchange.\n let slides: HTMLElement[] = Array.from(el.querySelectorAll<HTMLElement>(':scope > ore-carousel-slide'));\n const slideCount = signal(slides.length);\n\n const refreshSlides = (): void => {\n slides = Array.from(el.querySelectorAll<HTMLElement>(':scope > ore-carousel-slide'));\n slideCount.value = slides.length;\n };\n\n const isHorizontal = computed(() => props.orientation.value !== 'vertical');\n const looping = computed(() => props.loop.value !== false);\n const showControls = computed(() => props['show-controls'].value !== false);\n const showIndicators = computed(() => props['show-indicators'].value !== false);\n\n const canGoPrev = computed(() => looping.value || activeIndex.value > 0);\n const canGoNext = computed(() => looping.value || activeIndex.value < slideCount.value - 1);\n\n // ── Navigation ───────────────────────────────────────────────────────────\n\n // marqueeInstance is set in onMounted; accessed here via module-level ref\n // stored on the setup closure. No separate side-channel variable needed.\n let marqueeInstance: MarqueeInstance | null = null;\n\n const goTo = (index: number, announce_: boolean = true): void => {\n const count = slideCount.value;\n\n if (count === 0) return;\n\n const next = looping.value ? ((index % count) + count) % count : Math.max(0, Math.min(index, count - 1));\n\n if (next === activeIndex.value) return;\n\n activeIndex.value = next;\n el.setAttribute('slide-index', String(next));\n emit('change', { index: next });\n // Pass current slides snapshot so seekTo never reads a stale closure.\n marqueeInstance?.seekTo(next, slides);\n\n if (announce_) {\n announce(slides[next]?.getAttribute('aria-label') ?? `Slide ${next + 1} of ${count}`);\n }\n };\n\n const prev = (): void => goTo(activeIndex.value - 1);\n const next = (): void => goTo(activeIndex.value + 1);\n\n // ── Sync prop → state ────────────────────────────────────────────────────\n\n watch(props['slide-index'], (v) => {\n if (typeof v === 'number' && v !== activeIndex.value) goTo(v, false);\n });\n\n // ── Sync variant + orientation → slides ──────────────────────────────────\n\n const syncSlideVariants = (): void => {\n const variant = props.variant.value ?? 'default';\n const orientation = props.orientation.value ?? 'horizontal';\n\n slides.forEach((slide) => {\n slide.setAttribute('data-variant', variant);\n slide.setAttribute('data-orientation', orientation);\n });\n };\n\n watch(\n computed(() => ({ orientation: props.orientation.value, variant: props.variant.value })),\n syncSlideVariants,\n { immediate: true },\n );\n\n // ── Sync active index → slides — dispatch table ───────────────────────────\n\n const syncTable: Record<CarouselVariant, (slides: HTMLElement[], current: number) => void> = {\n default: syncDefaultSlides,\n fade: syncDefaultSlides,\n filmstrip: syncFilmstripSlides,\n gallery: syncGallerySlides,\n marquee: syncMarqueeSlides,\n };\n\n const syncActiveState = (): void => {\n const variant = (props.variant.value ?? 'default') as CarouselVariant;\n\n syncTable[variant](slides, activeIndex.value);\n };\n\n watch(activeIndex, syncActiveState, { immediate: true });\n\n // ── Autoplay ─────────────────────────────────────────────────────────────\n\n const startAutoplay = (): void => {\n if (autoplayTimer !== null) return;\n\n autoplayTimer = setInterval(next, props['autoplay-interval'].value ?? 5000);\n };\n\n const stopAutoplay = (): void => {\n if (autoplayTimer !== null) {\n clearInterval(autoplayTimer);\n autoplayTimer = null;\n }\n };\n\n watch(\n computed(() => ({ enabled: props.autoplay.value, interval: props['autoplay-interval'].value })),\n ({ enabled }) => {\n stopAutoplay();\n\n if (enabled) startAutoplay();\n },\n );\n\n // ── Keyboard navigation ──────────────────────────────────────────────────\n\n const handleKeydown = (e: KeyboardEvent): void => {\n const isH = isHorizontal.value;\n const prevKey = isH ? 'ArrowLeft' : 'ArrowUp';\n const nextKey = isH ? 'ArrowRight' : 'ArrowDown';\n\n if (e.key === prevKey) {\n e.preventDefault();\n prev();\n } else if (e.key === nextKey) {\n e.preventDefault();\n next();\n } else if (e.key === 'Home') {\n e.preventDefault();\n goTo(0);\n } else if (e.key === 'End') {\n e.preventDefault();\n goTo(slideCount.value - 1);\n }\n };\n\n // ── Swipe ────────────────────────────────────────────────────────────────\n\n const swipe = createSwipeControl({\n axis: () => (isHorizontal.value ? 'x' : 'y'),\n onCommit: (detail) => {\n if (detail.distance < 0) next();\n else prev();\n },\n threshold: () => 48,\n });\n\n // ── Host bindings ────────────────────────────────────────────────────────\n\n bind({\n attr: {\n 'aria-label': () => props.label.value ?? 'Carousel',\n 'aria-roledescription': () => 'carousel',\n orientation: () => props.orientation.value ?? 'horizontal',\n role: () => 'region',\n style: () => `touch-action:${isHorizontal.value ? 'pan-y' : 'pan-x'}`,\n variant: () => props.variant.value ?? 'default',\n },\n on: {\n focusin: () => {\n stopAutoplay();\n },\n focusout: () => {\n if (props.autoplay.value) startAutoplay();\n },\n keydown: handleKeydown,\n pointercancel: (e: PointerEvent) => swipe.handlePointerCancel(e),\n pointerdown: (e: PointerEvent) => {\n const path = e.composedPath();\n const onButton = path.some(\n (n) =>\n n instanceof HTMLElement &&\n (n.tagName === 'BUTTON' || n.tagName === 'ORE-BUTTON' || n.tagName === 'ORE-PROGRESS'),\n );\n\n if (!onButton) swipe.handlePointerDown(e);\n },\n pointerenter: () => {\n stopAutoplay();\n },\n pointerleave: () => {\n if (props.autoplay.value) startAutoplay();\n },\n pointermove: (e: PointerEvent) => swipe.handlePointerMove(e),\n pointerup: (e: PointerEvent) => swipe.handlePointerUp(e),\n },\n });\n\n // ── Marquee ───────────────────────────────────────────────────────────────\n // Clones slides for a seamless loop. Seek uses WAAPI when available\n // (all modern browsers) so it can be cancelled cleanly. Falls back to\n // instant negative-delay repositioning in environments without WAAPI\n // (e.g. jsdom in tests).\n\n const setupMarquee = (track: HTMLElement): MarqueeInstance => {\n const orientation = props.orientation.value ?? 'horizontal';\n const horizontal = orientation !== 'vertical';\n\n if (isMarquee.value && props.loop.value === false) {\n warn(\n 'ore-carousel: loop=\"false\" on the marquee variant stops the scroll animation rather than ' +\n 'disabling navigation wrap-around. Navigation in marquee always loops. ' +\n 'This is different from loop=\"false\" on other variants.',\n );\n }\n\n const clones = slides.map((s) => {\n const clone = s.cloneNode(true) as HTMLElement;\n\n clone.setAttribute('aria-hidden', 'true');\n clone.setAttribute('data-variant', 'marquee');\n clone.setAttribute('data-orientation', orientation);\n clone.setAttribute('data-marquee-clone', '');\n track.appendChild(clone);\n\n return clone;\n });\n\n track.style.setProperty('--_marquee-duration', `${props['marquee-duration'].value ?? 10}s`);\n\n if (!looping.value) {\n track.style.setProperty('animation-iteration-count', '1');\n }\n\n let isHovered = false;\n\n const pause = (): void => {\n isHovered = true;\n track.style.setProperty('animation-play-state', 'paused');\n };\n\n const resume = (): void => {\n isHovered = false;\n track.style.removeProperty('animation-play-state');\n };\n\n // mouseenter/mouseleave fire only when the pointer crosses the host\n // boundary — never when moving between children (e.g. onto controls).\n // This means clicking buttons never accidentally resumes the animation.\n el.addEventListener('mouseenter', pause);\n el.addEventListener('mouseleave', resume);\n\n // ── Seek ──────────────────────────────────────────────────────────────\n // Smoothly slides to the target position using a CSS transition on the\n // inline transform (the CSS keyframe animation is paused throughout so\n // there is no compositing conflict). On transitionend, switches back to\n // the keyframe animation via a negative animation-delay.\n\n let seekTimer: ReturnType<typeof setTimeout> | null = null;\n\n const seekTo = (index: number, slideSnapshot: HTMLElement[]): void => {\n const slide = slideSnapshot[index];\n\n if (!slide) return;\n\n const targetOffset = horizontal ? slide.offsetLeft : slide.offsetTop;\n const halfSize = horizontal ? track.scrollWidth / 2 : track.scrollHeight / 2;\n const cycleDuration = props['marquee-duration'].value ?? 10;\n const delay = halfSize > 0 ? -((targetOffset / halfSize) * cycleDuration) : 0;\n\n // Cancel any in-flight seek timer.\n if (seekTimer !== null) {\n clearTimeout(seekTimer);\n seekTimer = null;\n // Snap the previous transition to its end state immediately.\n track.style.removeProperty('transition');\n }\n\n // No layout (jsdom): instant seek with no visual transition.\n if (halfSize === 0) {\n track.style.setProperty('animation-delay', `${delay}s`);\n\n if (!isHovered) {\n track.style.removeProperty('animation-play-state');\n }\n\n return;\n }\n\n const seekMs =\n parseFloat(getComputedStyle(el).getPropertyValue('--carousel-transition-duration') || '0.35') * 1000 || 350;\n\n const targetTransform = horizontal ? `translateX(-${targetOffset}px)` : `translateY(-${targetOffset}px)`;\n\n // 1. Read the current visual position from the live animation, then\n // kill the animation entirely so nothing else drives transform.\n // getBoundingClientRect() flushes layout so the matrix is current.\n void track.getBoundingClientRect();\n\n const computedTransform = getComputedStyle(track).transform;\n const matrixValues = computedTransform\n .match(/matrix\\(([^)]+)\\)/)?.[1]\n .split(',')\n .map(Number);\n const frozenOffset = horizontal ? (matrixValues?.[4] ?? 0) : (matrixValues?.[5] ?? 0);\n const frozenTransform = horizontal ? `translateX(${frozenOffset}px)` : `translateY(${frozenOffset}px)`;\n\n // Stop the CSS animation — inline transform is now the sole driver.\n track.style.setProperty('animation', 'none');\n track.style.setProperty('transform', frozenTransform);\n\n // 2. Next frame: apply transition and slide to target.\n requestAnimationFrame(() => {\n track.style.setProperty('transition', `transform ${seekMs}ms ease-in-out`);\n track.style.setProperty('transform', targetTransform);\n\n // 3. After the transition completes, restore the keyframe animation\n // at the correct position via negative animation-delay.\n seekTimer = setTimeout(() => {\n seekTimer = null;\n track.style.removeProperty('transition');\n track.style.removeProperty('transform');\n track.style.removeProperty('animation');\n track.style.setProperty('animation-delay', `${delay}s`);\n\n if (isHovered) {\n track.style.setProperty('animation-play-state', 'paused');\n }\n }, seekMs);\n });\n };\n\n return {\n cleanup: () => {\n if (seekTimer !== null) clearTimeout(seekTimer);\n\n seekTimer = null;\n clones.forEach((c) => c.remove());\n track.style.removeProperty('transition');\n track.style.removeProperty('transform');\n track.style.removeProperty('animation');\n track.style.removeProperty('--_marquee-duration');\n track.style.removeProperty('animation-iteration-count');\n track.style.removeProperty('animation-delay');\n track.style.removeProperty('animation-play-state');\n el.removeEventListener('mouseenter', pause);\n el.removeEventListener('mouseleave', resume);\n },\n seekTo,\n };\n };\n\n // ── Lifecycle ────────────────────────────────────────────────────────────\n\n onMounted(() => {\n const shadowRoot = el.shadowRoot!;\n const track = shadowRoot.querySelector<HTMLElement>('.track')!;\n const slot = shadowRoot.querySelector<HTMLSlotElement>('slot')!;\n\n // slotchange replaces MutationObserver — fires exactly when assigned\n // nodes change, scoped to this component's slot, no polling overhead.\n const onSlotChange = (): void => {\n refreshSlides();\n syncSlideVariants();\n syncActiveState();\n\n if (isMarquee.value) {\n marqueeInstance?.cleanup();\n marqueeInstance = setupMarquee(track);\n }\n };\n\n slot.addEventListener('slotchange', onSlotChange);\n\n watch(\n computed(() => ({\n duration: props['marquee-duration'].value,\n isMarquee: isMarquee.value,\n loop: props.loop.value,\n orientation: props.orientation.value,\n })),\n ({ isMarquee: active }) => {\n marqueeInstance?.cleanup();\n marqueeInstance = active ? setupMarquee(track) : null;\n },\n { immediate: true },\n );\n\n if (props.autoplay.value) {\n startAutoplay();\n }\n\n return () => {\n stopAutoplay();\n swipe.dispose();\n slot.removeEventListener('slotchange', onSlotChange);\n marqueeInstance?.cleanup();\n };\n });\n\n // ── Template ─────────────────────────────────────────────────────────────\n\n const focusIndicator = (index: number): void => {\n const dot = el.shadowRoot?.querySelector<HTMLElement>(`.indicator[data-index=\"${index}\"]`);\n\n dot?.focus();\n };\n\n const handleIndicatorKeydown = (e: KeyboardEvent, i: number): void => {\n const count = slideCount.value;\n let target: number | undefined;\n\n switch (e.key) {\n case 'ArrowDown':\n case 'ArrowRight':\n target = (i + 1) % count;\n break;\n case 'ArrowLeft':\n case 'ArrowUp':\n target = (i - 1 + count) % count;\n break;\n case 'End':\n target = count - 1;\n break;\n case 'Home':\n target = 0;\n break;\n default:\n return;\n }\n\n e.preventDefault();\n goTo(target);\n focusIndicator(target);\n };\n\n const renderControls = () =>\n showControls.value\n ? html`<div class=\"controls\" part=\"controls\">\n <ore-button\n class=\"nav-btn prev-btn\"\n part=\"prev-btn\"\n variant=\"ghost\"\n :color=${() => props.color.value}\n rounded\n icon-only\n aria-label=\"Previous slide\"\n :disabled=${() => (!canGoPrev.value ? true : undefined)}\n @click=${(e: Event) => {\n e.stopPropagation();\n prev();\n }}>\n <ore-icon\n :name=${() => (isHorizontal.value ? 'chevron-left' : 'chevron-up')}\n size=\"16\"\n stroke-width=\"2\"\n aria-hidden=\"true\"></ore-icon>\n </ore-button>\n <ore-button\n class=\"nav-btn next-btn\"\n part=\"next-btn\"\n variant=\"ghost\"\n :color=${() => props.color.value}\n rounded\n icon-only\n aria-label=\"Next slide\"\n :disabled=${() => (!canGoNext.value ? true : undefined)}\n @click=${(e: Event) => {\n e.stopPropagation();\n next();\n }}>\n <ore-icon\n :name=${() => (isHorizontal.value ? 'chevron-right' : 'chevron-down')}\n size=\"16\"\n stroke-width=\"2\"\n aria-hidden=\"true\"></ore-icon>\n </ore-button>\n </div>`\n : html``;\n\n return html`\n <div class=\"track\" part=\"track\" :aria-live=${() => (props.autoplay.value ? 'off' : 'polite')}>\n <slot></slot>\n </div>\n\n ${() =>\n showIndicators.value && slideCount.value > 1 && !isMarquee.value\n ? html`<div class=\"indicators\" part=\"indicators\" role=\"tablist\" aria-label=\"Slide indicators\">\n ${() =>\n Array.from(\n { length: slideCount.value },\n (_, i) =>\n html`<button\n type=\"button\"\n role=\"tab\"\n data-index=\"${i}\"\n :class=${() =>\n `indicator${!isMarquee.value && i === activeIndex.value ? ' indicator-active' : ''}`}\n :aria-selected=${() => String(!isMarquee.value && i === activeIndex.value)}\n :tabindex=${() => (!isMarquee.value && i === activeIndex.value ? '0' : '-1')}\n aria-label=\"${`Go to slide ${i + 1}`}\"\n @click=${() => goTo(i)}\n @keydown=${(e: KeyboardEvent) => handleIndicatorKeydown(e, i)}>\n <ore-progress\n aria-hidden=\"true\"\n tabindex=\"-1\"\n :color=${() => props.color.value}\n :type=${() => (isHorizontal.value ? 'linear' : 'vertical')}\n :value=${() => (!isMarquee.value && i === activeIndex.value ? 100 : 0)}\n :style=${() => {\n const fillAnim = isHorizontal.value ? 'carousel-fill' : 'carousel-fill-v';\n\n return `--carousel-timeout:${props['autoplay-interval'].value ?? 5000};--carousel-animation-name:${!isMarquee.value && i === activeIndex.value && props.autoplay.value ? fillAnim : 'none'}`;\n }}></ore-progress>\n </button>`,\n )}\n ${renderControls}\n </div>`\n : html`${renderControls}`}\n `;\n },\n styles: [componentStyles],\n});\n","@layer refine.base {\n :host {\n display: inline-flex;\n flex-direction: row;\n }\n\n /* Overlap avatars, latest first */\n ::slotted(ore-avatar) {\n --avatar-border: var(--border-2) solid var(--color-canvas);\n\n margin-left: calc(var(--avatar-group-overlap, -0.75rem));\n }\n\n ::slotted(ore-avatar:first-child) {\n margin-left: 0;\n }\n\n :host([dir='rtl']) ::slotted(ore-avatar),\n :host(:dir(rtl)) ::slotted(ore-avatar) {\n margin-right: calc(var(--avatar-group-overlap, -0.75rem));\n margin-left: 0;\n }\n\n :host([dir='rtl']) ::slotted(ore-avatar:first-child),\n :host(:dir(rtl)) ::slotted(ore-avatar:first-child) {\n margin-right: 0;\n }\n\n ::slotted(ore-avatar[data-avatar-group-hidden]) {\n display: none;\n }\n\n .overflow-badge {\n --_size: var(--avatar-size, var(--size-10));\n\n box-sizing: border-box;\n display: inline-flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n width: var(--_size);\n height: var(--_size);\n margin-left: calc(var(--avatar-group-overlap, -0.75rem));\n font-size: var(--text-xs);\n font-weight: var(--font-semibold);\n color: var(--color-contrast-700);\n user-select: none;\n background: var(--color-contrast-200);\n border: var(--border-2) solid var(--color-canvas);\n border-radius: var(--rounded-full);\n }\n\n :host([dir='rtl']) .overflow-badge,\n :host(:dir(rtl)) .overflow-badge {\n margin-right: calc(var(--avatar-group-overlap, -0.75rem));\n margin-left: 0;\n }\n}\n","@layer refine.base {\n :host {\n --_bg: var(--avatar-bg, var(--_theme-backdrop, var(--color-contrast-200)));\n --_color: var(--avatar-color, var(--_theme-base, var(--color-contrast-700)));\n --_radius: var(--avatar-radius, var(--rounded-full));\n --_font-weight: var(--avatar-font-weight, var(--font-semibold));\n --_border: var(--avatar-border, none);\n --_border-color: var(--avatar-border-color, var(--color-canvas));\n --_size: var(--avatar-size, var(--size-10));\n --_font-size: var(--avatar-font-size, var(--text-sm));\n\n position: relative;\n display: inline-flex;\n flex-shrink: 0;\n }\n\n .avatar {\n box-sizing: border-box;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--_size);\n height: var(--_size);\n overflow: hidden;\n font-size: var(--_font-size);\n font-weight: var(--_font-weight);\n line-height: 1;\n color: var(--_color);\n text-transform: uppercase;\n user-select: none;\n background: var(--_bg);\n border: var(--_border);\n border-color: var(--_border-color);\n border-radius: var(--_radius);\n }\n\n img {\n display: block;\n width: 100%;\n height: 100%;\n object-fit: cover;\n }\n\n img[hidden] {\n display: none;\n }\n\n .initials {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n }\n\n .icon-fallback {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n color: var(--_color);\n opacity: 0.6;\n }\n\n .status {\n position: absolute;\n inset-inline-end: 0;\n bottom: 0;\n width: 0.75em;\n height: 0.75em;\n border: 2px solid var(--_border-color, var(--color-canvas));\n border-radius: var(--rounded-full);\n }\n\n .status[data-status='online'] {\n background: var(--color-success);\n }\n\n .status[data-status='offline'] {\n background: var(--color-contrast-400);\n }\n\n .status[data-status='busy'] {\n background: var(--color-error);\n }\n\n .status[data-status='away'] {\n background: var(--color-warning);\n }\n}\n\n/* forcedColorsMixin targets :host; avatar needs the border on .avatar (different geometry),\n so forced-color rules are kept inline and unlayered to match mixin convention. */\n@media (forced-colors: active) {\n .avatar {\n forced-color-adjust: none;\n border: 1px solid ButtonText;\n }\n\n .status {\n background: Highlight;\n border: 2px solid ButtonText;\n }\n}\n","import { define, html, prop } from '@vielzeug/ore';\nimport { computed, signal, watch } from '@vielzeug/ripple';\n\nimport type { ComponentSize, RoundedSize, ThemeColor } from '../../types';\n\nimport '../icon/icon';\nimport { roundableBundle, sizableBundle, themableBundle } from '../../shared';\nimport { colorThemeMixin, roundedVariantMixin, sizeVariantMixin } from '../../styles';\nimport groupStyles from './avatar-group.css?inline';\nimport componentStyles from './avatar.css?inline';\n\nexport type AvatarStatus = 'online' | 'offline' | 'busy' | 'away';\n\nconst STATUS_LABELS: Record<AvatarStatus, string> = {\n away: 'Away',\n busy: 'Busy',\n offline: 'Offline',\n online: 'Online',\n};\n\n/** Avatar component properties */\nexport type OreAvatarProps = {\n /** Alt text for the image; also used to derive initials when no `initials` prop is given */\n alt?: string;\n /** Theme color (used for initials background) */\n color?: ThemeColor;\n /** Explicit initials to display when no image is available (e.g. \"JD\") */\n initials?: string;\n /** Border radius */\n rounded?: RoundedSize | '';\n /** Component size */\n size?: ComponentSize;\n /** Image source URL */\n src?: string;\n /** Online presence indicator */\n status?: AvatarStatus;\n};\n\n// ============================================\n// Component\n// ============================================\n\n/**\n * Displays a user avatar: image → initials → generic fallback icon, in that priority order.\n *\n * @element ore-avatar\n *\n * @attr {string} src - Image source URL\n * @attr {string} alt - Image alt text (also used to derive initials)\n * @attr {string} initials - Explicit initials (up to 2 chars)\n * @attr {string} color - Theme color for initials background: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - 'sm' | 'md' | 'lg'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n * @attr {string} status - 'online' | 'offline' | 'busy' | 'away'\n *\n * @slot - Fallback content shown when image and initials are unavailable.\n * @cssprop --avatar-size - Diameter of the avatar\n * @cssprop --avatar-bg - Background color\n * @cssprop --avatar-color - Text/icon color\n * @cssprop --avatar-radius - Border radius\n * @cssprop --avatar-border - Border shorthand\n * @cssprop --avatar-border-color - Border color (also controls status dot border)\n *\n * @part avatar - Avatar root container.\n * @part img - Image element.\n * @part initials - Initials fallback element.\n * @part fallback - Shadow part for the `fallback` element.\n * @part status - Status indicator element.\n * @part overflow - Overflow indicator element.\n * @example\n * ```html\n * <ore-avatar src=\"/jane.jpg\" alt=\"Jane Doe\"></ore-avatar>\n * <ore-avatar initials=\"JD\" color=\"primary\"></ore-avatar>\n * <ore-avatar alt=\"John Smith\" status=\"online\"></ore-avatar>\n * ```\n */\nexport const AVATAR_TAG = 'ore-avatar' as const;\ndefine<OreAvatarProps>(AVATAR_TAG, {\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...roundableBundle,\n alt: prop.string(),\n initials: prop.string(),\n src: prop.string(),\n status: prop.string<AvatarStatus>(),\n },\n setup(props) {\n const imgFailed = signal(false);\n\n // Reset stale error state whenever src changes\n watch(props.src, () => {\n imgFailed.value = false;\n });\n\n // Attach load/error listeners reactively when the img element mounts\n const attachImgListeners = (el: HTMLImageElement | null) => {\n if (!el) return;\n\n el.addEventListener('error', () => {\n imgFailed.value = true;\n });\n el.addEventListener('load', () => {\n imgFailed.value = false;\n });\n };\n const derivedInitials = computed(() => {\n if (props.initials.value) return props.initials.value.slice(0, 2);\n\n const alt = props.alt.value;\n\n if (!alt) return '';\n\n const parts = alt.trim().split(/\\s+/);\n\n if (parts.length >= 2) return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();\n\n return parts[0].slice(0, 2).toUpperCase();\n });\n const showImage = computed(() => !!props.src.value && !imgFailed.value);\n const showInitials = computed(() => !showImage.value && !!derivedInitials.value);\n const showFallback = computed(() => !showImage.value && !showInitials.value);\n const avatarLabel = () => {\n const name = (props.alt.value as string | undefined) || null;\n const statusKey = props.status.value as AvatarStatus | undefined;\n const status = statusKey ? STATUS_LABELS[statusKey] : null;\n\n if (!name && !status) return null;\n\n if (!name) return `Status: ${status}`;\n\n if (!status) return name;\n\n return `${name}, ${status}`;\n };\n const avatarRole = () => (avatarLabel() ? 'img' : null);\n\n return html`\n <span class=\"avatar\" part=\"avatar\" :aria-label=\"${avatarLabel}\" :role=\"${avatarRole}\">\n ${() =>\n props.src.value\n ? html`<img\n ref=\"${attachImgListeners}\"\n part=\"img\"\n :src=\"${props.src}\"\n :alt=\"${props.alt}\"\n ?hidden=\"${() => !showImage.value}\"\n aria-hidden=\"true\" />`\n : ''}\n ${() =>\n showInitials.value\n ? html`<span class=\"initials\" part=\"initials\" aria-hidden=\"true\">${derivedInitials}</span>`\n : ''}\n ${() =>\n showFallback.value\n ? html`<ore-icon class=\"icon-fallback\" part=\"fallback\" name=\"user\" size=\"50%\"></ore-icon>`\n : ''}\n </span>\n ${() =>\n props.status.value\n ? html`<span class=\"status\" part=\"status\" :data-status=\"${props.status}\" aria-hidden=\"true\"></span>`\n : ''}\n `;\n },\n styles: [\n colorThemeMixin,\n roundedVariantMixin,\n sizeVariantMixin({\n lg: { fontSize: 'var(--avatar-font-size, var(--text-base))', size: 'var(--avatar-size, var(--size-14))' },\n md: { fontSize: 'var(--avatar-font-size, var(--text-sm))', size: 'var(--avatar-size, var(--size-10))' },\n sm: { fontSize: 'var(--avatar-font-size, var(--text-xs))', size: 'var(--avatar-size, var(--size-7))' },\n }),\n componentStyles,\n ],\n});\n\n// ============================================\n// AvatarGroup\n// ============================================\n\n/** AvatarGroup component properties */\nexport type OreAvatarGroupProps = {\n /** Maximum number of avatars to show before showing a +N badge */\n max?: number;\n /** Total count shown in the overflow badge (defaults to the actual hidden count) */\n total?: number;\n};\n\n/**\n * Groups multiple `ore-avatar` elements in a stacked, overlapping row.\n *\n * @element ore-avatar-group\n *\n * @attr {number} max - Max visible avatars before overflow badge (default: 5)\n * @attr {number} total - Override the total count displayed in the badge\n *\n * @slot - `ore-avatar` elements\n *\n * @cssprop --avatar-group-overlap - Negative margin creating the overlap (default: -0.75rem)\n *\n * @part overflow - Overflow count badge shown when avatars exceed `max`.\n *\n * @example\n * ```html\n * <ore-avatar-group max=\"3\">\n * <ore-avatar src=\"/a.jpg\" alt=\"Alice\"></ore-avatar>\n * <ore-avatar src=\"/b.jpg\" alt=\"Bob\"></ore-avatar>\n * <ore-avatar src=\"/c.jpg\" alt=\"Carol\"></ore-avatar>\n * <ore-avatar src=\"/d.jpg\" alt=\"Dave\"></ore-avatar>\n * </ore-avatar-group>\n * ```\n */\nexport const AVATAR_GROUP_TAG = 'ore-avatar-group' as const;\ndefine<OreAvatarGroupProps>(AVATAR_GROUP_TAG, {\n props: {\n max: prop.number(5),\n total: prop.number(),\n },\n setup(props, { el, slots, watch }) {\n const overflowCount = signal(0);\n\n const updateVisibility = () => {\n const avatars = [...el.querySelectorAll('ore-avatar')];\n const max = Number(props.max.value) || 5;\n const hidden = Math.max(0, avatars.length - max);\n\n overflowCount.value = props.total.value != null ? Number(props.total.value) - max : hidden;\n avatars.forEach((a, i) => {\n if (i >= max) a.setAttribute('data-avatar-group-hidden', '');\n else a.removeAttribute('data-avatar-group-hidden');\n });\n };\n\n watch(() => {\n void slots.elements().value;\n updateVisibility();\n });\n\n const overflowLabel = () => `+${overflowCount.value} more`;\n const overflowText = () => `+${overflowCount.value}`;\n\n return html`\n <slot></slot>\n ${() =>\n overflowCount.value > 0\n ? html`<span class=\"overflow-badge\" part=\"overflow\" aria-label=\"${overflowLabel}\"> ${overflowText} </span>`\n : ''}\n `;\n },\n styles: [groupStyles],\n});\n","@layer refine.base {\n :host {\n display: inline-flex;\n align-items: center;\n }\n\n .item {\n display: inline-flex;\n align-items: center;\n }\n\n .separator {\n display: none;\n padding-inline: var(--size-2);\n font-size: var(--text-sm);\n font-weight: var(--font-normal);\n color: var(--color-contrast-400);\n }\n\n :host([data-show-separator]) .separator {\n display: inline-block;\n }\n\n .link {\n display: inline-flex;\n gap: var(--size-1);\n align-items: center;\n font-size: var(--text-sm);\n font-weight: var(--font-medium);\n color: var(--color-contrast-600);\n text-decoration: none;\n outline-offset: 2px;\n border-radius: var(--rounded-lg);\n transition: color var(--transition-fast);\n }\n\n .link:hover {\n color: var(--color-contrast-900);\n text-decoration: underline;\n }\n\n .link:focus-visible {\n outline: var(--border-2) solid currentcolor;\n outline-offset: var(--border-2);\n }\n\n :host([active]) .link {\n font-weight: var(--font-semibold);\n color: var(--color-contrast-900);\n text-decoration: none;\n pointer-events: none;\n }\n\n /* Icon slot */\n .icon {\n display: contents;\n }\n\n .label {\n min-width: 0;\n max-width: var(--breadcrumb-item-max-width, 20ch);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n}\n","@layer refine.base {\n :host {\n display: block;\n }\n\n nav {\n display: block;\n }\n\n ol {\n display: flex;\n flex-wrap: wrap;\n gap: 0;\n align-items: center;\n padding: 0;\n margin: 0;\n list-style: none;\n }\n}\n","import { define, html, prop } from '@vielzeug/ore';\n\nimport itemStyles from './breadcrumb-item.css?inline';\nimport componentStyles from './breadcrumb.css?inline';\n\nexport type OreBreadcrumbProps = {\n label?: string;\n separator?: string;\n};\n\nexport type OreBreadcrumbItemProps = {\n active?: boolean;\n href?: string;\n separator?: string;\n};\n\n/**\n * A single breadcrumb entry rendered inside `<ore-breadcrumb>`.\n *\n * @element ore-breadcrumb-item\n *\n * @attr {boolean} active - Marks this item as the current page (`aria-current=\"page\"`)\n * @attr {string} href - Link target for this breadcrumb item\n * @attr {string} separator - Separator text shown before the item (except first item)\n *\n * @slot - Item label/content\n * @slot icon - Optional leading icon for the crumb\n *\n * @part separator - Separator element before the item label\n * @part link - The interactive anchor element\n *\n * @example\n * ```html\n * <ore-breadcrumb-item href=\"/\">Home</ore-breadcrumb-item>\n * <ore-breadcrumb-item active>Current Page</ore-breadcrumb-item>\n * ```\n */\nexport const BREADCRUMB_ITEM_TAG = 'ore-breadcrumb-item' as const;\ndefine<OreBreadcrumbItemProps>(BREADCRUMB_ITEM_TAG, {\n props: {\n active: prop.bool(),\n href: prop.string(),\n separator: prop.string('/'),\n },\n setup(props) {\n return html`\n <li class=\"item\" role=\"listitem\">\n <span class=\"separator\" part=\"separator\" aria-hidden=\"true\">${props.separator}</span>\n <a\n class=\"link\"\n :href=\"${props.href}\"\n :aria-current=\"${() => (props.active.value ? 'page' : null)}\"\n :tabindex=\"${() => (props.active.value ? '-1' : null)}\"\n part=\"link\">\n <span class=\"icon\"><slot name=\"icon\"></slot></span>\n <span class=\"label\"><slot></slot></span>\n </a>\n </li>\n `;\n },\n styles: [itemStyles],\n});\n\n// ============================================\n// Breadcrumb Component\n// ============================================\n\n/**\n * Accessible breadcrumb navigation container.\n *\n * @element ore-breadcrumb\n *\n * @attr {string} label - Accessible label for the internal `<nav>` landmark\n * @attr {string} separator - Separator text propagated to child `<ore-breadcrumb-item>` elements\n *\n * @slot - One or more `<ore-breadcrumb-item>` children\n *\n * @part nav - Internal navigation landmark element\n * @part list - Internal ordered list container\n *\n * @cssprop --breadcrumb-separator - Optional custom separator text synced to child items\n *\n * @example\n * ```html\n * <ore-breadcrumb label=\"Page breadcrumb\">\n * <ore-breadcrumb-item href=\"/\">Home</ore-breadcrumb-item>\n * <ore-breadcrumb-item href=\"/blog\">Blog</ore-breadcrumb-item>\n * <ore-breadcrumb-item active>My Post</ore-breadcrumb-item>\n * </ore-breadcrumb>\n * ```\n */\nexport const BREADCRUMB_TAG = 'ore-breadcrumb' as const;\ndefine<OreBreadcrumbProps>(BREADCRUMB_TAG, {\n props: {\n label: prop.string('Breadcrumb'),\n separator: prop.string(),\n },\n setup(props, { el, slots, watch }) {\n // ────────────────────────────────────────────────────────────────\n // Item & Separator Synchronization\n // ────────────────────────────────────────────────────────────────\n\n const getItems = (): HTMLElement[] => Array.from(el.getElementsByTagName('ore-breadcrumb-item'));\n\n const syncItems = () => {\n const sep = props.separator.value || '/';\n const items = getItems();\n\n for (let i = 0; i < items.length; i++) {\n items[i].setAttribute('separator', sep);\n items[i].toggleAttribute('data-show-separator', i > 0);\n }\n\n // Sync CSS variable for CSS-based separator (if used)\n if (sep) el.style.setProperty('--breadcrumb-separator', `'${sep}'`);\n else el.style.removeProperty('--breadcrumb-separator');\n };\n\n // ────────────────────────────────────────────────────────────────\n // Lifecycle\n // ────────────────────────────────────────────────────────────────\n\n watch(() => {\n void slots.elements().value;\n syncItems();\n });\n\n return html`\n <nav part=\"nav\" :aria-label=\"${props.label}\">\n <ol role=\"list\" part=\"list\">\n <slot></slot>\n </ol>\n </nav>\n `;\n },\n styles: [componentStyles],\n});\n","@layer refine.base {\n :host {\n --_bg: var(--card-bg, var(--color-canvas));\n --_color: var(--card-color, var(--color-contrast-900));\n --_border: var(--card-border, var(--border));\n --_border-color: var(--card-border-color, var(--color-contrast-300));\n --_radius: var(--card-radius, var(--rounded-lg));\n --_padding: var(--card-padding, var(--size-4));\n --_shadow: var(--card-shadow, var(--shadow-sm));\n --_hover-shadow: var(--card-hover-shadow, var(--shadow-md));\n\n position: relative;\n display: flex;\n flex-direction: column;\n }\n\n .card {\n position: relative;\n display: flex;\n flex: 1;\n flex-direction: column;\n overflow: hidden;\n color: var(--_color);\n background: var(--_bg);\n border-radius: var(--_radius);\n backdrop-filter: blur(var(--blur-md));\n transition:\n box-shadow var(--transition-normal),\n transform var(--transition-normal),\n background var(--transition-normal),\n border-color var(--transition-normal);\n }\n\n /* ── Card Structure ───────────────────────── */\n\n .card-media {\n flex-shrink: 0;\n overflow: hidden;\n }\n\n .card-media img {\n display: block;\n width: 100%;\n height: auto;\n object-fit: cover;\n }\n\n .card-body {\n display: flex;\n flex: 1;\n flex-direction: column;\n min-height: 0;\n }\n\n .card-header,\n .card-content,\n .card-footer {\n padding: var(--_padding);\n }\n\n .card-header {\n padding-bottom: calc(var(--_padding) / 2);\n }\n\n .card-footer {\n padding-top: calc(var(--_padding) / 2);\n }\n\n .card-content {\n flex: 1;\n }\n\n .card-actions {\n display: flex;\n flex-wrap: wrap;\n gap: var(--size-2);\n align-items: center;\n padding: var(--_padding);\n padding-top: calc(var(--_padding) / 2);\n }\n\n [hidden] {\n display: none;\n }\n}\n\n@layer refine.variants {\n /* Default — bordered card with shadow */\n :host(:not([variant], [color])) {\n --_shadow: var(--card-shadow, var(--shadow-sm));\n }\n\n :host(:not([variant], [color])) .card {\n border: var(--_border) solid var(--_border-color);\n box-shadow: var(--_shadow);\n }\n\n /* Default + color — tinted backdrop */\n :host(:not([variant])[color]) {\n --_bg: var(--card-bg, var(--_theme-backdrop));\n --_border-color: var(--card-border-color, var(--_theme-border));\n }\n\n :host(:not([variant])[color]) .card {\n border: var(--_border) solid var(--_border-color);\n }\n\n :host(:not([variant])[color]:hover) {\n --_bg: var(--card-bg, color-mix(in oklch, var(--_theme-base) 16%, var(--color-contrast-50)));\n --_border-color: var(--card-border-color, var(--_theme-focus));\n }\n\n /* Solid — fully filled with theme color */\n :host([variant='solid']) {\n --_bg: var(--card-bg, var(--_theme-base));\n --_color: var(--card-color, var(--_theme-contrast));\n --_border-color: var(--card-border-color, var(--_theme-base));\n --_shadow: var(--card-shadow, var(--shadow-sm));\n }\n\n :host([variant='solid']) .card {\n border: var(--_border) solid var(--_border-color);\n box-shadow: var(--_shadow);\n }\n\n /* Flat — tinted backdrop, subtle border */\n :host([variant='flat']) {\n --_bg: var(--card-bg, var(--_theme-backdrop));\n --_border-color: var(--card-border-color, color-mix(in oklch, var(--_theme-border) 50%, transparent));\n }\n\n :host([variant='flat']) .card {\n border: var(--_border) solid var(--_border-color);\n }\n\n /* Glass — frosted blur panel */\n :host([variant='glass']) .card {\n text-shadow: var(--text-shadow-xs);\n border: var(--_border) solid var(--_border-color);\n box-shadow: var(--card-shadow, var(--shadow-md)), var(--inset-shadow-xs);\n backdrop-filter: blur(var(--blur-lg)) saturate(180%) brightness(1.05);\n }\n\n :host([variant='glass']:hover) .card {\n box-shadow: var(--card-hover-shadow, var(--shadow-xl)), var(--inset-shadow-sm);\n backdrop-filter: blur(var(--blur-xl)) saturate(200%) brightness(1.1);\n }\n\n :host([variant='glass'][interactive]:hover) .card {\n box-shadow: var(--card-hover-shadow, var(--shadow-2xl)), var(--inset-shadow-sm);\n }\n}\n\n@layer refine.overrides {\n /* ── Loading bar ──────────────────────────── */\n\n /* Bar lives inside .card which already has overflow:hidden,\n so translateX can sweep freely without any overflow. */\n .loading-bar {\n position: absolute;\n inset-inline-start: 0;\n top: 0;\n display: none;\n width: 65%;\n height: 3px;\n background: linear-gradient(90deg, transparent 0%, var(--_theme-base, var(--color-primary)) 50%, transparent 100%);\n }\n\n :host([loading]) .loading-bar {\n display: block;\n animation: var(--_motion-animation, loading-bar 1.4s linear infinite);\n }\n\n /* In RTL the loading bar sweeps right-to-left */\n :host(:dir(rtl)[loading]) .loading-bar {\n animation-direction: reverse;\n }\n\n /* ── Disabled ─────────────────────────────── */\n\n :host([disabled]) {\n pointer-events: none;\n opacity: 0.6;\n }\n\n :host([disabled][interactive]) .card {\n cursor: not-allowed;\n }\n\n /* ── Interactive hover/active ─────────────── */\n\n :host([interactive]:not([disabled]):hover) .card {\n box-shadow: var(--_hover-shadow);\n transform: translateY(-2px) scale(1.01);\n }\n\n :host([interactive]) .card {\n cursor: pointer;\n will-change: transform;\n }\n\n :host([interactive]:not([disabled]):active) .card {\n box-shadow: var(--_shadow);\n transform: translateY(0) scale(0.99);\n transition:\n box-shadow var(--transition-fast),\n transform 120ms var(--ease-spring);\n }\n\n :host([interactive]:focus-visible) .card {\n outline: var(--border-2) solid var(--_theme-focus, var(--color-primary));\n outline-offset: var(--border-2);\n }\n\n /* ── Horizontal orientation ───────────────── */\n\n :host([orientation='horizontal']) .card {\n flex-direction: row;\n }\n\n :host([orientation='horizontal']) .card-media {\n width: 30%;\n min-width: 192px;\n max-width: 320px;\n }\n\n :host([orientation='horizontal']) .card-media img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n }\n\n :host([orientation='horizontal']) .card-body {\n flex: 1;\n }\n}\n\n@keyframes loading-bar {\n 0% {\n transform: translateX(-100%);\n }\n\n 100% {\n transform: translateX(200%);\n }\n}\n","import { define, html, prop } from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\n\nimport type { ElevationLevel, PaddingSize, ThemeColor } from '../../types';\n\nimport { createInteraction } from '../../headless';\nimport { disablableBundle, loadableBundle, themableBundle } from '../../shared';\nimport { frostVariantMixin, reducedMotionMixin, surfaceMixins } from '../../styles';\nimport componentStyles from './card.css?inline';\n\nconst INTERACTIVE_DESCENDANT_SELECTOR =\n 'button, a[href], input, select, textarea, summary, [role=\"button\"], [role=\"link\"], [contenteditable=\"\"], [contenteditable=\"true\"]';\n\nfunction isNestedInteractiveTarget(host: HTMLElement, event: Event): boolean {\n for (const node of event.composedPath()) {\n if (!(node instanceof HTMLElement)) continue;\n\n if (node === host) return false;\n\n if (node.matches(INTERACTIVE_DESCENDANT_SELECTOR) || !!node.closest(INTERACTIVE_DESCENDANT_SELECTOR)) {\n return true;\n }\n }\n\n return false;\n}\n\n/** Card component properties */\n\nexport type OreCardEvents = {\n activate: { originalEvent: MouseEvent | KeyboardEvent; trigger: 'pointer' | 'keyboard' };\n};\n\nexport type OreCardProps = {\n /** Theme color */\n color?: ThemeColor;\n /** Disable interaction */\n disabled?: boolean;\n /** Shadow elevation level (0-5) */\n elevation?: ElevationLevel;\n /** Make the card interactive (role=button, keyboard nav, emits activate) */\n interactive?: boolean;\n /** Show a loading progress bar */\n loading?: boolean;\n /** Card orientation */\n orientation?: 'horizontal';\n /** Internal padding size */\n padding?: PaddingSize;\n /** Visual style variant */\n variant?: 'solid' | 'flat' | 'glass' | 'frost';\n};\n\n/**\n * A versatile card container with semantic slots for media, header, body, footer, and actions.\n *\n * @element ore-card\n *\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'glass' | 'frost'\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} padding - Internal padding: 'none' | 'sm' | 'md' | 'lg' | 'xl'\n * @attr {string} elevation - Shadow elevation: '0' | '1' | '2' | '3' | '4' | '5'\n * @attr {string} orientation - Card layout: 'horizontal'\n * @attr {boolean} interactive - Enable pointer/keyboard activation\n * @attr {boolean} disabled - Disable card interaction\n * @attr {boolean} loading - Show loading progress bar\n *\n * @fires activate - Emitted when an interactive card is activated. detail: { originalEvent: MouseEvent | KeyboardEvent; trigger: 'pointer' | 'keyboard' }\n *\n * @slot media - Media content displayed at top/left\n * @slot header - Card header (title, subtitle)\n * @slot - Main card content\n * @slot footer - Card footer content\n * @slot actions - Action buttons or links\n *\n * @cssprop --card-bg - Background color\n * @cssprop --card-color - Text color\n * @cssprop --card-border - Border width\n * @cssprop --card-border-color - Border color\n * @cssprop --card-radius - Border radius\n * @cssprop --card-padding - Internal padding\n * @cssprop --card-shadow - Box shadow\n * @cssprop --card-hover-shadow - Shadow on hover\n *\n * @part card - Card root container.\n * @part loading-bar - Loading progress bar.\n * @part media - Media slot container.\n * @part body - Body content container.\n * @part header - Header container.\n * @part content - Content container.\n * @part footer - Footer container.\n * @part actions - Actions slot container.\n * @example\n * ```html\n * <ore-card elevation=\"2\"><h3 slot=\"header\">Title</h3><p>Content</p></ore-card>\n * <ore-card interactive color=\"primary\"><h3 slot=\"header\">Click me</h3></ore-card>\n * <ore-card variant=\"frost\" color=\"secondary\">Frosted card</ore-card>\n * ```\n */\nexport const CARD_TAG = 'ore-card' as const;\ndefine<OreCardProps, OreCardEvents>(CARD_TAG, {\n props: {\n ...themableBundle,\n ...disablableBundle,\n ...loadableBundle,\n elevation: prop.number<ElevationLevel>(),\n interactive: prop.bool(false),\n orientation: prop.string<'horizontal'>(),\n padding: prop.string<PaddingSize>(),\n variant: prop.string<'solid' | 'flat' | 'glass' | 'frost'>(),\n },\n\n setup(props, { bind, el, emit, slots, watch }) {\n bind({\n attr: {\n ariaBusy: () => (props.loading.value ? 'true' : 'false'),\n ariaDisabled: () => (props.interactive.value ? String(props.disabled.value) : null),\n role: () => (props.interactive.value ? 'button' : null),\n },\n });\n\n watch(() => {\n if (props.interactive.value) {\n el.setAttribute('tabindex', props.disabled.value ? '-1' : '0');\n } else {\n el.removeAttribute('tabindex');\n }\n });\n\n // ────────────────────────────────────────────────────────────────\n // Event Handlers\n // ────────────────────────────────────────────────────────────────\n\n const pressControl = createInteraction({\n disabled: computed(() => !props.interactive.value || Boolean(props.disabled.value)),\n onPress: (originalEvent, trigger) => {\n emit('activate', { originalEvent, trigger });\n },\n });\n\n const handleClick = (e: MouseEvent) => {\n if (!props.interactive.value || props.disabled.value) return;\n\n if (isNestedInteractiveTarget(el, e)) return;\n\n pressControl.handleClick(e);\n };\n\n const handleKeydown = (e: KeyboardEvent) => {\n pressControl.handleKeydown(e);\n };\n\n bind({\n on: {\n click: (e: MouseEvent) => handleClick(e),\n keydown: (e: KeyboardEvent) => handleKeydown(e),\n },\n });\n\n // ────────────────────────────────────────────────────────────────\n // Template\n // ────────────────────────────────────────────────────────────────\n\n return html`\n <div class=\"card\" part=\"card\">\n <div class=\"loading-bar\" part=\"loading-bar\"></div>\n <div class=\"card-media\" part=\"media\" ?hidden=\"${() => !slots.has('media').value}\">\n <slot name=\"media\"></slot>\n </div>\n <div class=\"card-body\" part=\"body\">\n <div class=\"card-header\" part=\"header\" ?hidden=\"${() => !slots.has('header').value}\">\n <slot name=\"header\"></slot>\n </div>\n <div class=\"card-content\" part=\"content\" ?hidden=\"${() => !slots.has().value}\">\n <slot></slot>\n </div>\n <div class=\"card-footer\" part=\"footer\" ?hidden=\"${() => !slots.has('footer').value}\">\n <slot name=\"footer\"></slot>\n </div>\n <div class=\"card-actions\" part=\"actions\" ?hidden=\"${() => !slots.has('actions').value}\">\n <slot name=\"actions\"></slot>\n </div>\n </div>\n </div>\n `;\n },\n\n styles: [...surfaceMixins, frostVariantMixin('.card'), reducedMotionMixin, componentStyles],\n});\n","/**\n * Validates that a string is a safe CSS length value before injecting it\n * into a CSS custom property. Accepts standard length units, percentages,\n * CSS keywords, and `calc()`/`var()` expressions without embedded semicolons,\n * curly braces, or other CSS injection vectors.\n *\n * @returns The trimmed value if safe, `null` otherwise.\n */\nexport function safeCSSLength(value: string | null | undefined): string | null {\n if (!value) return null;\n\n const v = value.trim();\n\n // Block CSS injection sequences (parens excluded — needed by var()/calc())\n if (/[;{}\\n\\r]/.test(v)) return null;\n\n // Allow: numbers with units, %, keywords, var(--token), calc(...), env(...)\n if (\n /^-?(\\d+(\\.\\d+)?)(px|em|rem|%|vh|vw|vmin|vmax|dvh|dvw|svh|svw|ch|ex|lh|rlh|cm|mm|in|pt|pc|fr|s|ms|deg|rad|turn)$/.test(\n v,\n )\n )\n return v;\n\n if (/^(0|auto|none|inherit|initial|unset|revert)$/.test(v)) return v;\n\n // Allow CSS function expressions: var(--token), calc(...), env(...), clamp(...), min(...), max(...)\n // Tightened pattern: must match the whole value and inner parens must close properly.\n if (/^(var|calc|env|clamp|min|max)\\([^;{}]*\\)$/.test(v)) return v;\n\n return null;\n}\n","import { computed, type Readable } from '@vielzeug/ripple';\n\nimport type { LinkTarget } from '../shared';\n\n/**\n * Computes a safe `rel` attribute value for anchor elements.\n *\n * When `target=\"_blank\"`, automatically injects `noopener` and `noreferrer`\n * to prevent reverse tabnapping attacks (the opened page accessing\n * `window.opener` to redirect the origin).\n *\n * @param rel - The explicit `rel` prop value (may be undefined).\n * @param target - The link `target` prop value (may be undefined).\n * @returns A `rel` string with security tokens merged in, or `null` when no\n * rel is needed.\n */\nexport function computeSafeRel(rel: string | undefined, target: string | undefined): string | null {\n const base = rel ?? '';\n\n if (target !== '_blank') return base || null;\n\n const parts = new Set(base.split(/\\s+/).filter(Boolean));\n\n parts.add('noopener');\n parts.add('noreferrer');\n\n return [...parts].join(' ');\n}\n\n/**\n * Props required by any component that renders as an anchor when `href` is set.\n * Import and spread into your component's props type to get consistent link support.\n */\nexport type LinkProps = {\n /** When set, the component renders as an `<a>` instead of its default element. */\n href?: string;\n /** Anchor `rel` attribute. `noopener noreferrer` is automatically added for `target=\"_blank\"`. */\n rel?: string;\n /** Anchor browsing context. */\n target?: LinkTarget;\n};\n\n/**\n * Derives computed link state from reactive `href`, `rel`, and `target` signals.\n *\n * Returns:\n * - `isLink` — true when `href` is set (and optionally not disabled)\n * - `effectiveRel` — `rel` merged with security tokens when `target=\"_blank\"`\n *\n * @example\n * ```ts\n * const { isLink, effectiveRel } = useLinkProps(props.href, props.rel, props.target);\n * ```\n */\nexport function useLinkProps(\n href: Readable<string | undefined>,\n rel: Readable<string | undefined>,\n target: Readable<LinkTarget | undefined>,\n disabled?: Readable<boolean>,\n) {\n const isLink = computed(() => !!href.value && !disabled?.value);\n const effectiveRel = computed(() => computeSafeRel(rel.value, target.value));\n\n return { effectiveRel, isLink };\n}\n","@layer refine.base {\n /* ========================================\n Base Styles\n ======================================== */\n\n :host {\n display: inline-flex;\n\n --group-gap: var(--size-2);\n --group-radius: var(--rounded-lg);\n }\n\n .button-group {\n display: flex;\n flex-direction: row;\n gap: var(--group-gap);\n }\n}\n\n@layer refine.variants {\n /* ========================================\n Orientation\n ======================================== */\n\n :host([orientation='vertical']) .button-group {\n flex-direction: column;\n }\n}\n\n@layer refine.overrides {\n /* ========================================\n Full Width\n ======================================== */\n\n :host([fullwidth]) {\n display: flex;\n width: 100%;\n }\n\n :host([fullwidth]) .button-group {\n width: 100%;\n }\n\n :host([fullwidth]) ::slotted(ore-button) {\n flex: 1;\n }\n\n /* ========================================\n Attached Mode\n ======================================== */\n\n :host([attached]) .button-group {\n gap: 0;\n }\n\n /* Ensure attached buttons have proper z-index on hover/focus */\n :host([attached]) ::slotted(ore-button:hover),\n :host([attached]) ::slotted(ore-button:focus-within) {\n position: relative;\n z-index: 1;\n }\n\n /* Horizontal attached - remove inner borders and round corners */\n :host([attached]:not([orientation='vertical'])) ::slotted(ore-button) {\n --button-radius: 0;\n }\n\n :host([attached]:not([orientation='vertical'])) ::slotted(ore-button:not(:first-child)) {\n --button-border-start: 0;\n }\n\n :host([attached]:not([orientation='vertical'])) ::slotted(ore-button:first-child) {\n --button-radius: var(--group-radius) 0 0 var(--group-radius);\n }\n\n :host([attached]:not([orientation='vertical'])) ::slotted(ore-button:last-child) {\n --button-radius: 0 var(--group-radius) var(--group-radius) 0;\n }\n\n /* Vertical attached - remove inner borders and round corners */\n :host([attached][orientation='vertical']) ::slotted(ore-button) {\n --button-radius: 0;\n }\n\n :host([attached][orientation='vertical']) ::slotted(ore-button:not(:first-child)) {\n --button-border-top: 0;\n }\n\n :host([attached][orientation='vertical']) ::slotted(ore-button:first-child) {\n --button-radius: var(--group-radius) var(--group-radius) 0 0;\n }\n\n :host([attached][orientation='vertical']) ::slotted(ore-button:last-child) {\n --button-radius: 0 0 var(--group-radius) var(--group-radius);\n }\n}\n","import { createContext, define, html, prop } from '@vielzeug/ore';\nimport { type Readable } from '@vielzeug/ripple';\n\nimport type { ComponentSize, ThemeColor } from '../../shared';\nimport type { ButtonVariant } from '../button/button';\n\nimport { sizableBundle, themableBundle } from '../../shared';\nimport styles from './button-group.css?inline';\n\n/** Button group properties */\nexport type OreButtonGroupProps = {\n /** Join buttons together into a single unit */\n attached?: boolean;\n /** Theme color tint for all child buttons */\n color?: ThemeColor;\n /** Group children span full width */\n fullwidth?: boolean;\n /** Label for screen readers */\n label?: string;\n /** Layout direction */\n orientation?: 'horizontal' | 'vertical';\n /** Shared size for all child buttons */\n size?: ComponentSize;\n /** Shared visual variant for all child buttons */\n variant?: ButtonVariant;\n};\n\n/** Shared context propagated from ore-button-group to child ore-button elements */\nexport type ButtonGroupContext = {\n color: Readable<ThemeColor | undefined>;\n size: Readable<ComponentSize | undefined>;\n variant: Readable<ButtonVariant | undefined>;\n};\n\nexport const BUTTON_GROUP_CTX = createContext<ButtonGroupContext | undefined>('OreButtonGroup');\n\n/**\n * A container for grouping related buttons.\n * Child `ore-button` components automatically inherit the group's color, size, and variant.\n *\n * @element ore-button-group\n *\n * @attr {boolean} attached - Join buttons together into a unit\n * @attr {string} color - Shared color tint: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {boolean} fullwidth - Group spans full width\n * @attr {string} label - Accessible label\n * @attr {string} orientation - 'horizontal' | 'vertical'\n * @attr {string} size - Shared size: 'sm' | 'md' | 'lg'\n * @attr {string} variant - Shared visual variant: 'solid' | 'flat' | 'bordered' | 'outline' | 'ghost' | 'frost'\n *\n * @slot - Place ore-button elements here\n *\n * @cssprop --group-gap - Gap between buttons (non-attached mode)\n * @cssprop --group-radius - Border radius of the group container\n * @cssprop --button-radius - Passed through to child buttons to control corner radius\n * @cssprop --button-border-start - Passed through to suppress start borders in attached mode\n * @cssprop --button-border-top - Passed through to suppress top borders in vertical attached mode\n * @part group - Group container.\n * @example\n * ```html\n * <ore-button-group attached>\n * <ore-button variant=\"solid\" color=\"primary\">Save</ore-button>\n * <ore-button variant=\"solid\" color=\"primary\">Save & Continue</ore-button>\n * </ore-button-group>\n * <ore-button-group orientation=\"vertical\" size=\"sm\">\n * <ore-button>Top</ore-button>\n * <ore-button>Middle</ore-button>\n * <ore-button>Bottom</ore-button>\n * </ore-button-group>\n * ```\n */\nexport const BUTTON_GROUP_TAG = 'ore-button-group' as const;\ndefine<OreButtonGroupProps>(BUTTON_GROUP_TAG, {\n props: {\n ...themableBundle,\n ...sizableBundle,\n attached: prop.bool(false),\n fullwidth: prop.bool(false),\n label: prop.string(),\n orientation: prop.string<'horizontal' | 'vertical'>(),\n variant: prop.string(),\n },\n setup(props, { provide }) {\n provide(BUTTON_GROUP_CTX, {\n color: props.color!,\n size: props.size!,\n variant: props.variant!,\n });\n\n return html`\n <div class=\"button-group\" part=\"group\" role=\"group\" :aria-label=\"${props.label}\">\n <slot></slot>\n </div>\n `;\n },\n styles: [styles],\n});\n","import type { HostBindFn } from '@vielzeug/ore';\nimport type { Readable, Signal } from '@vielzeug/ripple';\n\nimport type { ComponentSize } from '../../types';\n\n/**\n * Minimal shape of the handle returned by `createCheckable` that\n * `applyCheckableBinding` needs. Matches both checkbox (with `indeterminate`)\n * and switch (without).\n */\nexport type CheckableBindingHandle = {\n assistiveId: string;\n checked: Signal<boolean>;\n disabled: Readable<boolean>;\n errorText: Readable<string>;\n handleClick: (event: MouseEvent) => boolean;\n handleKeydown: (event: KeyboardEvent) => boolean;\n helperText: Readable<string>;\n indeterminate?: Signal<boolean>;\n labelId: string;\n};\n\n/**\n * Applies the standard host bindings shared by all checkable components\n * (checkbox, switch, radio).\n *\n * Wires `role`, all ARIA attributes, `checked`, `size`, `tabindex`, the\n * `is-checked`/`is-disabled` classes, and the `click`/`keydown` event handlers.\n *\n * Pass `handle.indeterminate` for components that need it (checkbox);\n * omit it for switch/radio.\n */\nexport const applyCheckableBinding = (\n bind: HostBindFn,\n fCtxSize: Readable<ComponentSize | undefined>,\n handle: CheckableBindingHandle,\n role: 'checkbox' | 'radio' | 'switch',\n): void => {\n const { assistiveId, checked, disabled, errorText, handleClick, handleKeydown, helperText, indeterminate, labelId } =\n handle;\n\n bind({\n attr: {\n ...(indeterminate !== undefined && { indeterminate }),\n ariaChecked: () => {\n if (role === 'checkbox' && indeterminate?.value) return 'mixed';\n\n return checked.value ? 'true' : 'false';\n },\n ariaDescribedby: () => (errorText.value || helperText.value ? assistiveId : null),\n ariaDisabled: () => (disabled.value ? 'true' : null),\n ariaInvalid: () => (errorText.value ? 'true' : null),\n ariaLabelledby: labelId,\n checked,\n role,\n size: fCtxSize,\n tabindex: () => (disabled.value ? undefined : 0),\n },\n class: () => ({\n 'is-checked': checked.value,\n 'is-disabled': disabled.value,\n ...(indeterminate !== undefined && { 'is-indeterminate': indeterminate.value }),\n }),\n on: {\n click: handleClick,\n keydown: handleKeydown,\n },\n });\n};\n","import { createContext, type HostBindFn } from '@vielzeug/ore';\nimport { computed, type Readable } from '@vielzeug/ripple';\n\nimport type { ValidationTrigger } from '../../headless';\nimport type { ComponentSize, VisualVariant } from '../../types';\n\nexport type FormContext = {\n /** Whether all child fields are disabled */\n disabled: Readable<boolean>;\n /** Default size propagated to all child form fields */\n size: Readable<ComponentSize | undefined>;\n /**\n * When to validate child form controls:\n * - `'submit'` (default): only on form submit\n * - `'blur'`: validate each field when it loses focus\n * - `'change'`: validate on every value change\n * - `'input'`: validate on every input event\n */\n validateOn: Readable<ValidationTrigger>;\n /** Default variant propagated to all child form fields */\n variant: Readable<VisualVariant | undefined>;\n};\n\nexport const FORM_CTX = createContext<FormContext>('FormContext');\n\n// ── Prop resolver ─────────────────────────────────────────────────────────────\n\ntype FormContextResolvedProps = {\n disabled: Readable<boolean>;\n size: Readable<ComponentSize | undefined>;\n variant: Readable<VisualVariant | undefined>;\n};\n\n/**\n * Pure resolver: merges local prop signals with an optional `FormContext`.\n * Returns computed `disabled`, `size`, and `variant` signals without any\n * side-effects — suitable for unit testing and composition.\n */\nexport const mergeFormContext = (\n props: {\n disabled?: Readable<boolean | undefined> | Readable<boolean>;\n size?: Readable<string | undefined> | Readable<string>;\n variant?: Readable<string | undefined> | Readable<string>;\n },\n formCtx?: FormContext,\n): FormContextResolvedProps => ({\n disabled: computed(() => Boolean(props.disabled?.value) || Boolean(formCtx?.disabled?.value)),\n size: computed(\n (): ComponentSize | undefined => (props.size?.value ?? formCtx?.size?.value) as ComponentSize | undefined,\n ),\n variant: computed(\n (): VisualVariant | undefined => (props.variant?.value ?? formCtx?.variant?.value) as VisualVariant | undefined,\n ),\n});\n\n/**\n * Resolves form context props AND automatically reflects the computed `disabled`\n * state as a `disabled` attribute on the host element.\n *\n * The `use` prefix signals that calling this function performs a side-effect\n * (`host.bind`) in addition to returning the resolved props — similar to a\n * framework hook.\n *\n * Accepts `FormContext | undefined` directly — pass `inject(FORM_CTX)`.\n */\nexport const useFormContext = (\n bind: HostBindFn,\n props: Parameters<typeof mergeFormContext>[0],\n formCtx?: FormContext,\n): FormContextResolvedProps => {\n const resolved = mergeFormContext(props, formCtx);\n\n bind({\n attr: {\n disabled: () => (resolved.disabled.value ? '' : undefined),\n },\n });\n\n return resolved;\n};\n","import type { Readable } from '@vielzeug/ripple';\n\nimport { html } from '@vielzeug/ore';\n\n/**\n * Renders the standard assistive text region (helper/error) used across all\n * field components. Encapsulates the repeated `aria-live`/`hidden` markup so\n * each component only passes the data.\n *\n * @param assistiveId - The stable ID shared with the ARIA `aria-describedby` attribute.\n * @param errorText - Reactive error text signal from the field primitive.\n * @param helperText - Reactive helper text signal from the field primitive.\n * @param setRef - Optional callback to capture the container element.\n */\nexport const renderHelperRegion = (\n assistiveId: string,\n errorText: Readable<string>,\n helperText: Readable<string>,\n setRef?: (el: HTMLElement | null) => void,\n) => {\n return html`<div\n class=\"helper-text\"\n part=\"helper-text\"\n id=\"${assistiveId}\"\n :role=\"${() => (errorText.value ? 'alert' : null)}\"\n aria-live=\"polite\"\n ?hidden=\"${() => !errorText.value && !helperText.value}\"\n ref=${(el: HTMLElement | null) => {\n setRef?.(el);\n }}>\n ${() => errorText.value || helperText.value}\n </div>`;\n};\n","import type { Readable } from '@vielzeug/ripple';\n\nimport type { ButtonType } from '../../shared';\n\n/**\n * Handles form submission relay for form-associated button-like components.\n *\n * The inner `<button>` always has `type=\"button\"` so the shadow DOM never\n * drives native form actions directly. This composable intercepts clicks and\n * forwards submit/reset to the associated form via `ElementInternals`.\n *\n * @param form - The associated HTMLFormElement (from `useField().internals.form`).\n * @param type - Reactive signal for the button `type` prop.\n * @param isDisabled - Reactive signal indicating whether the button is disabled/loading.\n * @param host - The host custom element.\n * @returns A click handler to attach to the inner element.\n */\nexport function useFormAction(\n getForm: () => HTMLFormElement | null,\n type: Readable<ButtonType | undefined>,\n isDisabled: Readable<boolean>,\n host: HTMLElement,\n): (e: MouseEvent) => void {\n return (e: MouseEvent) => {\n if (isDisabled.value) {\n e.preventDefault();\n e.stopImmediatePropagation();\n\n return;\n }\n\n const form = getForm();\n\n if (form) {\n if (type.value === 'submit') {\n e.preventDefault();\n form.requestSubmit();\n } else if (type.value === 'reset') {\n e.preventDefault();\n form.reset();\n }\n }\n\n // Re-dispatch if the native click didn't bubble to host (shadow DOM interop).\n if (!e.composedPath().includes(host)) {\n host.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, composed: true }));\n }\n };\n}\n","@layer refine.base {\n :host {\n --_bg: var(--button-bg, var(--color-contrast-100));\n --_color: var(--button-color, var(--color-contrast-900));\n --_border-color: var(--button-border-color, var(--color-contrast-300));\n --_radius: var(--button-radius, var(--rounded-lg));\n\n display: inline-flex;\n align-items: center;\n justify-content: var(--button-justify, center);\n }\n\n /* Link mode: disable pointer interaction on the inner <a> while disabled/loading. */\n :host([disabled]) a,\n :host([loading]) a {\n pointer-events: none;\n cursor: not-allowed;\n }\n\n :host([loading]) a {\n cursor: wait;\n }\n\n [part='button'] {\n position: relative;\n box-sizing: border-box;\n display: flex;\n gap: var(--_gap, var(--size-2));\n align-items: center;\n justify-content: var(--button-justify, center);\n width: 100%;\n min-width: 0;\n height: var(--_height, var(--size-10));\n min-height: var(--_touch-target);\n padding: var(--_padding, var(--size-2) var(--size-4));\n font-size: var(--_font-size, var(--text-sm));\n font-weight: var(--font-medium);\n line-height: var(--_line-height, var(--leading-normal));\n color: var(--_color);\n white-space: nowrap;\n cursor: pointer;\n user-select: none;\n background: var(--_bg);\n border: var(--button-border, var(--border)) solid var(--_border-color);\n border-block-start-width: var(--button-border-top, var(--button-border, var(--border)));\n border-block-end-width: var(--button-border-bottom, var(--button-border, var(--border)));\n border-inline-start-width: var(--button-border-start, var(--button-border, var(--border)));\n border-inline-end-width: var(--button-border-end, var(--button-border, var(--border)));\n border-radius: var(--_radius);\n transition: var(\n --_motion-transition,\n background var(--transition-normal),\n border-color var(--transition-normal),\n box-shadow var(--transition-normal),\n color var(--transition-normal),\n transform 120ms var(--ease-spring)\n );\n }\n\n [part='button']:focus-visible {\n outline: none;\n }\n\n /* Keyframe must live in shadow DOM — @keyframes don't inherit across shadow roots */\n @keyframes spin {\n to {\n transform: rotate(360deg);\n }\n }\n\n .loader {\n position: absolute;\n width: 1em;\n height: 1em;\n border: var(--border-2) solid currentcolor;\n border-inline-end-color: transparent;\n border-radius: 50%;\n animation: var(--_motion-animation, spin var(--transition-loader) infinite);\n }\n\n .content {\n display: inline-flex;\n align-items: center;\n min-width: 0;\n max-width: 100%;\n overflow: hidden;\n text-overflow: ellipsis;\n vertical-align: middle;\n white-space: nowrap;\n }\n\n ::slotted([slot='prefix']),\n ::slotted([slot='suffix']) {\n display: inline-flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n }\n\n ::slotted(svg) {\n flex-shrink: 0;\n width: var(--_icon-size, var(--leading-6));\n height: var(--_icon-size, var(--leading-6));\n }\n}\n\n@layer refine.overrides {\n :host([fullwidth]) {\n display: flex;\n width: 100%;\n }\n\n /* Icon-only always uses perfect circle */\n :host([rounded][icon-only]) [part='button'] {\n border-radius: 50%;\n }\n\n :host([loading]) .content {\n visibility: hidden;\n }\n}\n\n@layer refine.variants {\n :host([icon-only]) [part='button'] {\n aspect-ratio: 1;\n padding: 0;\n }\n\n /* ── Per-variant token assignments ─────────────────────────────────────────\n Each variant sets --_bg/--_color/--_border-color (consuming the public\n --button-* tokens as overrides) plus optional --_hover-* / --_active-*\n tokens for interactive states.\n The shared :is(button, a):hover / :active rules below read these tokens.\n ─────────────────────────────────────────────────────────────────────── */\n\n /* Solid (Default) */\n :host(:not([variant])),\n :host([variant='solid']) {\n --_bg: var(--button-bg, var(--_theme-base));\n --_color: var(--button-color, var(--_theme-contrast));\n --_border-color: var(--button-border-color, var(--_theme-base));\n --_hover-bg: var(--_theme-focus);\n --_active-bg: color-mix(in oklch, var(--_theme-focus) 85%, black);\n --_active-color: var(--_theme-contrast);\n }\n\n /* Flat */\n :host([variant='flat']) {\n --_bg: var(--button-bg, color-mix(in oklch, var(--_theme-backdrop) 25%, var(--color-contrast-100)));\n --_color: var(--button-color, var(--_theme-base));\n --_border-color: var(--button-border-color, color-mix(in oklch, var(--_theme-focus) 20%, transparent));\n --_hover-bg: var(--_theme-focus);\n --_hover-color: var(--_theme-contrast);\n --_active-bg: color-mix(in oklch, var(--_theme-focus) 85%, black);\n --_active-color: var(--_theme-contrast);\n }\n\n :host([variant='flat']) [part='button'] {\n box-shadow: var(--inset-shadow-2xs);\n }\n\n :host([variant='flat']) [part='button']:hover {\n box-shadow: var(--inset-shadow-xs);\n }\n\n :host([variant='flat']) [part='button']:active {\n box-shadow: var(--inset-shadow-sm);\n }\n\n /* Bordered */\n :host([variant='bordered']) {\n --_bg: var(--button-bg, var(--_theme-backdrop));\n --_color: var(--button-color, var(--_theme-base));\n --_border-color: var(--button-border-color, var(--_theme-border));\n --_hover-bg: var(--_theme-focus);\n --_hover-color: var(--_theme-contrast);\n --_hover-border-color: var(--_theme-focus);\n --_active-bg: color-mix(in oklch, var(--_theme-focus) 85%, black);\n --_active-color: var(--_theme-contrast);\n }\n\n :host([variant='bordered']) [part='button'] {\n box-shadow: var(--inset-shadow-xs);\n }\n\n :host([variant='bordered']) [part='button']:hover {\n box-shadow: var(--inset-shadow-xs);\n }\n\n :host([variant='bordered']) [part='button']:active {\n box-shadow: var(--inset-shadow-sm);\n }\n\n /* Outline */\n :host([variant='outline']) {\n --_bg: var(--button-bg, transparent);\n --_color: var(--button-color, var(--_theme-base));\n --_border-color: var(--button-border-color, var(--_theme-base));\n --_hover-bg: var(--_theme-backdrop);\n --_hover-border-color: var(--_theme-focus);\n --_active-bg: color-mix(in oklch, var(--_theme-base) 85%, black);\n --_active-color: var(--_theme-contrast);\n }\n\n /* Ghost */\n :host([variant='ghost']) {\n --_bg: var(--button-bg, transparent);\n --_color: var(--button-color, var(--_theme-base));\n --_border-color: var(--button-border-color, transparent);\n --_hover-bg: var(--_theme-backdrop);\n --_active-bg: color-mix(in oklch, var(--_theme-base) 85%, black);\n --_active-color: var(--_theme-contrast);\n }\n\n :host([variant='ghost']) [part='button'] {\n border-width: 0;\n }\n\n /* Text */\n :host([variant='text']) {\n --_bg: var(--button-bg, transparent);\n --_color: var(--button-color, var(--_theme-base));\n --_border-color: var(--button-border-color, transparent);\n --_hover-color: var(--_theme-focus);\n --_active-color: color-mix(in oklch, var(--_theme-focus) 85%, black);\n }\n\n :host([variant='text']) [part='button'] {\n border-width: 0;\n }\n\n /* Frost — sets its own interactive tokens so the shared rules below apply uniformly */\n :host([variant='frost']:not([color])) {\n --_hover-bg: var(--button-frost-active-bg, color-mix(in oklch, var(--color-canvas) 70%, transparent));\n --_hover-border-color: var(\n --button-frost-active-border-color,\n color-mix(in oklch, var(--_theme-focus) 40%, transparent)\n );\n --_active-bg: var(--button-frost-active-bg, color-mix(in oklch, var(--color-canvas) 70%, transparent));\n --_active-border-color: var(\n --button-frost-active-border-color,\n color-mix(in oklch, var(--_theme-focus) 40%, transparent)\n );\n }\n\n :host([variant='frost'][color]) {\n --_hover-bg: var(--button-frost-active-bg, color-mix(in oklch, var(--_theme-backdrop) 50%, var(--_theme-base) 50%));\n --_hover-border-color: var(\n --button-frost-active-border-color,\n color-mix(in oklch, var(--_theme-focus) 65%, transparent)\n );\n --_active-bg: var(\n --button-frost-active-bg,\n color-mix(in oklch, var(--_theme-backdrop) 50%, var(--_theme-base) 50%)\n );\n --_active-border-color: var(\n --button-frost-active-border-color,\n color-mix(in oklch, var(--_theme-focus) 65%, transparent)\n );\n }\n\n /* ── Shared interactive states — all variants use --_* tokens set above ── */\n\n [part='button']:hover {\n color: var(--_hover-color, var(--_color));\n background: var(--_hover-bg, var(--_bg));\n border-color: var(--_hover-border-color, var(--_border-color));\n }\n\n [part='button']:active {\n color: var(--_active-color, var(--_color));\n background: var(--_active-bg, var(--_bg));\n border-color: var(--_active-border-color, var(--_border-color));\n box-shadow: var(--inset-shadow-2xs);\n }\n}\n\n@layer refine.overrides {\n /* Focus ring — keyboard navigation only; combines focus shadow + halo to avoid shadow pop */\n [part='button']:focus-visible {\n outline: none;\n box-shadow: var(--_theme-shadow), var(--_theme-halo);\n }\n\n /* Hover depth — halo border effect matching ore-input focus style */\n [part='button']:hover {\n border-color: var(--_hover-border-color, var(--_theme-focus));\n box-shadow: var(--_theme-shadow);\n }\n\n /* Ghost + Text variants: no border/shadow decoration on hover */\n :host([variant='ghost']) [part='button']:hover,\n :host([variant='text']) [part='button']:hover {\n border-color: transparent;\n box-shadow: none;\n transform: none;\n }\n\n /* Physical press feedback */\n [part='button']:active {\n transform: translateY(1px);\n }\n}\n","import { define, useField, html, inject, prop } from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\n\nimport type { ButtonType, ComponentSize, LinkTarget, RoundedSize, ThemeColor } from '../../types';\n\nimport { commonProps } from '../../shared';\nimport {\n coarsePointerMixin,\n colorThemeMixin,\n disabledLoadingMixin,\n forcedColorsMixin,\n frostVariantMixin,\n rainbowEffectMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n shineEffectMixin,\n sizeVariantMixin,\n} from '../../styles';\nimport { useLinkProps } from '../../utils';\nimport { BUTTON_GROUP_CTX } from '../button-group/button-group';\nimport { useFormAction } from '../shared';\nimport componentStyles from './button.css?inline';\n\nexport const BUTTON_VARIANTS = ['solid', 'flat', 'bordered', 'outline', 'ghost', 'text', 'frost'] as const;\n\n/** Visual variant for ore-button — derived from BUTTON_VARIANTS for a single source of truth. */\nexport type ButtonVariant = (typeof BUTTON_VARIANTS)[number];\n\n/** Animated border effect for ore-button. */\nexport type ButtonEffect = 'shine' | 'rainbow';\n\n/** Button component properties */\nexport type OreButtonProps = {\n /** Theme color */\n color?: ThemeColor;\n /** Disable interaction */\n disabled?: boolean;\n /** Animated border effect: 'shine' (color-aware neon sweep) or 'rainbow' */\n effect?: ButtonEffect;\n /** Full width button (100% of container) */\n fullwidth?: boolean;\n /** When set, renders an `<a>` instead of `<button>` */\n href?: string;\n /** Icon-only mode (square aspect ratio, no padding) */\n iconOnly?: boolean;\n /** Accessible label for the inner button — required for icon-only buttons */\n label?: string;\n /** Show loading state with spinner */\n loading?: boolean;\n /** Link rel attribute (requires href) */\n rel?: string;\n /** Border radius size */\n rounded?: RoundedSize;\n /** Component size */\n size?: ComponentSize;\n /** Link target (requires href) */\n target?: LinkTarget;\n /** HTML button type attribute */\n type?: ButtonType;\n /** Visual style variant */\n variant?: ButtonVariant;\n};\n\n/**\n * A customizable button component with multiple variants, sizes, and states.\n * Supports icons, loading states, and animated border effects.\n *\n * @element ore-button\n *\n * @attr {string} type - HTML button type: 'button' | 'submit' | 'reset'\n * @attr {boolean} disabled - Disable button interaction\n * @attr {boolean} loading - Show loading state with spinner\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'outline' | 'ghost' | 'text' | 'frost'\n * @attr {string} size - Button size: 'sm' | 'md' | 'lg'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n * @attr {string} effect - Animated border effect: 'shine' | 'rainbow'\n * @attr {boolean} icon-only - Icon-only mode (square aspect ratio, no padding)\n * @attr {boolean} fullwidth - Full width button (100% of container)\n *\n * @fires click - Emitted when button is clicked (unless disabled/loading)\n *\n * @slot - Button content (text, icons, etc.)\n * @slot prefix - Content before the button text (e.g., icons)\n * @slot suffix - Content after the button text (e.g., icons, badges)\n *\n * @part button - The inner button or anchor element\n * @part loader - The loading spinner element\n * @part content - The button content wrapper\n *\n * @cssprop --button-bg - Background color override\n * @cssprop --button-color - Text color override\n * @cssprop --button-border - Border width override\n * @cssprop --button-border-color - Border color override\n * @cssprop --button-radius - Border radius override\n * @cssprop --button-padding - Inner padding override\n * @cssprop --button-gap - Gap between icon and text override\n * @cssprop --button-font-size - Font size override\n * @cssprop --button-frost-active-bg - Background when pressed (frost variant)\n * @cssprop --button-frost-active-border-color - Border color when pressed (frost variant)\n *\n * @example\n * ```html\n * <ore-button variant=\"solid\" color=\"primary\">Click me</ore-button>\n * <ore-button loading color=\"success\">Processing...</ore-button>\n * <ore-button effect=\"shine\" color=\"primary\">Shine</ore-button>\n * <ore-button effect=\"rainbow\" variant=\"frost\">Rainbow</ore-button>\n * ```\n */\nexport const BUTTON_TAG = 'ore-button' as const;\ndefine<OreButtonProps>(BUTTON_TAG, {\n formAssociated: true,\n props: {\n ...commonProps,\n effect: prop.string<ButtonEffect>(),\n fullwidth: prop.bool(false),\n href: prop.string(),\n iconOnly: prop.bool(false),\n label: prop.string(),\n rel: prop.string(),\n target: prop.string<LinkTarget>(),\n type: prop.oneOf(['button', 'submit', 'reset'] as const, 'button'),\n variant: prop.oneOf(BUTTON_VARIANTS, 'solid'),\n },\n setup(props, { bind, el }) {\n // Prefer group context over own props for color/size/variant.\n const groupCtx = inject(BUTTON_GROUP_CTX);\n const effectiveColor = computed(() => groupCtx?.color.value ?? props.color.value);\n const effectiveSize = computed(() => groupCtx?.size.value ?? props.size.value);\n const effectiveVariant = computed(() => groupCtx?.variant.value ?? props.variant.value);\n\n const isDisabled = computed(() => !!(props.disabled.value || props.loading.value));\n\n // isLink and effectiveRel are computed from signals — correct even if href changes at runtime.\n const { effectiveRel, isLink } = useLinkProps(props.href, props.rel, props.target);\n\n // Form association: relay submit/reset clicks to the associated form.\n // The inner <button> always has type=\"button\" so shadow DOM never drives native form actions.\n // getForm() returns null for link mode at runtime, so no form actions fire.\n const formField = useField({\n disabled: isDisabled,\n toFormValue: () => null,\n value: computed(() => ''),\n });\n\n const handleClick = (e: MouseEvent) => {\n if (isDisabled.value) {\n e.preventDefault();\n\n return;\n }\n\n // Link mode renders a real <a href> below — the browser handles left/middle/ctrl-click\n // navigation, target, and rel natively. No manual window.open/location.href needed.\n useFormAction(() => (isLink.value ? null : formField.internals.form), props.type, isDisabled, el)(e);\n };\n\n const handleKeydown = (e: KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n (el.shadowRoot?.querySelector('[part=\"button\"]') as HTMLElement)?.click();\n }\n };\n\n // ARIA attributes live on the host.\n bind({\n attr: {\n 'aria-busy': props.loading,\n 'aria-disabled': isDisabled,\n 'aria-label': props.label,\n color: effectiveColor,\n effect: props.effect,\n role: computed(() => el.getAttribute('role') ?? (isLink.value ? 'link' : 'button')),\n size: effectiveSize,\n tabindex: computed(() => (isDisabled.value ? '-1' : '0')),\n variant: effectiveVariant,\n },\n on: {\n keydown: handleKeydown,\n },\n });\n\n const buttonContent = html`\n <span class=\"loader\" part=\"loader\" aria-label=\"Loading\" ?hidden=${() => !props.loading.value}></span>\n <slot name=\"prefix\"></slot>\n <span class=\"content\" part=\"content\"><slot></slot></span>\n <slot name=\"suffix\"></slot>\n `;\n\n // The inner element (<a> or <span>) is deliberately non-focusable/decorative — this\n // component's real interactive semantics (role, tabindex, aria-label) live on the\n // custom-element host itself (see the `bind()` block above), since ore-button is\n // formAssociated and needs the host, not an inner element, to carry ElementInternals.\n // This differs from ore-navbar-item / ore-sidebar-item, which aren't form-associated\n // and so render their <a> as the one real focusable/semantic element.\n return html`\n ${() =>\n isLink.value\n ? html`<a\n part=\"button\"\n role=\"presentation\"\n tabindex=\"-1\"\n href=\"${props.href}\"\n :rel=\"${effectiveRel}\"\n :target=\"${props.target}\"\n @click=\"${handleClick}\">\n ${buttonContent}\n </a>`\n : html`<span part=\"button\" role=\"presentation\" @click=\"${handleClick}\">${buttonContent}</span>`}\n `;\n },\n shadow: { delegatesFocus: false },\n styles: [\n colorThemeMixin,\n coarsePointerMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n forcedColorsMixin,\n sizeVariantMixin({\n lg: {\n fontSize: 'var(--text-base)',\n gap: 'var(--size-2-5)',\n height: 'var(--size-12)',\n iconSize: 'var(--size-6)',\n lineHeight: 'var(--leading-relaxed)',\n padding: 'var(--size-2-5) var(--size-5)',\n },\n sm: {\n fontSize: 'var(--text-sm)',\n gap: 'var(--size-1-5)',\n height: 'var(--size-8)',\n iconSize: 'var(--size-4)',\n lineHeight: 'var(--leading-tight)',\n padding: 'var(--size-1-5) var(--size-3)',\n },\n }),\n frostVariantMixin('button'),\n rainbowEffectMixin('button'),\n shineEffectMixin('button'),\n disabledLoadingMixin,\n componentStyles,\n ],\n});\n","@layer refine.base {\n :host {\n display: flex;\n gap: var(--size-1);\n align-items: center;\n }\n\n .pagination {\n display: flex;\n gap: var(--pagination-gap, var(--size-1));\n align-items: center;\n padding: 0;\n margin: 0;\n list-style: none;\n }\n\n li {\n display: contents;\n }\n\n button {\n all: unset;\n box-sizing: border-box;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: var(--pagination-item-size, var(--size-9));\n height: var(--pagination-item-size, var(--size-9));\n min-height: var(--_touch-target);\n padding: 0 var(--size-2);\n font-size: var(--_font-size, var(--text-sm));\n font-weight: var(--font-medium);\n color: var(--color-contrast-700);\n cursor: pointer;\n user-select: none;\n border: var(--border) solid transparent;\n border-radius: var(--pagination-radius, var(--rounded-lg));\n transition:\n background var(--transition-fast),\n color var(--transition-fast),\n border-color var(--transition-fast);\n }\n\n /* Default (ghost-like) behavior unless variant is specified */\n :host(:not([variant])) button,\n :host([variant='ghost']) button {\n color: var(--color-contrast-700);\n background: transparent;\n border-color: transparent;\n border-width: 0;\n }\n\n :host(:not([variant])) button:hover:not(:disabled, [aria-current='page']),\n :host([variant='ghost']) button:hover:not(:disabled, [aria-current='page']) {\n background: var(--_theme-backdrop);\n }\n\n :host([variant='solid']) button {\n color: var(--_theme-contrast);\n background: var(--_theme-base);\n border-color: var(--_theme-base);\n }\n\n :host([variant='solid']) button:hover:not(:disabled, [aria-current='page']) {\n background: var(--_theme-focus);\n }\n\n :host([variant='flat']) button {\n color: var(--_theme-base);\n background: color-mix(in oklch, var(--_theme-backdrop) 8%, var(--color-contrast-100));\n border-color: color-mix(in oklch, var(--_theme-focus) 20%, transparent);\n box-shadow: var(--inset-shadow-2xs);\n }\n\n :host([variant='flat']) button:hover:not(:disabled, [aria-current='page']) {\n color: var(--_theme-contrast);\n background: var(--_theme-focus);\n }\n\n :host([variant='bordered']) button {\n color: var(--_theme-base);\n background: var(--_theme-backdrop);\n border-color: var(--_theme-border);\n box-shadow: var(--inset-shadow-xs);\n }\n\n :host([variant='bordered']) button:hover:not(:disabled, [aria-current='page']) {\n color: var(--_theme-contrast);\n background: var(--_theme-focus);\n border-color: var(--_theme-focus);\n }\n\n :host([variant='outline']) button {\n color: var(--_theme-base);\n background: transparent;\n border-color: var(--_theme-base);\n }\n\n :host([variant='outline']) button:hover:not(:disabled, [aria-current='page']) {\n background: var(--_theme-backdrop);\n border-color: var(--_theme-focus);\n }\n\n :host([variant='text']) button {\n color: var(--_theme-base);\n background: transparent;\n border-color: transparent;\n border-width: 0;\n }\n\n :host([variant='text']) button:hover:not(:disabled, [aria-current='page']) {\n color: var(--_theme-focus);\n background: transparent;\n }\n\n :host([variant='frost']) button {\n color: var(--_theme-content);\n background: color-mix(in oklch, var(--_theme-backdrop) 45%, transparent);\n border-color: color-mix(in oklch, var(--_theme-border) 45%, transparent);\n backdrop-filter: blur(var(--blur-xl)) saturate(200%);\n }\n\n :host([variant='frost']) button:hover:not(:disabled, [aria-current='page']) {\n background: color-mix(in oklch, var(--_theme-backdrop) 65%, transparent);\n border-color: color-mix(in oklch, var(--_theme-focus) 55%, transparent);\n }\n\n :host([variant='glass']) button {\n color: var(--_theme-content);\n background: color-mix(in oklch, var(--color-canvas) 70%, transparent);\n border-color: color-mix(in oklch, var(--_theme-border) 40%, transparent);\n backdrop-filter: blur(var(--blur-md)) saturate(140%);\n }\n\n :host([variant='glass']) button:hover:not(:disabled, [aria-current='page']) {\n background: color-mix(in oklch, var(--color-canvas) 55%, transparent);\n border-color: color-mix(in oklch, var(--_theme-border) 45%, transparent);\n }\n\n button:hover:not(:disabled, [aria-current='page']) {\n background: var(--color-contrast-100);\n }\n\n button:focus-visible {\n outline: var(--border-2) solid var(--_theme-base, var(--color-contrast-500));\n outline-offset: var(--border-2);\n }\n\n /* Selected page styling - applies to all variants */\n button[aria-current='page'] {\n font-weight: var(--font-bold);\n color: var(--_theme-contrast, var(--color-canvas));\n cursor: default;\n background: var(--_theme-base, var(--color-contrast-800));\n border-color: var(--_theme-base, var(--color-contrast-800));\n }\n\n :host([variant='ghost']) button[aria-current='page'],\n :host(:not([variant])) button[aria-current='page'] {\n color: var(--_theme-contrast);\n background: var(--_theme-focus);\n border-color: var(--_theme-focus);\n }\n\n :host([variant='solid']) button[aria-current='page'] {\n background: var(--_theme-focus);\n border-color: var(--_theme-focus);\n }\n\n :host([variant='flat']) button[aria-current='page'] {\n color: var(--_theme-contrast);\n background: var(--_theme-base);\n border-color: var(--_theme-base);\n }\n\n :host([variant='bordered']) button[aria-current='page'] {\n color: var(--_theme-contrast);\n background: var(--_theme-focus);\n border-color: var(--_theme-focus);\n }\n\n :host([variant='outline']) button[aria-current='page'] {\n color: var(--_theme-contrast);\n background: var(--_theme-base);\n border-color: var(--_theme-base);\n }\n\n :host([variant='text']) button[aria-current='page'] {\n color: var(--_theme-focus);\n text-decoration-line: underline;\n text-decoration-thickness: 2px;\n text-underline-offset: 4px;\n }\n\n :host([variant='frost']) button[aria-current='page'] {\n color: var(--_theme-contrast);\n background: color-mix(in oklch, var(--_theme-base) 70%, transparent);\n border-color: var(--_theme-base);\n }\n\n :host([variant='glass']) button[aria-current='page'] {\n color: var(--_theme-contrast);\n background: color-mix(in oklch, var(--color-canvas) 90%, transparent);\n border-color: var(--_theme-base);\n }\n\n button:disabled {\n cursor: not-allowed;\n opacity: 0.4;\n }\n\n .ellipsis {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: var(--pagination-item-size, var(--size-9));\n height: var(--pagination-item-size, var(--size-9));\n font-size: var(--_font-size, var(--text-sm));\n color: var(--color-contrast-400);\n cursor: default;\n }\n}\n\n@layer refine.utilities {\n :host([size='sm']) {\n --pagination-item-size: var(--size-7);\n --pagination-gap: var(--size-0_5);\n --_font-size: var(--text-xs);\n }\n\n :host([size='lg']) {\n --pagination-item-size: var(--size-11);\n --_font-size: var(--text-base);\n }\n}\n","import { define, html, prop } from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\n\nimport '../icon/icon';\nimport '../../inputs/button/button';\nimport type { ComponentSize, ThemeColor, VisualVariant } from '../../types';\n\nimport { sizableBundle, themableBundle } from '../../shared';\nimport { coarsePointerMixin, colorThemeMixin, sizeVariantMixin } from '../../styles';\nimport componentStyles from './pagination.css?inline';\n\nexport type OrePaginationEvents = {\n change: { page: number };\n};\n\nexport type OrePaginationProps = {\n color?: ThemeColor;\n label?: string;\n page?: number;\n 'show-first-last'?: boolean;\n 'show-prev-next'?: boolean;\n siblings?: number;\n size?: ComponentSize;\n 'total-pages'?: number;\n variant?: VisualVariant;\n};\n\nfunction buildPageRange(\n currentPage: number,\n totalPages: number,\n siblings: number,\n): Array<number | 'ellipsis-start' | 'ellipsis-end'> {\n const BOUNDARY = 1; // always show first and last page\n const total = totalPages;\n const pages: Array<number | 'ellipsis-start' | 'ellipsis-end'> = [];\n\n // If total is small enough, show all pages\n if (total <= 2 * BOUNDARY + 2 * siblings + 3) {\n return Array.from({ length: total }, (_, i) => i + 1);\n }\n\n const leftSibling = Math.max(currentPage - siblings, BOUNDARY + 1);\n const rightSibling = Math.min(currentPage + siblings, total - BOUNDARY);\n\n pages.push(1);\n\n if (leftSibling > BOUNDARY + 2) pages.push('ellipsis-start');\n else if (leftSibling === BOUNDARY + 2) pages.push(BOUNDARY + 1);\n\n for (let i = leftSibling; i <= rightSibling; i++) pages.push(i);\n\n if (rightSibling < total - BOUNDARY - 1) pages.push('ellipsis-end');\n else if (rightSibling === total - BOUNDARY - 1) pages.push(total - BOUNDARY);\n\n pages.push(total);\n\n return pages;\n}\n\n/**\n * Page-based navigation control.\n *\n * @element ore-pagination\n *\n * @attr {number} page - Current page (1-indexed, default: 1)\n * @attr {number} total-pages - Total number of pages (required)\n * @attr {number} siblings - Sibling pages around current (default: 1)\n * @attr {boolean} show-first-last - Show first/last page buttons (default: false)\n * @attr {boolean} show-prev-next - Show prev/next buttons (default: false)\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} variant - Visual variant for nav buttons: 'solid' | 'flat' | 'bordered' | 'outline' | 'ghost' | 'text' | 'frost' (default: 'ghost')\n * @attr {string} size - 'sm' | 'md' | 'lg'\n * @attr {string} label - Accessible nav label (default: 'Pagination')\n *\n * @fires change - Emitted when the page changes, with { page: number }\n *\n * @cssprop --pagination-item-size - Width/height of each item\n * @cssprop --pagination-gap - Gap between items\n * @cssprop --pagination-radius - Border radius of items\n *\n * @part page-btn - Page button.\n * @part nav - Navigation container.\n * @part list - List container.\n * @part first-btn - First page button.\n * @part prev-btn - Previous page button.\n * @part next-btn - Next page button.\n * @part last-btn - Last page button.\n * @example\n * ```html\n * <!-- Basic -->\n * <ore-pagination page=\"3\" total-pages=\"10\" color=\"primary\"></ore-pagination>\n *\n * <!-- With prev/next and first/last buttons -->\n * <ore-pagination page=\"5\" total-pages=\"20\" show-prev-next show-first-last siblings=\"2\"></ore-pagination>\n *\n * <!-- Compact size -->\n * <ore-pagination page=\"1\" total-pages=\"5\" size=\"sm\" variant=\"ghost\"></ore-pagination>\n * ```\n */\nexport const PAGINATION_TAG = 'ore-pagination' as const;\ndefine<OrePaginationProps, OrePaginationEvents>(PAGINATION_TAG, {\n props: {\n ...themableBundle,\n ...sizableBundle,\n label: prop.string('Pagination'),\n page: prop.number(1),\n 'show-first-last': prop.bool(false),\n 'show-prev-next': prop.bool(false),\n siblings: prop.number(1),\n 'total-pages': prop.number(1),\n variant: prop.string<VisualVariant>(),\n },\n setup(props, { bind: _bind, el, emit }) {\n function goTo(page: number) {\n const total = props['total-pages'].value || 1;\n const next = Math.min(Math.max(1, page), total);\n\n if (next === props.page.value) return;\n\n el.setAttribute('page', String(next));\n emit('change', { page: next });\n }\n\n const pageItems = computed(() =>\n buildPageRange(props.page.value || 1, props['total-pages'].value || 1, props.siblings.value ?? 1),\n );\n\n const isFirst = computed(() => (props.page.value || 1) <= 1);\n const isLast = computed(() => (props.page.value || 1) >= (props['total-pages'].value || 1));\n\n return html`\n <nav :aria-label=\"${props.label}\" part=\"nav\">\n <ol class=\"pagination\" part=\"list\">\n ${() =>\n props['show-first-last'].value\n ? html`<li>\n <button\n type=\"button\"\n class=\"nav-btn\"\n part=\"first-btn\"\n aria-label=\"First page\"\n ?disabled=${isFirst}\n @click=${() => goTo(1)}>\n <ore-icon name=\"chevrons-left\" size=\"16\" aria-hidden=\"true\"></ore-icon>\n </button>\n </li>`\n : ''}\n ${() =>\n props['show-prev-next'].value\n ? html`<li>\n <button\n type=\"button\"\n class=\"nav-btn\"\n part=\"prev-btn\"\n aria-label=\"Previous page\"\n ?disabled=${isFirst}\n @click=${() => goTo((props.page.value || 1) - 1)}>\n <ore-icon name=\"chevron-left\" size=\"16\" aria-hidden=\"true\"></ore-icon>\n </button>\n </li>`\n : ''}\n <li style=\"display: contents;\">\n ${() =>\n pageItems.value.map((item) => {\n if (item === 'ellipsis-start' || item === 'ellipsis-end') {\n return html`<span class=\"ellipsis\" aria-hidden=\"true\">…</span>`;\n }\n\n const pg = item as number;\n const isCurrent = pg === (props.page.value || 1);\n const pgLabel = `Page ${pg}`;\n\n return isCurrent\n ? html`<button\n type=\"button\"\n part=\"page-btn\"\n aria-label=\"${pgLabel}\"\n aria-current=\"page\"\n @click=${() => goTo(pg)}>\n ${pg}\n </button>`\n : html`<button type=\"button\" part=\"page-btn\" aria-label=\"${pgLabel}\" @click=${() => goTo(pg)}>\n ${pg}\n </button>`;\n })}\n </li>\n ${() =>\n props['show-prev-next'].value\n ? html`<li>\n <button\n type=\"button\"\n class=\"nav-btn\"\n part=\"next-btn\"\n aria-label=\"Next page\"\n ?disabled=${isLast}\n @click=${() => goTo((props.page.value || 1) + 1)}>\n <ore-icon name=\"chevron-right\" size=\"16\" aria-hidden=\"true\"></ore-icon>\n </button>\n </li>`\n : ''}\n ${() =>\n props['show-first-last'].value\n ? html`<li>\n <button\n type=\"button\"\n class=\"nav-btn\"\n part=\"last-btn\"\n aria-label=\"Last page\"\n ?disabled=${isLast}\n @click=${() => goTo(props['total-pages'].value || 1)}>\n <ore-icon name=\"chevrons-right\" size=\"16\" aria-hidden=\"true\"></ore-icon>\n </button>\n </li>`\n : ''}\n </ol>\n </nav>\n `;\n },\n\n styles: [coarsePointerMixin, colorThemeMixin, sizeVariantMixin(), componentStyles],\n});\n","@layer refine.base {\n :host {\n --_color: var(--separator-color, var(--color-contrast-300));\n --_size: var(--separator-size, var(--border));\n --_spacing: var(--separator-spacing, 0);\n\n display: block;\n }\n\n .separator {\n all: unset;\n box-sizing: border-box;\n display: block;\n margin: var(--_spacing) 0;\n }\n\n :host([orientation='horizontal']),\n :host(:not([orientation='vertical'])) {\n width: 100%;\n }\n\n :host([orientation='horizontal']) .separator,\n :host(:not([orientation='vertical'])) .separator {\n width: 100%;\n border-top: var(--_size) solid var(--_color);\n }\n\n :host([orientation='vertical']) {\n display: inline-block;\n align-self: stretch;\n }\n\n :host([orientation='vertical']) .separator {\n height: 100%;\n border-inline-start: var(--_size) solid var(--_color);\n }\n\n :host([color]) {\n --_color: var(--_theme-base);\n }\n\n /* Labelled separator */\n .separator-wrapper {\n display: flex;\n gap: var(--size-3);\n align-items: center;\n }\n\n .separator-wrapper .separator {\n flex: 1;\n }\n\n :host([orientation='vertical']) .separator-wrapper {\n flex-direction: column;\n align-self: stretch;\n height: 100%;\n }\n\n :host([orientation='vertical']) .separator-wrapper .separator {\n flex: 1;\n width: auto;\n height: auto;\n border-inline-start: var(--_size) solid var(--_color);\n border-top: none;\n }\n\n .separator-label {\n font-size: var(--text-xs);\n font-weight: var(--font-medium);\n color: var(--_color);\n white-space: nowrap;\n }\n}\n","import { define, html, prop } from '@vielzeug/ore';\n\nimport type { ThemeColor } from '../../types';\n\nimport { colorThemeMixin } from '../../styles';\nimport componentStyles from './separator.css?inline';\n\n/** Separator component properties */\nexport type OreSeparatorProps = {\n /** Theme color tint */\n color?: ThemeColor;\n /** Decorative only (default true) — set to false for semantic separators */\n decorative?: boolean;\n /** Optional label text centered on the separator */\n label?: string;\n /** Orientation of the separator */\n orientation?: 'horizontal' | 'vertical';\n};\n\n/**\n * A simple visual divider between sections of content.\n *\n * @element ore-separator\n *\n * @attr {string} orientation - 'horizontal' (default) | 'vertical'\n * @attr {boolean} decorative - When true (default), aria-hidden is applied\n * @attr {string} label - Optional centered label text\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n *\n * @cssprop --separator-color - Line color\n * @cssprop --separator-size - Line thickness\n * @cssprop --separator-spacing - Vertical margin\n *\n * @part wrapper - Root wrapper container.\n * @part separator - Separator element.\n * @part label - Label element.\n * @example\n * ```html\n * <ore-separator></ore-separator>\n * <ore-separator label=\"or\"></ore-separator>\n * <ore-separator orientation=\"vertical\"></ore-separator>\n * ```\n */\nexport const SEPARATOR_TAG = 'ore-separator' as const;\ndefine<OreSeparatorProps>(SEPARATOR_TAG, {\n props: {\n color: prop.string<ThemeColor>(),\n decorative: prop.bool(true),\n label: prop.string(),\n orientation: prop.oneOf(['horizontal', 'vertical'] as const, 'horizontal'),\n },\n setup(props) {\n const roleAttr = () => (props.decorative.value ? 'none' : 'separator');\n const ariaHidden = () => (props.decorative.value ? 'true' : null);\n\n return html`\n ${() =>\n props.label.value\n ? html`\n <div class=\"separator-wrapper\" part=\"wrapper\">\n <hr\n class=\"separator\"\n part=\"separator\"\n :role=\"${roleAttr}\"\n :aria-hidden=\"${ariaHidden}\"\n :aria-orientation=\"${() => props.orientation.value}\" />\n <span class=\"separator-label\" part=\"label\">${() => props.label.value}</span>\n <hr\n class=\"separator\"\n part=\"separator\"\n :role=\"${roleAttr}\"\n :aria-hidden=\"${ariaHidden}\"\n :aria-orientation=\"${() => props.orientation.value}\" />\n </div>\n `\n : html`\n <hr\n class=\"separator\"\n part=\"separator\"\n :role=\"${roleAttr}\"\n :aria-hidden=\"${ariaHidden}\"\n :aria-orientation=\"${() => props.orientation.value}\" />\n `}\n `;\n },\n styles: [colorThemeMixin, componentStyles],\n});\n","/* ore-table — shadow DOM (proxy/mirror).\n *\n * Shadow tree (managed by table.ts):\n * :host display:block — token host (tableBaseMixin)\n * └─ .scroll-container overflow:auto — sticky / max-height context\n * └─ table display:table — native table semantics\n * ├─ caption — optional caption bar\n * ├─ thead — rows built from ore-tr[head]\n * ├─ tbody — rows built from plain ore-tr\n * └─ tfoot — rows built from ore-tr[foot]\n * └─ tr > th / td — mirrored from ore-th / ore-td\n *\n * Light DOM (consumer):\n * <ore-tr head><ore-th>…</ore-th></ore-tr>\n * <ore-tr><ore-td>…</ore-td></ore-tr>\n * <ore-tr foot><ore-td>…</ore-td></ore-tr>\n *\n * tableBaseMixin('table') handles: :host tokens, .scroll-container,\n * table width/collapse, loading state, size variants, fullwidth, bordered,\n * and sticky scroll-container activation.\n * This file handles: caption, section backgrounds, body tr/th/td, and variants.\n * No ::slotted() needed — the shadow tree owns all rendered th/td elements.\n */\n\n@layer refine.base {\n :host {\n border: none;\n border-radius: 0;\n box-shadow: var(--table-shadow, none);\n }\n\n /* ── Caption ─────────────────────────────────────────────────────────── */\n\n caption {\n padding: var(--size-3);\n font-size: var(--text-xs);\n font-weight: var(--font-semibold);\n color: var(--color-contrast-500);\n text-align: start;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n caption-side: top;\n background: var(--_header-bg);\n }\n\n /* ── Section backgrounds ─────────────────────────────────────────────── */\n\n thead,\n tfoot {\n background: var(--_header-bg);\n }\n\n thead {\n border-block-end: var(--border) solid var(--_border-color);\n }\n\n tfoot {\n border-block-start: var(--border) solid var(--_border-color);\n }\n\n /* ── Body rows ───────────────────────────────────────────────────────── */\n\n tbody tr {\n border-block-end: var(--border) solid var(--_border-color);\n transition: background var(--transition-fast);\n }\n\n tbody tr:hover {\n background: var(--_row-hover-bg);\n }\n\n /* ── Cells ───────────────────────────────────────────────────────────── */\n\n th,\n td {\n padding: var(--_cell-padding-y) var(--_cell-padding-x);\n font-size: var(--_font-size);\n font-weight: normal;\n vertical-align: middle;\n color: var(--color-contrast-800);\n text-align: start;\n }\n\n /* ── Header cells ────────────────────────────────────────────────────── */\n\n thead th,\n thead td,\n tfoot th,\n tfoot td {\n font-size: var(--text-xs);\n font-weight: var(--font-semibold);\n color: var(--color-contrast-500);\n text-transform: uppercase;\n letter-spacing: 0.04em;\n white-space: nowrap;\n user-select: none;\n }\n}\n\n@layer refine.variants {\n /* ── Bordered: vertical cell separators ─────────────────────────────── */\n\n :host([bordered]) th,\n :host([bordered]) td {\n border-inline-end: var(--border) solid var(--_border-color);\n }\n\n :host([bordered]) th:last-child,\n :host([bordered]) td:last-child {\n border-inline-end: none;\n }\n\n /* ── Striped ─────────────────────────────────────────────────────────── */\n\n :host([striped]) tbody tr:nth-child(even) {\n background: var(--_stripe-bg);\n }\n\n /* ── Sticky header ───────────────────────────────────────────────────── */\n\n /* tableBaseMixin activates overflow-y:auto on .scroll-container when\n [sticky] is present. position:sticky on thead is relative to that context. */\n\n :host([sticky]) thead {\n position: sticky;\n top: 0;\n z-index: 2;\n background: var(--table-sticky-header-bg, color-mix(in oklch, var(--_header-bg) 94%, transparent));\n\n /* border-collapse merges the bottom border into the cell below, which\n scrolls away under the sticky header. Use box-shadow instead — it\n travels with the element regardless of border-collapse. */\n box-shadow: inset 0 calc(var(--border) * -1) 0 var(--_border-color);\n backdrop-filter: blur(var(--table-sticky-blur, var(--blur-md))) saturate(140%);\n }\n}\n","import { define, html, prop } from '@vielzeug/ore';\n\nimport { reducedMotionMixin, tableBaseMixin } from '../../styles';\nimport componentStyles from './table.css?inline';\n\n/* ── Types ───────────────────────────────────────────────────────────────── */\n\n/** Table component properties */\nexport type OreTableProps = {\n /** Adds a thicker outer border */\n bordered?: boolean;\n /** Visible caption text — also used as the accessible table label via `aria-label` */\n caption?: string;\n /** Cell density: `'compact'` | `'cozy'` (default) | `'comfortable'` */\n density?: 'compact' | 'cozy' | 'comfortable';\n /** Expands the table to 100% of its container width */\n fullwidth?: boolean;\n /** Applies a busy/disabled state with reduced opacity */\n loading?: boolean;\n /** Enables sticky column headers with a vertical scroll container */\n sticky?: boolean;\n /** Alternating row stripe backgrounds */\n striped?: boolean;\n};\n\n/* ── Child element markers ───────────────────────────────────────────────── */\n// ore-tr, ore-th, ore-td are lightweight light-DOM markers.\n// ore-table reads them and constructs a fully-native shadow <table> so that\n// browser features that require real table elements (colspan/rowspan,\n// position:sticky on <thead>, table layout algorithm) all work correctly.\n// Attributes on ore-th/ore-td are mirrored to the generated native cells.\n\n/**\n * Light-DOM row marker consumed by `<ore-table>`.\n *\n * @element ore-tr\n * @attr {boolean} head - Places the row in the generated `<thead>` section\n * @attr {boolean} foot - Places the row in the generated `<tfoot>` section\n *\n * @example\n * ```html\n * <ore-table>\n * <ore-tr head><ore-th>Name</ore-th><ore-th>Role</ore-th></ore-tr>\n * <ore-tr><ore-td>Alice</ore-td><ore-td>Admin</ore-td></ore-tr>\n * </ore-table>\n * ```\n */\nif (!customElements.get('ore-tr')) customElements.define('ore-tr', class extends HTMLElement {});\n\n/**\n * Light-DOM header cell marker consumed by `<ore-table>`.\n *\n * @element ore-th\n * @attr {number} colspan - Mirrors to native `<th colspan>`\n * @attr {number} rowspan - Mirrors to native `<th rowspan>`\n * @attr {string} scope - Mirrors to native `<th scope>`: 'col' | 'row' | 'colgroup' | 'rowgroup'\n * @attr {string} headers - Mirrors to native `<th headers>`\n *\n * @example\n * ```html\n * <ore-tr head>\n * <ore-th scope=\"col\">Name</ore-th>\n * <ore-th scope=\"col\" colspan=\"2\">Address</ore-th>\n * </ore-tr>\n * ```\n */\nif (!customElements.get('ore-th')) customElements.define('ore-th', class extends HTMLElement {});\n\n/**\n * Light-DOM data cell marker consumed by `<ore-table>`.\n *\n * @element ore-td\n * @attr {number} colspan - Mirrors to native `<td colspan>`\n * @attr {number} rowspan - Mirrors to native `<td rowspan>`\n * @attr {string} headers - Mirrors to native `<td headers>`\n *\n * @example\n * ```html\n * <ore-tr>\n * <ore-td>Alice</ore-td>\n * <ore-td colspan=\"2\">123 Main St, Springfield</ore-td>\n * </ore-tr>\n * ```\n */\nif (!customElements.get('ore-td')) customElements.define('ore-td', class extends HTMLElement {});\n\n/* ── Proxy/mirror helpers ────────────────────────────────────────────────── */\n\n// Attributes forwarded from ore-th/ore-td to the generated native cell.\n// scope is intentionally excluded — it requires fallback logic and is handled separately.\nconst CELL_ATTRS = ['colspan', 'rowspan', 'headers', 'abbr'];\n\n/**\n * Sync text content and tracked attributes from a light-DOM marker to its\n * native mirror. `fallbackScope` is applied when the source element carries no\n * explicit `scope` attribute, ensuring the auto-inferred value is always\n * present and is restored if an explicit override is later removed.\n */\nfunction syncCell(source: Element, native: HTMLTableCellElement, fallbackScope?: string): void {\n if (source.childElementCount > 0) {\n // Source has element children — deep-clone them into the native cell so\n // components like ore-skeleton render correctly inside the shadow table.\n // Guard: skip re-clone if the serialised content is identical to avoid\n // redundant DOM work on every MutationObserver tick (e.g. 250+ cells\n // of skeleton loaders all cloning on each attribute change).\n const snapshot = source.innerHTML;\n\n if (native.getAttribute('data-src-html') === snapshot) return;\n\n native.setAttribute('data-src-html', snapshot);\n native.textContent = '';\n\n for (const child of source.childNodes) {\n native.appendChild(child.cloneNode(true));\n }\n } else {\n const text = source.textContent ?? '';\n\n if (native.textContent !== text) native.textContent = text;\n }\n\n for (const attr of CELL_ATTRS) {\n const val = source.getAttribute(attr);\n\n if (val !== null) native.setAttribute(attr, val);\n else native.removeAttribute(attr);\n }\n\n // scope: explicit attribute wins; otherwise restore the inferred fallback.\n const explicitScope = source.getAttribute('scope');\n\n if (explicitScope !== null) native.setAttribute('scope', explicitScope);\n else if (fallbackScope) native.scope = fallbackScope;\n else native.removeAttribute('scope');\n}\n\n/** Entry stored in the cell map: native mirror element + its inferred scope fallback. */\ntype CellEntry = { inferredScope: string | undefined; native: HTMLTableCellElement };\n\n/**\n * (Re)build the entire native shadow table from the current light-DOM markers.\n * Returns a WeakMap of source marker → CellEntry for targeted sync by the\n * content observer. Storing `inferredScope` per cell ensures that removing an\n * explicit `scope` attribute reverts to the auto-inferred value rather than\n * dropping it entirely.\n */\nfunction buildTable(\n host: HTMLElement,\n thead: HTMLTableSectionElement,\n tbody: HTMLTableSectionElement,\n tfoot: HTMLTableSectionElement,\n): WeakMap<Element, CellEntry> {\n const cellMap = new WeakMap<Element, CellEntry>();\n\n thead.textContent = '';\n tbody.textContent = '';\n tfoot.textContent = '';\n\n for (const child of host.children) {\n if (child.localName !== 'ore-tr') continue;\n\n const section = child.hasAttribute('head') ? thead : child.hasAttribute('foot') ? tfoot : tbody;\n const tr = document.createElement('tr');\n\n for (const cell of child.children) {\n if (cell.localName !== 'ore-th' && cell.localName !== 'ore-td') continue;\n\n const isHeader = cell.localName === 'ore-th';\n const native = document.createElement(isHeader ? 'th' : 'td');\n // Auto-infer scope for <th> elements; undefined for <td>.\n const inferredScope = isHeader ? (section === thead ? 'col' : 'row') : undefined;\n\n native.setAttribute('part', section === tbody ? 'cell' : 'header-cell');\n native.removeAttribute('data-src-html');\n syncCell(cell, native, inferredScope);\n cellMap.set(cell, { inferredScope, native });\n tr.appendChild(native);\n }\n\n section.appendChild(tr);\n }\n\n return cellMap;\n}\n\n/**\n * Data table component.\n *\n * Reads light-DOM `<ore-tr>`/`<ore-th>`/`<ore-td>` markers and projects them\n * into a fully-native shadow `<table>`. Cell attributes (`colspan`, `rowspan`,\n * `scope`, etc.) are mirrored. Changes are observed and synced incrementally.\n *\n * Native table features — sticky headers, colspan/rowspan, the table layout\n * algorithm — all work because the shadow tree contains real table elements.\n *\n * @element ore-table\n *\n * @attr {boolean} bordered - Thicker outer border\n * @attr {string} caption - Caption text shown above the table\n * @attr {boolean} fullwidth - Expands to 100% container width\n * @attr {boolean} loading - Busy state: reduced opacity, no pointer events\n * @attr {string} density - Cell density: 'compact' | 'cozy' | 'comfortable' (default: 'cozy')\n * @attr {boolean} sticky - Sticky `<thead>` with scroll container\n * @attr {boolean} striped - Alternating row backgrounds\n *\n * @part scroll - Scroll container that hosts the generated native table\n * @part table - Generated native `<table>` element\n * @part head - Generated native `<thead>` section\n * @part body - Generated native `<tbody>` section\n * @part foot - Generated native `<tfoot>` section\n * @part cell - Every native `<td>` in `<tbody>` rows\n * @part header-cell - Every native `<th>` / `<td>` in `<thead>` and `<tfoot>` rows\n *\n * @cssprop --table-bg - Table background color\n * @cssprop --table-border-color - Cell separator and outer border color\n * @cssprop --table-radius - Corner radius of the table container\n * @cssprop --table-shadow - Box shadow of the table container\n * @cssprop --table-header-bg - Background of header and footer rows\n * @cssprop --table-accent - Accent color for interactive states\n * @cssprop --table-row-hover-bg - Row hover background\n * @cssprop --table-stripe-bg - Even-row stripe background\n * @cssprop --table-cell-padding-x - Cell horizontal padding\n * @cssprop --table-cell-padding-y - Cell vertical padding\n * @cssprop --table-font-size - Base font size for cells\n * @cssprop --table-sticky-max-height - Max height of the sticky scroll container\n * @cssprop --table-sticky-header-bg - Background of sticky header cells\n * @cssprop --table-sticky-blur - Backdrop blur applied to sticky headers\n *\n * @example\n * ```html\n * <ore-table caption=\"Top repositories\" striped bordered sticky>\n * <ore-tr head>\n * <ore-th>Repository</ore-th>\n * <ore-th>Stars</ore-th>\n * </ore-tr>\n * <ore-tr>\n * <ore-td>vielzeug/refine</ore-td>\n * <ore-td>1 200</ore-td>\n * </ore-tr>\n * </ore-table>\n * ```\n */\nexport const TABLE_TAG = 'ore-table' as const;\ndefine<OreTableProps>(TABLE_TAG, {\n props: {\n bordered: prop.bool(false),\n caption: prop.string(),\n density: prop.string<'compact' | 'cozy' | 'comfortable'>(),\n fullwidth: prop.bool(false),\n loading: prop.bool(false),\n sticky: prop.bool(false),\n striped: prop.bool(false),\n },\n\n setup(props, { bind, el, onMounted, watch }) {\n bind({\n attr: {\n 'aria-busy': props.loading,\n 'aria-label': props.caption,\n },\n });\n\n // Build the native shadow table via DOM APIs (not innerHTML) to avoid\n // HTML-parser foster-parenting, which ejects table section elements from\n // their intended positions in the tree.\n onMounted(() => {\n const scrollContainer = el.shadowRoot!.querySelector('.scroll-container')!;\n\n const table = document.createElement('table');\n const captionEl = document.createElement('caption');\n const thead = document.createElement('thead');\n const tbody = document.createElement('tbody');\n const tfoot = document.createElement('tfoot');\n\n scrollContainer.setAttribute('part', 'scroll');\n table.setAttribute('part', 'table');\n thead.setAttribute('part', 'head');\n tbody.setAttribute('part', 'body');\n tfoot.setAttribute('part', 'foot');\n table.append(captionEl, thead, tbody, tfoot);\n scrollContainer.appendChild(table);\n\n // Reactively sync caption text and visibility from prop.\n watch(() => {\n const text = props.caption.value ?? '';\n\n captionEl.textContent = text;\n captionEl.hidden = text === '';\n });\n\n // Initial full build.\n let cellMap = buildTable(el, thead, tbody, tfoot);\n\n // Content observer: syncs text/attribute changes inside ore-th/ore-td.\n // Remains connected throughout the component lifetime — no\n // disconnect/reconnect during structural rebuilds. Records that arrive\n // for cells no longer in cellMap (after a rebuild) are silently ignored\n // by the `if (entry)` guard, so there is no correctness risk.\n const contentObserver = new MutationObserver((records) => {\n for (const rec of records) {\n const sourceCell = (rec.target instanceof Element ? rec.target : rec.target.parentElement)?.closest(\n 'ore-th, ore-td',\n );\n\n if (sourceCell) {\n const entry = cellMap.get(sourceCell);\n\n if (entry) syncCell(sourceCell, entry.native, entry.inferredScope);\n }\n }\n });\n\n contentObserver.observe(el, {\n // Include 'scope' in attributeFilter so explicit scope changes are picked\n // up and the fallback-restore logic in syncCell runs correctly.\n attributeFilter: [...CELL_ATTRS, 'scope'],\n attributes: true,\n characterData: true,\n childList: true,\n subtree: true,\n });\n\n // Structure observer: triggers a full rebuild when ore-tr elements are\n // added, removed, or reordered. Scoped to direct children only so it\n // never fires for cell-level mutations.\n const structureObserver = new MutationObserver(() => {\n cellMap = buildTable(el, thead, tbody, tfoot);\n });\n\n structureObserver.observe(el, { childList: true });\n\n return () => {\n structureObserver.disconnect();\n contentObserver.disconnect();\n };\n });\n\n return html`<div class=\"scroll-container\"></div>`;\n },\n\n styles: [reducedMotionMixin, tableBaseMixin('table'), componentStyles],\n});\n","/* ========================================\n Base Styles & Defaults\n ======================================== */\n\n:host {\n /* Internal variables with CSS custom property fallbacks */\n --_size: var(--text-size, var(--text-base));\n --_weight: var(--text-weight, var(--font-normal));\n --_color: var(--text-color, var(--text-color-body));\n --_line-height: var(--text-line-height, var(--leading-normal));\n --_letter-spacing: var(--text-letter-spacing, normal);\n\n display: block;\n font-size: var(--_size);\n font-weight: var(--_weight);\n line-height: var(--_line-height);\n color: var(--_color);\n letter-spacing: var(--_letter-spacing);\n}\n\n:host([hidden]) {\n display: none;\n}\n\n/* ========================================\n Unlayered display overrides\n These must live outside any @layer so they can beat the unlayered\n display: block on :host. Same cascade rule that was fixed for [lines].\n ======================================== */\n\n/* Multi-line truncation */\n:host([lines]) {\n display: -webkit-box;\n -webkit-box-orient: vertical;\n overflow: hidden;\n -webkit-line-clamp: var(--_lines);\n}\n\n/* Inline semantic tags — but not when align/truncate force block layout */\n:host(:is([as='span'], [as='label'], [as='code']):not([align], [truncate])) {\n display: inline;\n}\n\n/* ========================================\n Variant Styles\n ======================================== */\n\n/* Body (default) — uses base defaults above */\n\n/* Heading\n Default size: --heading-md (24px)\n Letter-spacing: --tracking-header (-0.05em) per theme guidelines\n Line-height: --leading-tight (1.15) for display headings */\n:host([variant='heading']) {\n --_size: var(--text-size, var(--heading-md));\n --_weight: var(--text-weight, var(--font-semibold));\n --_color: var(--text-color, var(--text-color-heading));\n --_line-height: var(--text-line-height, var(--leading-tight));\n --_letter-spacing: var(--text-letter-spacing, var(--tracking-header));\n}\n\n/* Label — slightly tighter line-height for UI labels */\n:host([variant='label']) {\n --_size: var(--text-size, var(--text-sm));\n --_weight: var(--text-weight, var(--font-medium));\n --_color: var(--text-color, var(--text-color-heading));\n --_line-height: var(--text-line-height, var(--leading-snug));\n}\n\n/* Caption */\n:host([variant='caption']) {\n --_size: var(--text-size, var(--text-sm));\n --_color: var(--text-color, var(--text-color-secondary));\n}\n\n/* Overline */\n:host([variant='overline']) {\n --_size: var(--text-size, var(--text-xs));\n --_weight: var(--text-weight, var(--font-semibold));\n --_line-height: var(--text-line-height, var(--leading-none));\n --_letter-spacing: var(--text-letter-spacing, 0.08em);\n\n text-transform: uppercase;\n}\n\n/* Code */\n:host([variant='code']) {\n --_size: var(--text-size, var(--text-sm));\n\n font-family: var(--font-mono, monospace);\n}\n\n/* ========================================\n Size Variants — body scale (--text-*)\n Used by all variants except heading.\n ======================================== */\n\n:host([size='xs']) {\n --_size: var(--text-size, var(--text-xs));\n}\n\n:host([size='sm']) {\n --_size: var(--text-size, var(--text-sm));\n}\n\n:host([size='md']) {\n --_size: var(--text-size, var(--text-base));\n}\n\n:host([size='lg']) {\n --_size: var(--text-size, var(--text-lg));\n}\n\n:host([size='xl']) {\n --_size: var(--text-size, var(--text-xl));\n}\n\n:host([size='2xl']) {\n --_size: var(--text-size, var(--text-2xl));\n}\n\n/* ========================================\n Size Variants — heading scale (--heading-*)\n Compound selectors override the body-scale rules above when\n variant=\"heading\" and a size is also provided.\n ======================================== */\n\n:host([variant='heading'][size='xs']) {\n --_size: var(--text-size, var(--heading-xs));\n}\n\n:host([variant='heading'][size='sm']) {\n --_size: var(--text-size, var(--heading-sm));\n}\n\n:host([variant='heading'][size='md']) {\n --_size: var(--text-size, var(--heading-md));\n}\n\n:host([variant='heading'][size='lg']) {\n --_size: var(--text-size, var(--heading-lg));\n}\n\n:host([variant='heading'][size='xl']) {\n --_size: var(--text-size, var(--heading-xl));\n}\n\n:host([variant='heading'][size='2xl']) {\n --_size: var(--text-size, var(--heading-2xl));\n}\n\n/* ========================================\n Weight Variants\n ======================================== */\n\n:host([weight='normal']) {\n --_weight: var(--text-weight, var(--font-normal));\n}\n\n:host([weight='medium']) {\n --_weight: var(--text-weight, var(--font-medium));\n}\n\n:host([weight='semibold']) {\n --_weight: var(--text-weight, var(--font-semibold));\n}\n\n:host([weight='bold']) {\n --_weight: var(--text-weight, var(--font-bold));\n}\n\n/* ========================================\n Color Variants\n Semantic colors map to --text-color-* tokens.\n Theme colors map to --color-* base tokens.\n ======================================== */\n\n:host([color='primary']) {\n --_color: var(--text-color, var(--color-primary));\n}\n\n:host([color='secondary']) {\n --_color: var(--text-color, var(--color-secondary));\n}\n\n:host([color='info']) {\n --_color: var(--text-color, var(--color-info));\n}\n\n:host([color='success']) {\n --_color: var(--text-color, var(--color-success));\n}\n\n:host([color='warning']) {\n --_color: var(--text-color, var(--color-warning));\n}\n\n:host([color='error']) {\n --_color: var(--text-color, var(--color-error));\n}\n\n/* Semantic text colors */\n:host([color='heading']) {\n --_color: var(--text-color, var(--text-color-heading)); /* --color-contrast-900 */\n}\n\n:host([color='body']) {\n --_color: var(--text-color, var(--text-color-body)); /* --color-contrast-800 */\n}\n\n:host([color='muted']) {\n --_color: var(--text-color, var(--text-color-secondary)); /* --color-contrast-600 — AA compliant */\n}\n\n:host([color='tertiary']) {\n --_color: var(--text-color, var(--text-color-tertiary)); /* --color-contrast-500 — AA for large text */\n}\n\n:host([color='disabled']) {\n --_color: var(--text-color, var(--text-color-disabled)); /* --color-contrast-400 */\n}\n\n:host([color='contrast']) {\n --_color: var(--text-color, var(--text-color-contrast)); /* --color-contrast-100 */\n}\n\n@layer refine.utilities {\n /* ========================================\n Alignment\n ======================================== */\n\n :host([align]) {\n display: block;\n }\n\n :host([align='left']) {\n text-align: start;\n }\n\n :host([align='center']) {\n text-align: center;\n }\n\n :host([align='right']) {\n text-align: end;\n }\n\n :host([align='justify']) {\n text-align: justify;\n }\n\n /* ========================================\n Truncate (single-line)\n ======================================== */\n\n :host([truncate]) {\n display: block;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n /* ========================================\n Italic\n ======================================== */\n\n :host([italic]) {\n font-style: italic;\n }\n\n /* ========================================\n Block Display for Certain Tags\n ======================================== */\n\n :host([as='p']),\n :host([as='div']),\n :host(:is([as='h1'], [as='h2'], [as='h3'], [as='h4'], [as='h5'], [as='h6'])) {\n display: block;\n }\n\n /* Note: display: inline for span/label/code is handled outside this @layer\n (above) so it can override the unlayered :host { display: block }. */\n}\n","import { define, html, prop } from '@vielzeug/ore';\n\nimport styles from './text.css?inline';\n\n/** Text component properties */\nexport type OreTextProps = {\n /** Text alignment */\n align?: 'left' | 'center' | 'right' | 'justify';\n /** Semantic HTML element to render as — sets the correct ARIA role/level on the host */\n as?: 'span' | 'p' | 'div' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'label' | 'code';\n /** Text color (semantic + theme colors) */\n color?:\n | 'primary'\n | 'secondary'\n | 'info'\n | 'success'\n | 'warning'\n | 'error'\n | 'heading'\n | 'body'\n | 'muted'\n | 'tertiary'\n | 'disabled'\n | 'contrast';\n /** Italic text style */\n italic?: boolean;\n /** Clamp text to N lines with an ellipsis (multi-line truncation) */\n lines?: number;\n /** Text size — maps to --text-* tokens for body variants and --heading-* tokens for the heading variant */\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n /** Enable single-line text truncation with ellipsis */\n truncate?: boolean;\n /** Text semantic variant */\n variant?: 'body' | 'heading' | 'label' | 'caption' | 'overline' | 'code';\n /** Font weight */\n weight?: 'normal' | 'medium' | 'semibold' | 'bold';\n};\n\n/**\n * A typography component with semantic variants and responsive sizing.\n *\n * @element ore-text\n *\n * @attr {string} variant - Text variant: 'body' | 'heading' | 'label' | 'caption' | 'overline' | 'code'\n * @attr {string} size - Font size: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'. Maps to --text-* tokens for body variants and --heading-* tokens for the heading variant.\n * @attr {string} weight - Font weight: 'normal' | 'medium' | 'semibold' | 'bold'\n * @attr {string} color - Text color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error' | 'heading' | 'body' | 'muted' | 'tertiary' | 'disabled' | 'contrast'\n * @attr {string} align - Text alignment: 'left' | 'center' | 'right' | 'justify'\n * @attr {boolean} truncate - Truncate text with ellipsis when it overflows (single-line)\n * @attr {number} lines - Clamp to N lines with ellipsis (multi-line truncation)\n * @attr {boolean} italic - Italic text style\n * @attr {string} as - Semantic HTML element: 'span' | 'p' | 'div' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'label' | 'code'\n *\n * @slot - Text content\n *\n * @cssprop --text-size - Font size\n * @cssprop --text-weight - Font weight\n * @cssprop --text-color - Text color\n * @cssprop --text-line-height - Line height\n * @cssprop --text-letter-spacing - Letter spacing\n *\n * @example\n * ```html\n * <ore-text variant=\"heading\" size=\"2xl\" weight=\"bold\">Welcome</ore-text>\n * <ore-text as=\"h2\" variant=\"heading\" size=\"xl\">Section title</ore-text>\n * <ore-text color=\"primary\" weight=\"semibold\">Important notice</ore-text>\n * <ore-text variant=\"code\">npm install</ore-text>\n * <ore-text lines=\"2\">Long paragraph that clamps at two lines…</ore-text>\n * ```\n */\n\nexport const TEXT_TAG = 'ore-text' as const;\ndefine<OreTextProps>(TEXT_TAG, {\n props: {\n align: prop.string<'left' | 'center' | 'right' | 'justify'>(),\n as: prop.string<'span' | 'p' | 'div' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'label' | 'code'>(),\n color: prop.string<\n | 'primary'\n | 'secondary'\n | 'info'\n | 'success'\n | 'warning'\n | 'error'\n | 'heading'\n | 'body'\n | 'muted'\n | 'tertiary'\n | 'disabled'\n | 'contrast'\n >(),\n italic: prop.bool(),\n lines: prop.number(),\n size: prop.string<'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'>(),\n truncate: prop.bool(),\n variant: prop.string<'body' | 'heading' | 'label' | 'caption' | 'overline' | 'code'>(),\n weight: prop.string<'normal' | 'medium' | 'semibold' | 'bold'>(),\n },\n setup(props, { bind, el: _el }) {\n bind({\n attr: {\n 'aria-level': () => {\n const match = /^h([1-6])$/.exec((props.as.value as string) ?? '');\n\n return match ? match[1] : null;\n },\n role: () => (/^h([1-6])$/.test((props.as.value as string) ?? '') ? 'heading' : null),\n },\n style: {\n '--_lines': () => (props.lines.value != null ? String(props.lines.value) : null),\n },\n });\n\n return html`<slot></slot>`;\n },\n styles: [styles],\n});\n","@layer refine.base {\n :host {\n --_bg: var(--accordion-bg);\n --_border-color: var(--accordion-border-color);\n\n display: flex;\n flex-direction: column;\n gap: var(--size-2);\n width: 100%;\n background: var(--_bg);\n }\n\n ::slotted(ore-accordion-item) {\n width: 100%;\n }\n}\n\n@layer refine.variants {\n /* ========================================\n Visual Variants\n ======================================== */\n\n /* Bordered variant */\n :host([variant='bordered']) {\n gap: var(--size-2);\n }\n\n /* Text variant - borderless with dividers */\n :host([variant='text']) {\n gap: 0;\n }\n\n :host([variant='text']) ::slotted(ore-accordion-item:not(:last-child)) {\n border-bottom: 1px solid var(--accordion-divider-color, var(--color-contrast-200));\n }\n\n /* Contained variants - grouped appearance */\n :host([variant='solid']),\n :host([variant='flat']),\n :host([variant='glass']),\n :host([variant='frost']) {\n gap: 0;\n padding: var(--size-2);\n border-radius: var(--rounded-lg);\n }\n\n /* Solid variant (default) */\n :host([variant='solid']) {\n --_bg: var(--accordion-bg, var(--color-contrast-50));\n --_border-color: var(--accordion-border-color, var(--color-contrast-200));\n\n border: var(--border) solid var(--_border-color);\n box-shadow: var(--accordion-shadow, var(--shadow-xs));\n }\n\n /* Flat variant */\n :host([variant='flat']) {\n --_bg: var(--accordion-bg, var(--color-contrast-100));\n --_border-color: var(--accordion-border-color, var(--color-contrast-200));\n\n border: var(--border) solid var(--_border-color);\n box-shadow: var(--accordion-shadow, var(--inset-shadow-xs));\n }\n\n /* Glass & Frost - Shared styles */\n :host([variant='glass']),\n :host([variant='frost']) {\n box-shadow: var(--accordion-shadow, var(--shadow-md), var(--inset-shadow-xs));\n backdrop-filter: blur(var(--blur-lg)) saturate(180%) brightness(1.05);\n }\n\n /* Glass variant - translucent with blur */\n :host([variant='glass']) {\n --_bg: var(--accordion-bg, color-mix(in oklch, var(--color-secondary) 30%, var(--color-contrast) 10%));\n }\n\n /* Frost variant - canvas-based transparency */\n :host([variant='frost']) {\n --_bg: var(--accordion-bg, color-mix(in oklch, var(--color-canvas) 55%, transparent));\n }\n\n /* Nested item border radius for glass and frost variants */\n :host(:is([variant='glass'], [variant='frost'])) ::slotted(ore-accordion-item) {\n border-radius: 0;\n }\n\n :host(:is([variant='glass'], [variant='frost'])) ::slotted(ore-accordion-item:first-child) {\n border-radius: var(--rounded-lg) var(--rounded-lg) 0 0;\n }\n\n :host(:is([variant='glass'], [variant='frost'])) ::slotted(ore-accordion-item:last-child) {\n border-radius: 0 0 var(--rounded-lg) var(--rounded-lg);\n }\n\n :host(:is([variant='glass'], [variant='frost'])) ::slotted(ore-accordion-item:only-child) {\n border-radius: var(--rounded-lg);\n }\n}\n","import { createContext, define, html, prop } from '@vielzeug/ore';\nimport { computed, type Readable } from '@vielzeug/ripple';\n\nimport type { ComponentSize, SurfaceVariant } from '../../types';\n\nimport { createListControl } from '../../headless';\nimport styles from './accordion.css?inline';\n\n/** Context provided by ore-accordion to its ore-accordion-item children. */\nexport type AccordionContext = {\n selectionMode: Readable<'single' | 'multiple' | undefined>;\n size: Readable<ComponentSize | undefined>;\n variant: Readable<SurfaceVariant | undefined>;\n};\n/** Injection key for the accordion context. */\nexport const ACCORDION_CTX = createContext<AccordionContext>('AccordionContext');\n\n/** Accordion component properties */\n\nexport type OreAccordionEvents = {\n change: { expandedItem: HTMLElement };\n};\n\nexport type OreAccordionProps = {\n /** Selection mode (single = only one opens, multiple = multiple can be open) */\n selectionMode?: 'single' | 'multiple';\n /** Size for all items (propagated via context) */\n size?: ComponentSize;\n /** Visual variant for all items (propagated via context) */\n variant?: SurfaceVariant;\n};\n\n/**\n * A container for accordion items with single or multiple selection modes.\n *\n * @element ore-accordion\n * @element ore-accordion-item - Child element for each collapsible panel\n *\n * @attr {string} selection-mode - Selection mode: 'single' | 'multiple'\n * @attr {string} size - Size for all items: 'sm' | 'md' | 'lg' (propagated to children)\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'text' | 'glass' | 'frost' (propagated to children)\n *\n * @fires expand - Emitted when an item expands. detail: { expanded: boolean; item: HTMLElement }\n * @fires change - Emitted when selection changes (single mode). detail: { expandedItem: HTMLElement }\n *\n * @slot - `ore-accordion-item` elements\n *\n * @cssprop --accordion-bg - Container background color (solid/flat/glass/frost variants)\n * @cssprop --accordion-border-color - Container border color (solid/flat variants)\n * @cssprop --accordion-divider-color - Divider color between items (text variant)\n * @cssprop --accordion-shadow - Container box shadow\n * @example\n * ```html\n * <ore-accordion selection-mode=\"single\">\n * <ore-accordion-item>\n * <span slot=\"title\">What is Refine?</span>\n * <p>Refine is a headless web component library.</p>\n * </ore-accordion-item>\n * <ore-accordion-item>\n * <span slot=\"title\">How do I install it?</span>\n * <p>Run <code>npm install @vielzeug/refine</code>.</p>\n * </ore-accordion-item>\n * </ore-accordion>\n * <ore-accordion variant=\"bordered\" selection-mode=\"multiple\">\n * <ore-accordion-item expanded><span slot=\"title\">Open by default</span><p>Content</p></ore-accordion-item>\n * </ore-accordion>\n * ```\n */\n\nexport const ACCORDION_TAG = 'ore-accordion' as const;\ndefine<OreAccordionProps, OreAccordionEvents>(ACCORDION_TAG, {\n props: {\n selectionMode: prop.string<'single' | 'multiple'>(),\n size: prop.string<ComponentSize>(),\n variant: prop.string<SurfaceVariant>(),\n },\n\n setup(props, { bind, el, emit, provide }) {\n const handleSelectionMode = (expandedItem: HTMLElement) => {\n if (props.selectionMode.value !== 'single') return;\n\n el.querySelectorAll(':scope > ore-accordion-item[expanded]').forEach((item) => {\n if (item !== expandedItem && item.hasAttribute('expanded')) {\n item.removeAttribute('expanded');\n }\n });\n\n emit('change', { expandedItem });\n };\n\n const getAccordionItems = () => {\n return [...el.querySelectorAll<HTMLElement>(':scope > ore-accordion-item:not([disabled])')];\n };\n\n const getSummaryElements = () => {\n return getAccordionItems()\n .map((item) => item.shadowRoot?.querySelector<HTMLElement>('summary'))\n .filter(Boolean) as HTMLElement[];\n };\n\n const listControl = createListControl({\n getItems: () => getAccordionItems(),\n loop: true,\n onNavigate: (_action, index) => {\n const summaries = getSummaryElements();\n\n summaries[index]?.focus();\n },\n });\n\n provide(ACCORDION_CTX, {\n selectionMode: computed(() => props.selectionMode.value),\n size: props.size,\n variant: props.variant,\n });\n\n // Group-level event and keyboard handling for WAI-ARIA Accordion pattern\n\n bind({\n on: {\n expand: (event: Event) => {\n const eventTarget = event.composedPath().find((node): node is HTMLElement => node instanceof HTMLElement);\n const expandedItem = (event as CustomEvent<{ item?: HTMLElement }>).detail?.item ?? eventTarget;\n\n if (!expandedItem || expandedItem.localName !== 'ore-accordion-item') return;\n\n // Guard: only respond to accordion-items that belong to THIS accordion instance\n if (expandedItem.closest('ore-accordion') !== el) return;\n\n handleSelectionMode(expandedItem);\n },\n keydown: (evt: KeyboardEvent) => {\n const summaries = getSummaryElements();\n\n if (!summaries.length) return;\n\n const activeSummary = evt\n .composedPath()\n .find((node): node is HTMLElement => node instanceof HTMLElement && node.localName === 'summary');\n const focused = activeSummary ? summaries.indexOf(activeSummary) : -1;\n\n if (focused === -1) return; // focus is not on a summary — let native handling proceed\n\n listControl.set(focused);\n listControl.handleKeydown(evt);\n },\n },\n });\n\n return html`<slot></slot>`;\n },\n\n styles: [styles],\n});\n","@layer refine.base {\n :host {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n\n --tabs-transition: var(--transition-normal);\n --tabs-radius: var(--rounded-lg);\n }\n\n .tablist-wrapper {\n position: relative;\n flex-shrink: 0;\n }\n\n [role='tablist'] {\n position: relative;\n display: flex;\n gap: var(--tabs-tab-gap, var(--size-1));\n align-items: stretch;\n overflow-x: auto;\n scrollbar-width: none;\n }\n\n [role='tablist']::-webkit-scrollbar {\n display: none;\n }\n\n .indicator {\n position: absolute;\n bottom: 0;\n left: 0;\n height: 2px;\n pointer-events: none;\n background: var(--tabs-indicator-color, var(--_theme-base));\n border-radius: var(--rounded-full);\n transition: transform var(--tabs-transition);\n }\n\n .panels {\n display: flex;\n flex: 1;\n flex-direction: column;\n min-height: 0;\n }\n}\n\n@layer refine.orientation {\n /* ─── vertical orientation ─── */\n :host([orientation='vertical']) {\n flex-direction: row;\n align-items: flex-start;\n }\n\n :host([orientation='vertical']) .tablist-wrapper {\n display: flex;\n flex-shrink: 0;\n }\n\n :host([orientation='vertical']) [role='tablist'] {\n flex-direction: column;\n width: max-content;\n overflow-x: unset;\n overflow-y: auto;\n }\n\n :host([orientation='vertical']) .indicator {\n inset-inline-start: 0;\n top: 0;\n\n /* Reposition indicator to inline-start side for vertical */\n bottom: unset;\n width: 2px;\n height: unset;\n transition: transform var(--tabs-transition);\n }\n}\n\n@layer refine.variants {\n /* ─── solid (default) ─── */\n :host,\n :host([variant='solid']) {\n --tabs-tab-gap: var(--size-1);\n --_tablist-bg: var(--tabs-tablist-bg, var(--color-contrast-100));\n --_tablist-border-color: var(--tabs-tablist-border-color, var(--color-contrast-200));\n }\n\n :host [role='tablist'],\n :host([variant='solid']) [role='tablist'] {\n padding: var(--size-1);\n background: var(--_tablist-bg);\n border: var(--border) solid var(--_tablist-border-color);\n border-radius: var(--tabs-radius);\n }\n\n :host .indicator,\n :host([variant='solid']) .indicator {\n display: none;\n }\n\n /* ─── flat ─── */\n :host([variant='flat']) {\n --_tablist-border-color: var(--tabs-tablist-border-color, var(--color-contrast-200));\n\n overflow: hidden;\n background: var(--tabs-bg, var(--color-contrast-100));\n border: var(--border) solid var(--_tablist-border-color);\n border-radius: var(--tabs-radius);\n box-shadow: var(--inset-shadow-xs), var(--shadow-2xs);\n }\n\n :host([variant='flat']) [role='tablist'] {\n gap: var(--size-1);\n padding: var(--size-1);\n background: transparent;\n border: none;\n border-bottom: var(--border) solid var(--_tablist-border-color);\n border-radius: 0;\n }\n\n :host([variant='flat']) .indicator {\n display: none;\n }\n\n /* ─── bordered ─── */\n :host([variant='bordered']) {\n --_tablist-border-color: var(--tabs-tablist-border-color, var(--color-contrast-200));\n }\n\n :host([variant='bordered']) [role='tablist'] {\n gap: var(--size-1);\n padding: var(--size-1);\n background: transparent;\n border: var(--border) solid var(--_tablist-border-color);\n border-bottom: none;\n border-radius: var(--tabs-radius) var(--tabs-radius) 0 0;\n }\n\n :host([variant='bordered']) .indicator {\n display: none;\n }\n\n :host([variant='bordered']) .panels {\n border: var(--border) solid var(--_tablist-border-color);\n border-radius: 0 0 var(--tabs-radius) var(--tabs-radius);\n }\n\n :host([variant='bordered'][orientation='vertical']) [role='tablist'] {\n border-right: none;\n border-bottom: var(--border) solid var(--_tablist-border-color);\n border-radius: var(--tabs-radius) 0 0 var(--tabs-radius);\n }\n\n :host([variant='bordered'][orientation='vertical']) .panels {\n border-radius: 0 var(--tabs-radius) var(--tabs-radius) 0;\n }\n\n /* ─── ghost ─── */\n :host([variant='ghost']) [role='tablist'] {\n gap: var(--size-1);\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n }\n\n :host([variant='ghost']) .indicator {\n display: none;\n }\n\n /* ─── glass ─── */\n :host([variant='glass']) {\n --_tablist-bg: var(--tabs-tablist-bg, color-mix(in oklch, var(--color-secondary) 20%, transparent));\n --_tablist-border-color: var(\n --tabs-tablist-border-color,\n color-mix(in oklch, var(--color-secondary-contrast) 15%, transparent)\n );\n }\n\n :host([variant='glass']) [role='tablist'] {\n padding: var(--size-1);\n background: var(--_tablist-bg);\n border: var(--border) solid var(--_tablist-border-color);\n border-radius: var(--tabs-radius);\n box-shadow: var(--shadow-md), var(--inset-shadow-xs);\n backdrop-filter: blur(var(--blur-lg)) saturate(180%) brightness(1.05);\n }\n\n :host([variant='glass']) .indicator {\n display: none;\n }\n\n /* ─── frost ─── */\n :host([variant='frost']) {\n --_tablist-bg: var(--tabs-tablist-bg, color-mix(in oklch, var(--color-canvas) 55%, transparent));\n --_tablist-border-color: var(\n --tabs-tablist-border-color,\n color-mix(in oklch, var(--color-contrast-300) 50%, transparent)\n );\n }\n\n :host([variant='frost']) [role='tablist'] {\n padding: var(--size-1);\n background: var(--_tablist-bg);\n border: var(--border) solid var(--_tablist-border-color);\n border-radius: var(--tabs-radius);\n box-shadow: var(--shadow-md), var(--inset-shadow-xs);\n backdrop-filter: blur(var(--blur-lg)) saturate(180%);\n }\n\n :host([variant='frost']) .indicator {\n display: none;\n }\n}\n","import { createContext, define, html, prop, ref } from '@vielzeug/ore';\nimport { computed, type Readable, signal, watch } from '@vielzeug/ripple';\n\nimport type { ComponentSize, SurfaceVariant, ThemeColor } from '../../types';\n\nimport { createInteraction, createListControl } from '../../headless';\nimport { sizableBundle, themableBundle } from '../../shared';\nimport { colorThemeMixin } from '../../styles';\nimport styles from './tabs.css?inline';\n\n/** Context provided by ore-tabs to its ore-tab-item and ore-tab-panel children. */\nexport type TabsContext = {\n color: Readable<ThemeColor | undefined>;\n orientation: Readable<'horizontal' | 'vertical'>;\n size: Readable<ComponentSize | undefined>;\n value: Readable<string | undefined>;\n variant: Readable<SurfaceVariant | undefined>;\n};\n/** Injection key for the tabs context. */\nexport const TABS_CTX = createContext<TabsContext>('TabsContext');\n\nexport type OreTabsEvents = {\n change: { value: string };\n};\n\nexport type OreTabsProps = {\n /**\n * Keyboard activation mode.\n * - `'auto'` (default): Selecting a tab on arrow-key focus immediately activates it (ARIA recommendation for most cases).\n * - `'manual'`: Arrow keys only move focus; the user must press Enter or Space to activate the focused tab.\n */\n activation?: 'auto' | 'manual';\n /** Theme color */\n color?: ThemeColor;\n /** Accessible label for the tablist (passed as aria-label). Use when there is no visible heading labelling the tabs. */\n label?: string;\n /** Tab list orientation */\n orientation?: 'horizontal' | 'vertical';\n /** Component size */\n size?: ComponentSize;\n /** Currently selected tab value */\n value?: string;\n /** Visual style variant */\n variant?: SurfaceVariant;\n};\n\n/**\n * Tabs container. Manages tab selection and syncs state to child tab items and panels.\n *\n * @element ore-tabs\n * @element ore-tab-item - Child element for tab buttons (auto-discovered)\n * @element ore-tab-panel - Child element for tab content (auto-discovered)\n *\n * @attr {string} value - The value of the currently selected tab\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'ghost' | 'glass' | 'frost'\n * @attr {string} size - Size: 'sm' | 'md' | 'lg'\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n *\n * @fires change - Emitted when the active tab changes with detail: { value: string }\n *\n * @slot tabs - Place `ore-tab-item` elements here\n * @slot - Place `ore-tab-panel` elements here\n *\n * @cssprop --tabs-radius - Border radius of the tablist container and panels\n * @cssprop --tabs-transition - Transition duration/easing for the active indicator\n * @cssprop --tabs-indicator-color - Color of the sliding active indicator line\n * @cssprop --tabs-bg - Background of the host element (flat variant)\n * @cssprop --tabs-tablist-bg - Tablist container background (solid/glass/frost variants)\n * @cssprop --tabs-tablist-border-color - Tablist container border color\n * @part tablist - Container that holds the slotted tab items\n * @part indicator - Active tab indicator element\n * @part panels - Container that holds tab panel content\n * @example\n * ```html\n * <ore-tabs value=\"tab1\" variant=\"bordered\">\n * <ore-tab-item slot=\"tabs\" value=\"tab1\">Overview</ore-tab-item>\n * <ore-tab-item slot=\"tabs\" value=\"tab2\">Settings</ore-tab-item>\n * <ore-tab-panel value=\"tab1\"><p>Overview content</p></ore-tab-panel>\n * <ore-tab-panel value=\"tab2\"><p>Settings content</p></ore-tab-panel>\n * </ore-tabs>\n * ```\n */\nexport const TABS_TAG = 'ore-tabs' as const;\ndefine<OreTabsProps, OreTabsEvents>(TABS_TAG, {\n props: {\n ...themableBundle,\n ...sizableBundle,\n activation: prop.oneOf(['auto', 'manual'] as const, 'auto'),\n label: prop.string(),\n orientation: prop.oneOf(['horizontal', 'vertical'] as const, 'horizontal'),\n value: prop.string(),\n variant: prop.string<SurfaceVariant>(),\n },\n setup(props, { bind, el, emit, onMounted, provide }) {\n const shadowRoot = el.shadowRoot;\n const tablistRef = ref<HTMLElement>();\n const indicatorRef = ref<HTMLElement>();\n const selectedValue = signal<string | undefined>(props.value.value);\n const isManualActivation = () => props.activation.value === 'manual';\n const isVertical = () => props.orientation.value === 'vertical';\n\n bind({\n attr: {\n value: () => selectedValue.value ?? null,\n },\n });\n\n const getTabs = () => [...el.querySelectorAll<HTMLElement>(':scope > ore-tab-item[slot=\"tabs\"]')];\n const getEnabledTabs = () => getTabs().filter((t) => !t.hasAttribute('disabled'));\n const focusTab = (tab: HTMLElement | undefined) => {\n if (!tab) return;\n\n const focusable = tab.shadowRoot?.querySelector<HTMLElement>('[role=\"tab\"]') ?? tab;\n\n focusable.focus();\n };\n\n // ────────────────────────────────────────────────────────────────\n // Selection State Management\n // ────────────────────────────────────────────────────────────────\n\n const setSelection = (value: string | undefined, shouldEmit = false) => {\n selectedValue.value = value;\n\n if (shouldEmit && value) emit('change', { value });\n };\n\n const ensureSelection = () => {\n const tabs = getTabs();\n\n if (tabs.length === 0) return; // No tabs yet, keep current selection\n\n const current = selectedValue.value;\n const hasCurrent = current\n ? tabs.some((tab) => tab.getAttribute('value') === current && !tab.hasAttribute('disabled'))\n : false;\n\n if (hasCurrent) return;\n\n const firstEnabled = tabs.find((tab) => !tab.hasAttribute('disabled'))?.getAttribute('value') ?? undefined;\n\n setSelection(firstEnabled, false);\n };\n\n watch(props.value, (value) => {\n selectedValue.value = value;\n ensureSelection();\n });\n\n // ────────────────────────────────────────────────────────────────\n // List Control for Keyboard Navigation\n // ────────────────────────────────────────────────────────────────\n\n const listControl = createListControl({\n getItems: () => getEnabledTabs(),\n loop: true,\n onNavigate: (_action, index) => {\n const tabs = getEnabledTabs();\n const nextTab = tabs[index];\n\n focusTab(nextTab);\n\n if (!isManualActivation()) {\n const value = nextTab?.getAttribute('value');\n\n if (value) setSelection(value, true);\n }\n },\n orientation: () => (isVertical() ? 'vertical' : 'both'),\n });\n\n // ────────────────────────────────────────────────────────────────\n // Context & Indicator Management\n // ────────────────────────────────────────────────────────────────\n\n provide(TABS_CTX, {\n color: props.color,\n orientation: computed(() => props.orientation.value ?? 'horizontal'),\n size: props.size,\n value: selectedValue,\n variant: props.variant,\n });\n\n const moveIndicator = (activeTab: HTMLElement | undefined) => {\n const indicator = indicatorRef.value;\n const tablist = tablistRef.value;\n\n if (!indicator || !tablist || !activeTab) return;\n\n const tabRect = activeTab.getBoundingClientRect();\n const listRect = tablist.getBoundingClientRect();\n\n if (isVertical()) {\n const y = tabRect.top - listRect.top + tablist.scrollTop;\n\n indicator.style.transition = 'none';\n indicator.style.height = `${tabRect.height}px`;\n indicator.style.width = '';\n indicator.style.left = '0';\n indicator.style.top = '0';\n void indicator.offsetWidth;\n indicator.style.transition = '';\n indicator.style.transform = `translateY(${y}px)`;\n } else {\n const x = tabRect.left - listRect.left + tablist.scrollLeft;\n\n indicator.style.transition = 'none';\n indicator.style.width = `${tabRect.width}px`;\n indicator.style.height = '';\n indicator.style.top = '';\n indicator.style.left = '0';\n void indicator.offsetWidth;\n indicator.style.transition = '';\n indicator.style.transform = `translateX(${x}px)`;\n }\n };\n\n const updateIndicator = () => {\n const value = selectedValue.value;\n\n if (!value) return;\n\n const activeTab = getTabs().find((t) => t.getAttribute('value') === value);\n\n moveIndicator(activeTab);\n };\n\n watch(selectedValue, () => {\n requestAnimationFrame(updateIndicator);\n });\n\n // ────────────────────────────────────────────────────────────────\n // Event Handlers\n // ────────────────────────────────────────────────────────────────\n\n const handleTabClick = (e: Event) => {\n const tab = e\n .composedPath()\n .find((node): node is HTMLElement => node instanceof HTMLElement && node.localName === 'ore-tab-item');\n\n if (!tab || tab.hasAttribute('disabled')) return;\n\n // Guard: only respond to tab-items that belong to THIS tabs instance\n if (tab.closest('ore-tabs') !== el) return;\n\n const value = tab.getAttribute('value');\n\n if (!value || value === selectedValue.value) return;\n\n setSelection(value, true);\n };\n\n const activateFocusedTab = (): void => {\n const tabs = getEnabledTabs();\n const focusedTab = tabs.find(\n (tab) => tab === document.activeElement || tab.shadowRoot?.activeElement === document.activeElement,\n );\n const focusedValue = focusedTab?.getAttribute('value');\n\n if (focusedValue && focusedValue !== selectedValue.value) setSelection(focusedValue, true);\n };\n\n const manualActivationPress = createInteraction({\n disabled: computed(() => !isManualActivation()),\n onPress: activateFocusedTab,\n });\n\n const handleKeydown = (e: KeyboardEvent) => {\n const tabs = getEnabledTabs();\n\n if (tabs.length === 0) return;\n\n const path = e.composedPath();\n const activeTabFromEvent = path.find(\n (node): node is HTMLElement => node instanceof HTMLElement && node.localName === 'ore-tab-item',\n );\n\n const tabFromEvent = activeTabFromEvent ?? tabs.find((t) => t.getAttribute('value') === selectedValue.value);\n const focused = tabFromEvent ? tabs.indexOf(tabFromEvent) : -1;\n\n if (focused >= 0) listControl.set(focused);\n\n if (listControl.handleKeydown(e)) return;\n\n manualActivationPress.handleKeydown(e);\n };\n\n bind({\n on: {\n click: handleTabClick,\n keydown: handleKeydown,\n },\n });\n\n // ────────────────────────────────────────────────────────────────\n // Lifecycle\n // ────────────────────────────────────────────────────────────────\n\n onMounted(() => {\n const syncSelection = () => {\n ensureSelection();\n updateIndicator();\n };\n\n const tabsSlot = shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"tabs\"]');\n\n if (tabsSlot) {\n tabsSlot.addEventListener('slotchange', syncSelection);\n }\n\n syncSelection();\n requestAnimationFrame(syncSelection);\n\n return () => {\n if (tabsSlot) {\n tabsSlot.removeEventListener('slotchange', syncSelection);\n }\n };\n });\n\n return html`\n <div class=\"tablist-wrapper\">\n <div\n role=\"tablist\"\n ref=\"${tablistRef}\"\n part=\"tablist\"\n aria-orientation=\"${props.orientation}\"\n aria-label=\"${props.label}\">\n <slot name=\"tabs\"></slot>\n </div>\n <div class=\"indicator\" ref=\"${indicatorRef}\" part=\"indicator\"></div>\n </div>\n <div class=\"panels\" part=\"panels\">\n <slot></slot>\n </div>\n `;\n },\n styles: [colorThemeMixin, styles],\n});\n","@layer refine.base {\n /* ========================================\n Base Styles & Defaults\n ======================================== */\n\n :host {\n display: block;\n color: var(--accordion-item-body-color, var(--text-color-body));\n\n --accordion-details-radius: var(--rounded-lg);\n --accordion-item-transition: var(--transition-normal);\n --accordion-item-expand-easing: var(--ease-spring);\n }\n\n details {\n width: 100%;\n overflow: hidden;\n border-radius: var(--accordion-item-radius);\n }\n\n summary {\n position: relative;\n display: flex;\n gap: var(--size-4);\n align-items: center;\n min-height: var(--_touch-target);\n padding: var(--accordion-item-details-padding, var(--size-3) var(--size-4));\n font-size: var(--accordion-item-title);\n cursor: pointer;\n user-select: none;\n outline: none;\n list-style: none;\n background: var(--accordion-item-bg);\n border: var(--border) solid var(--accordion-item-border-color);\n border-radius: var(--accordion-details-radius);\n transition:\n background var(--accordion-item-transition),\n border-color var(--accordion-item-transition),\n color var(--accordion-item-transition);\n }\n\n summary::-webkit-details-marker {\n display: none;\n }\n\n summary:focus {\n outline: none;\n }\n\n summary:focus-visible {\n outline: var(--border-2) solid currentcolor;\n outline-offset: var(--border-2);\n box-shadow: 0 0 0 3px color-mix(in oklch, currentcolor 20%, transparent);\n }\n\n .header-content {\n display: flex;\n flex: 1;\n flex-direction: column;\n min-width: 0;\n }\n\n .subtitle {\n font-size: var(--accordion-item-subtitle-size);\n line-height: var(--leading-normal);\n color: var(--accordion-item-subtitle-color, var(--text-color-secondary));\n }\n\n .title {\n overflow: hidden;\n text-overflow: ellipsis;\n font-weight: var(--font-medium);\n color: var(--accordion-item-title-color, var(--text-color-heading));\n white-space: nowrap;\n }\n\n .content-wrapper {\n display: grid;\n grid-template-rows: 0fr;\n font-size: var(--accordion-item-body);\n background: var(--accordion-item-bg);\n border-inline: 1px solid var(--accordion-item-border-color);\n border-bottom: 1px solid var(--accordion-item-border-color);\n border-radius: var(--accordion-summary-radius);\n transition: grid-template-rows 200ms var(--accordion-item-expand-easing, var(--ease-spring));\n }\n\n details[open] .content-wrapper {\n grid-template-rows: 1fr;\n }\n\n .content-inner {\n padding: var(--accordion-item-summary-padding, var(--size-2) var(--size-4));\n overflow: hidden;\n opacity: 1;\n transform: translateY(0);\n transition:\n opacity 200ms 60ms var(--ease-spring),\n transform 200ms 60ms var(--ease-spring);\n }\n\n /* Opening: set from-state with no transition — transition fires on base rule when class is removed */\n details.opening .content-inner {\n opacity: 0;\n transform: translateY(-6px);\n transition: none;\n }\n\n /* Closing: content fades out immediately, row collapses after */\n details.closing .content-inner {\n opacity: 0;\n transform: translateY(-4px);\n transition:\n opacity 150ms var(--ease-spring),\n transform 150ms var(--ease-spring);\n }\n\n /* Keep row expanded while closing animation plays */\n details.closing .content-wrapper {\n grid-template-rows: 1fr;\n transition: grid-template-rows 200ms 120ms var(--accordion-item-expand-easing, var(--ease-spring));\n }\n}\n\n@layer refine.variants {\n /* ========================================\n Visual Variants\n ======================================== */\n\n :host,\n :host([variant='solid']) {\n --accordion-item-bg: var(--color-contrast-50);\n --accordion-item-border-color: transparent;\n --accordion-item-hover-bg: var(--color-contrast-200);\n }\n\n :host([variant='flat']) {\n --accordion-item-bg: var(--color-contrast-100);\n --accordion-item-hover-bg: var(--color-contrast-200);\n }\n\n :host([variant='bordered']) {\n --accordion-item-bg: var(--color-contrast-100);\n --accordion-item-border-color: var(--color-divider);\n --accordion-item-hover-bg: var(--color-contrast-200);\n\n box-shadow: var(--inset-shadow-xs), var(--shadow-2xs);\n }\n\n :host([variant='outline']) {\n --accordion-item-bg: transparent;\n --accordion-item-border-color: var(--color-divider);\n --accordion-item-hover-bg: var(--color-contrast-300);\n }\n\n :host([variant='ghost']) {\n --accordion-item-bg: transparent;\n --accordion-item-border-color: transparent;\n --accordion-item-hover-bg: var(--color-contrast-200);\n }\n\n :host([variant='text']) {\n --accordion-item-bg: transparent;\n --accordion-item-border-color: transparent;\n --accordion-item-hover-bg: transparent;\n }\n\n /* ── Shared hover state reads per-variant --accordion-item-hover-bg ── */\n :host summary:hover {\n background: var(--accordion-item-hover-bg);\n }\n\n /* Glass & Frost - Shared Styles */\n :host([variant='glass']) details,\n :host([variant='frost']) details {\n border-radius: inherit;\n }\n\n :host([variant='glass']) summary,\n :host([variant='frost']) summary {\n border-radius: inherit;\n backdrop-filter: blur(var(--blur-lg)) saturate(180%);\n }\n\n :host([variant='glass']) .content-wrapper,\n :host([variant='frost']) .content-wrapper {\n border-radius: 0;\n backdrop-filter: blur(var(--blur-lg)) saturate(180%);\n }\n\n /* Glass */\n :host([variant='glass']) {\n --accordion-item-bg: color-mix(in oklch, var(--color-secondary) 30%, var(--color-contrast) 10%);\n --accordion-item-border-color: transparent;\n --accordion-item-hover-bg: color-mix(in oklch, var(--color-secondary) 20%, transparent);\n --accordion-item-title-color: color-mix(in oklch, var(--color-secondary-contrast) 100%, transparent);\n --accordion-item-subtitle-color: color-mix(in oklch, var(--color-secondary-contrast) 60%, transparent);\n --accordion-item-body-color: color-mix(in oklch, var(--color-secondary-contrast) 80%, transparent);\n }\n\n :host([variant='glass']) summary {\n text-shadow: var(--text-shadow-xs);\n }\n\n :host([variant='glass']) .content-wrapper {\n filter: brightness(1.05);\n }\n\n /* Frost */\n :host([variant='frost']) {\n --accordion-item-bg: color-mix(in oklch, var(--color-canvas) 55%, transparent);\n --accordion-item-border-color: transparent;\n --accordion-item-hover-bg: color-mix(in oklch, var(--color-canvas) 20%, transparent);\n }\n\n :host([variant='frost']) summary {\n text-shadow: var(--text-shadow-2xs);\n }\n\n /* ========================================\n Size Variants\n ======================================== */\n\n :host([size='sm']) {\n --accordion-item-details-padding: var(--size-2) var(--size-4);\n --accordion-item-summary-padding: var(--size-1) var(--size-5);\n --accordion-item-title: var(--text-sm);\n --accordion-item-subtitle-size: var(--text-xs);\n --accordion-item-body: var(--text-xs);\n }\n\n :host(:not([size])),\n :host([size='md']) {\n --accordion-item-details-padding: var(--size-3) var(--size-4);\n --accordion-item-summary-padding: var(--size-1) var(--size-5);\n --accordion-item-title: var(--text-base);\n --accordion-item-subtitle-size: var(--text-sm);\n --accordion-item-body: var(--text-sm);\n }\n\n :host([size='lg']) {\n --accordion-item-details-padding: var(--size-4) var(--size-4);\n --accordion-item-summary-padding: var(--size-1) var(--size-5);\n --accordion-item-title: var(--text-lg);\n --accordion-item-subtitle-size: var(--text-base);\n --accordion-item-body: var(--text-base);\n }\n\n /* ─── coarse pointer: promote one size tier for proportional scaling ─── */\n @media (pointer: coarse) {\n :host,\n :host([size='md']) {\n --accordion-item-details-padding: var(--size-4) var(--size-5);\n --accordion-item-title: var(--text-lg);\n --accordion-item-subtitle-size: var(--text-base);\n --accordion-item-body: var(--text-base);\n }\n\n :host([size='sm']) {\n --accordion-item-details-padding: var(--size-3) var(--size-4);\n --accordion-item-title: var(--text-base);\n --accordion-item-subtitle-size: var(--text-sm);\n --accordion-item-body: var(--text-sm);\n }\n }\n\n /* ========================================\n States\n ======================================== */\n\n :host([disabled]) {\n pointer-events: none;\n opacity: 0.6;\n }\n\n /* ========================================\n Chevron Animation\n ======================================== */\n\n .chevron {\n width: var(--_size, var(--size-5));\n height: var(--_size, var(--size-5));\n\n --ore-icon-size: var(--_size, var(--size-5));\n\n margin-inline-start: auto;\n transform: rotate(-90deg);\n transition: transform 200ms var(--ease-spring);\n }\n\n details[open] .chevron {\n transform: rotate(0deg);\n }\n\n /* RTL Support - use .rtl class added by JavaScript */\n details.rtl .chevron {\n transform: rotate(90deg);\n }\n\n details.rtl[open] .chevron {\n transform: rotate(0deg);\n }\n\n /* :dir(rtl) is inheritance-driven and crosses the shadow boundary; the ancestor-attribute\n selectors (html[dir='rtl']/[dir='rtl']) cannot match anything inside this shadow root and\n were removed. */\n :dir(rtl) .chevron {\n transform: rotate(90deg);\n }\n\n :dir(rtl) details[open] .chevron {\n transform: rotate(0deg);\n }\n\n /* Expanded state - adjust border radius */\n :host([expanded]) {\n --accordion-details-radius: var(--rounded-lg) var(--rounded-lg) 0 0;\n --accordion-summary-radius: 0 0 var(--rounded-lg) var(--rounded-lg);\n }\n\n @media (forced-colors: active) {\n /* Default variant uses a transparent border — ensure a visible border\n renders in HCM so the summary is distinguishable from the body */\n summary {\n border-color: ButtonText;\n }\n }\n}\n","import { define, html, inject, prop, ref } from '@vielzeug/ore';\n\nimport type { ComponentSize, SurfaceVariant } from '../../types';\n\nimport '../../content/icon/icon';\nimport { elementDirection } from '../../headless/direction';\nimport { disablableBundle } from '../../shared';\nimport { coarsePointerMixin } from '../../styles';\nimport { ACCORDION_CTX } from '../accordion/accordion';\nimport styles from './accordion-item.css?inline';\n\n/** Accordion item component properties */\n\nexport type OreAccordionItemEvents = {\n collapse: { expanded: boolean; item: HTMLElement };\n expand: { expanded: boolean; item: HTMLElement };\n};\n\nexport type OreAccordionItemProps = {\n /** Disable accordion item interaction */\n disabled?: boolean;\n /** Whether the item is expanded/open */\n expanded?: boolean;\n /** Item size */\n size?: ComponentSize;\n /** Visual style variant */\n variant?: SurfaceVariant;\n};\n\n/**\n * An individual accordion item with expand/collapse functionality using native details/summary.\n *\n * @element ore-accordion-item\n *\n * @attr {boolean} expanded - Whether the item is expanded/open\n * @attr {boolean} disabled - Disable accordion item interaction\n * @attr {string} size - Item size: 'sm' | 'md' | 'lg'\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'outline' | 'ghost' | 'text' | 'glass' | 'frost'\n *\n * @fires expand - Emitted when item expands. detail: { expanded: boolean; item: HTMLElement }\n * @fires collapse - Emitted when item collapses. detail: { expanded: boolean; item: HTMLElement }\n *\n * @slot prefix - Content before the title (e.g., icons)\n * @slot title - Main accordion item title\n * @slot subtitle - Optional subtitle text\n * @slot suffix - Content after the title (e.g., badges)\n * @slot - Accordion item content (shown when expanded)\n *\n * @cssprop --accordion-item-bg - Background color\n * @cssprop --accordion-item-hover-bg - Background color on hover\n * @cssprop --accordion-item-border-color - Border color\n * @cssprop --accordion-item-title-color - Title text color\n * @cssprop --accordion-item-subtitle-color - Subtitle text color\n * @cssprop --accordion-item-body-color - Body text color\n * @cssprop --accordion-item-radius - Border radius\n * @cssprop --accordion-item-transition - Transition duration\n * @cssprop --accordion-item-title - Title font size\n * @cssprop --accordion-item-subtitle-size - Subtitle font size\n * @cssprop --accordion-item-body - Body font size\n * @cssprop --accordion-item-details-padding - Summary/header padding\n * @cssprop --accordion-item-summary-padding - Content padding\n *\n * @part item - Item root element.\n * @part summary - Summary trigger row.\n * @part header - Header container.\n * @part title - Title text element.\n * @part subtitle - Subtitle text element.\n * @part content - Content container.\n * @example\n * ```html\n * <ore-accordion-item><span slot=\"title\">Click to expand</span><p>Content</p></ore-accordion-item>\n * <ore-accordion-item expanded variant=\"bordered\"><span slot=\"title\">Title</span><p>Content</p></ore-accordion-item>\n * ```\n */\n\nexport const ACCORDION_ITEM_TAG = 'ore-accordion-item' as const;\ndefine<OreAccordionItemProps, OreAccordionItemEvents>(ACCORDION_ITEM_TAG, {\n props: {\n ...disablableBundle,\n expanded: prop.bool(false),\n size: prop.string<ComponentSize>(),\n variant: prop.string<SurfaceVariant>(),\n },\n\n setup(props, { el, emit, onMounted, watch }) {\n // Inherit size/variant from a parent ore-accordion when present.\n const accordionCtx = inject(ACCORDION_CTX);\n\n if (accordionCtx) {\n watch(() => {\n const size = accordionCtx.size.value;\n const variant = accordionCtx.variant.value;\n\n if (size !== undefined) el.setAttribute('size', size);\n\n if (variant !== undefined) el.setAttribute('variant', variant);\n });\n }\n\n const titleId = 'accordion-item-title';\n const detailsRef = ref<HTMLDetailsElement>();\n const summaryRef = ref<HTMLElement>();\n let isAnimating = false;\n\n const openItem = () => {\n const details = detailsRef.value;\n\n if (!details || details.open) return;\n\n details.classList.add('opening');\n details.open = true;\n\n el.toggleAttribute('expanded', true);\n emit('expand', { expanded: true, item: el });\n\n requestAnimationFrame(() => {\n const inner = details.querySelector<HTMLElement>('.content-inner');\n\n if (!inner) {\n details.classList.remove('opening');\n isAnimating = false;\n\n return;\n }\n\n const onDone = () => {\n details.classList.remove('opening');\n isAnimating = false;\n };\n const transitions = inner.getAnimations?.().filter((a) => a instanceof CSSTransition) ?? [];\n\n if (transitions.length > 0) {\n Promise.allSettled(transitions.map((a) => a.finished)).then(onDone);\n } else {\n onDone();\n }\n });\n };\n\n const closeItem = () => {\n const details = detailsRef.value;\n\n if (!details || !details.open || isAnimating) return;\n\n isAnimating = true;\n\n details.classList.add('closing');\n\n const inner = details.querySelector<HTMLElement>('.content-inner');\n const onDone = () => {\n details.classList.remove('closing');\n details.open = false;\n el.toggleAttribute('expanded', false);\n emit('collapse', { expanded: false, item: el });\n isAnimating = false;\n };\n\n if (inner) {\n const transitions = inner.getAnimations?.().filter((a) => a instanceof CSSTransition) ?? [];\n\n if (transitions.length > 0) {\n Promise.allSettled(transitions.map((a) => a.finished)).then(onDone);\n } else {\n onDone();\n }\n } else {\n onDone();\n }\n };\n\n let touchHandled = false;\n let touchStartY = 0;\n\n const toggleDetails = () => {\n if (props.disabled.value) return;\n\n const details = detailsRef.value;\n\n if (!details) return;\n\n if (details.open) {\n closeItem();\n } else {\n openItem();\n }\n };\n\n const handleSummaryTouchStart = (e: TouchEvent) => {\n touchStartY = e.touches[0]?.clientY ?? 0;\n };\n\n const handleSummaryTouchEnd = (e: TouchEvent) => {\n const dy = Math.abs((e.changedTouches[0]?.clientY ?? 0) - touchStartY);\n\n if (dy > 10) return;\n\n e.preventDefault();\n touchHandled = true;\n toggleDetails();\n };\n\n const handleSummaryClick = (e: Event) => {\n if (touchHandled) {\n touchHandled = false;\n e.preventDefault();\n\n return;\n }\n\n e.preventDefault();\n toggleDetails();\n };\n\n const handleToggle = () => {\n // Only fires for programmatic open/close (e.g. from accordion parent)\n const isOpen = detailsRef.value?.open ?? false;\n const wasExpanded = Boolean(props.expanded.value);\n\n if (isOpen && !wasExpanded) {\n el.toggleAttribute('expanded', true);\n emit('expand', { expanded: true, item: el });\n } else if (!isOpen && wasExpanded) {\n el.toggleAttribute('expanded', false);\n emit('collapse', { expanded: false, item: el });\n }\n };\n\n onMounted(() => {\n const details = detailsRef.value;\n const summary = summaryRef.value;\n\n if (!details || !summary) return;\n\n // Detect RTL so plain CSS classes can target it (see `elementDirection` for the\n // ancestor-dir / computed-style resolution rule).\n const checkRTL = () => {\n details.classList.toggle('rtl', elementDirection(el) === 'rtl');\n };\n\n // Check initially\n checkRTL();\n\n // Re-check when `dir` changes on this element's own ancestor chain (not the whole\n // document — `elementDirection` only ever looks at `el`'s ancestors, so that's all we\n // need to watch).\n const observer = new MutationObserver((mutations) => {\n const dirChanged = mutations.some((m) => m.attributeName === 'dir');\n\n if (dirChanged) {\n checkRTL();\n }\n });\n\n for (let ancestor: Element | null = el; ancestor; ancestor = ancestor.parentElement) {\n observer.observe(ancestor, { attributeFilter: ['dir'], attributes: true });\n }\n\n details.addEventListener('toggle', handleToggle);\n summary.addEventListener('touchstart', handleSummaryTouchStart, { passive: true });\n summary.addEventListener('touchend', handleSummaryTouchEnd, { passive: false });\n summary.addEventListener('click', handleSummaryClick);\n\n return () => {\n observer.disconnect();\n details.removeEventListener('toggle', handleToggle);\n summary.removeEventListener('touchstart', handleSummaryTouchStart);\n summary.removeEventListener('touchend', handleSummaryTouchEnd);\n summary.removeEventListener('click', handleSummaryClick);\n };\n });\n\n return html` <details part=\"item\" ?open=\"${props.expanded}\" ref=\"${detailsRef}\">\n <summary\n part=\"summary\"\n :aria-expanded=\"${() => String(props.expanded.value)}\"\n :aria-disabled=\"${() => (props.disabled.value ? 'true' : 'false')}\"\n :tabindex=\"${() => (props.disabled.value ? '-1' : null)}\"\n ref=\"${summaryRef}\">\n <slot name=\"prefix\"></slot>\n <div class=\"header-content\" part=\"header\">\n <span class=\"title\" part=\"title\" id=\"${titleId}\">\n <slot name=\"title\"></slot>\n </span>\n <span class=\"subtitle\" part=\"subtitle\">\n <slot name=\"subtitle\"></slot>\n </span>\n </div>\n <slot name=\"suffix\"></slot>\n <ore-icon class=\"chevron\" name=\"chevron-down\" size=\"20\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </summary>\n <div class=\"content-wrapper\" part=\"content\" role=\"region\" aria-labelledby=\"${titleId}\">\n <div class=\"content-inner\">\n <slot></slot>\n </div>\n </div>\n </details>`;\n },\n\n styles: [coarsePointerMixin, styles],\n});\n","@layer refine.base {\n :host {\n display: inline-flex;\n outline: none;\n\n --tab-item-transition: var(--transition-normal);\n --tab-item-radius: var(--rounded-lg);\n }\n\n button {\n position: relative;\n display: inline-flex;\n gap: var(--size-2);\n align-items: center;\n justify-content: center;\n width: 100%;\n min-height: var(--_touch-target);\n padding: var(--tab-item-padding, var(--size-1-5) var(--size-4));\n font-family: inherit;\n font-size: var(--tab-item-font-size, var(--text-sm));\n font-weight: var(--font-medium);\n color: var(--tab-item-color, var(--text-color-secondary));\n white-space: nowrap;\n cursor: pointer;\n user-select: none;\n background: transparent;\n border: none;\n border-radius: var(--tab-item-radius);\n transition:\n background var(--tab-item-transition),\n color var(--tab-item-transition),\n box-shadow var(--tab-item-transition);\n }\n\n button:focus {\n outline: none;\n }\n\n :host(:focus-visible) button,\n button:focus-visible {\n outline: var(--border-2) solid var(--_theme-focus);\n outline-offset: 2px;\n box-shadow: 0 0 0 3px var(--_theme-shadow);\n }\n}\n\n@layer refine.variants {\n /* ─── solid / default ─── */\n :host,\n :host([variant='solid']) {\n --_hover-bg: var(--tab-item-hover-bg, var(--color-contrast-200));\n --_active-bg: var(--tab-item-active-bg, var(--color-contrast-0, var(--color-canvas)));\n --_active-color: var(--tab-item-active-color, var(--text-color-heading));\n --_active-shadow: var(--tab-item-active-shadow, var(--shadow-xs), var(--inset-shadow-xs));\n }\n\n /* ─── flat ─── */\n :host([variant='flat']) {\n --_hover-bg: var(--tab-item-hover-bg, var(--color-contrast-200));\n --_active-bg: var(--tab-item-active-bg, var(--color-contrast-0, var(--color-canvas)));\n --_active-color: var(--tab-item-active-color, var(--text-color-heading));\n --_active-shadow: var(--tab-item-active-shadow, var(--shadow-xs), var(--inset-shadow-xs));\n }\n\n /* ─── bordered ─── */\n :host([variant='bordered']) {\n --_hover-bg: var(--tab-item-hover-bg, var(--color-contrast-200));\n --_active-bg: var(--tab-item-active-bg, var(--color-contrast-0, var(--color-canvas)));\n --_active-color: var(--tab-item-active-color, var(--text-color-heading));\n --_active-shadow: var(--tab-item-active-shadow, var(--shadow-xs));\n }\n\n /* ─── ghost ─── */\n :host([variant='ghost']) {\n --_hover-bg: var(--tab-item-hover-bg, var(--color-contrast-100));\n --_active-bg: var(--tab-item-active-bg, var(--_theme-base));\n --_active-color: var(--tab-item-active-color, var(--_theme-contrast));\n }\n\n /* ─── glass ─── */\n :host([variant='glass']) {\n --_color: var(--tab-item-color, color-mix(in oklch, var(--color-secondary-contrast) 70%, transparent));\n --_hover-bg: var(--tab-item-hover-bg, color-mix(in oklch, var(--color-secondary-contrast) 10%, transparent));\n --_active-bg: var(--tab-item-active-bg, color-mix(in oklch, var(--color-secondary-contrast) 15%, transparent));\n --_active-color: var(--tab-item-active-color, var(--color-secondary-contrast));\n --_active-shadow: var(--tab-item-active-shadow, var(--shadow-xs), var(--inset-shadow-xs));\n }\n\n :host([variant='glass']) button {\n color: var(--_color);\n text-shadow: var(--text-shadow-2xs);\n }\n\n :host([variant='glass']) button:hover {\n color: var(--tab-item-active-color, var(--color-secondary-contrast));\n }\n\n /* ─── frost ─── */\n :host([variant='frost']) {\n --_hover-bg: var(--tab-item-hover-bg, color-mix(in oklch, var(--color-contrast) 10%, transparent));\n --_active-bg: var(--tab-item-active-bg, color-mix(in oklch, var(--color-canvas) 60%, transparent));\n --_active-color: var(--tab-item-active-color, var(--text-color-heading));\n --_active-shadow: var(--tab-item-active-shadow, var(--shadow-xs), var(--inset-shadow-xs));\n }\n\n :host([variant='frost']) button {\n color: var(--text-color-secondary);\n }\n\n /* ─── Shared interactive states (read per-variant --_* tokens) ─── */\n\n :host button:hover {\n color: var(--tab-item-active-color, var(--text-color-heading));\n background: var(--_hover-bg);\n }\n\n :host([active]) button {\n color: var(--_active-color);\n background: var(--_active-bg);\n box-shadow: var(--_active-shadow);\n }\n\n /* ─── sizes ─── */\n :host([size='sm']) {\n --tab-item-font-size: var(--text-xs);\n --tab-item-padding: var(--size-1) var(--size-3);\n }\n\n :host(:not([size])),\n :host([size='md']) {\n --tab-item-font-size: var(--text-sm);\n --tab-item-padding: var(--size-1-5) var(--size-4);\n }\n\n :host([size='lg']) {\n --tab-item-font-size: var(--text-base);\n --tab-item-padding: var(--size-2) var(--size-5);\n }\n\n /* ─── coarse pointer: promote one size tier for proportional scaling ─── */\n @media (pointer: coarse) {\n :host,\n :host([size='md']) {\n --tab-item-font-size: var(--text-base);\n --tab-item-padding: var(--size-2) var(--size-5);\n }\n\n :host([size='sm']) {\n --tab-item-font-size: var(--text-sm);\n --tab-item-padding: var(--size-1-5) var(--size-4);\n }\n }\n\n /* ─── disabled ─── */\n :host([disabled]) {\n pointer-events: none;\n opacity: 0.5;\n }\n\n @media (forced-colors: active) {\n /* Ensure focus ring is visible regardless of variant theme color */\n button:focus-visible {\n outline: 2px solid Highlight;\n box-shadow: none;\n }\n\n /* Active tab: box-shadow raised indicator is stripped; use outline inste\n ad so the selected tab remains distinguishable */\n :host([active]) button {\n outline: 2px solid Highlight;\n outline-offset: -2px;\n }\n }\n}\n","import { define, html, inject, prop } from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\n\nimport type { ComponentSize, SurfaceVariant, ThemeColor } from '../../types';\n\nimport { disablableBundle } from '../../shared';\nimport { coarsePointerMixin, colorThemeMixin, forcedColorsFocusMixin } from '../../styles';\nimport { TABS_CTX } from '../tabs/tabs';\nimport styles from './tab-item.css?inline';\n\nexport type OreTabItemProps = {\n /** Whether this tab is currently selected (set by ore-tabs) */\n active?: boolean;\n /** Theme color (inherited from ore-tabs) */\n color?: ThemeColor;\n /** Disable this tab */\n disabled?: boolean;\n /** Size (inherited from ore-tabs) */\n size?: ComponentSize;\n /** Unique value identifier — must match a ore-tab-panel value */\n value: string;\n /** Visual variant (inherited from ore-tabs) */\n variant?: SurfaceVariant;\n};\n\n/**\n * Individual tab trigger. Must be placed in the `tabs` slot of `ore-tabs`.\n *\n * @element ore-tab-item\n *\n * @attr {string} value - Unique identifier, matches the corresponding ore-tab-panel value\n * @attr {boolean} active - Set by the parent ore-tabs when this tab is selected\n * @attr {boolean} disabled - Prevents selection\n * @attr {string} size - 'sm' | 'md' | 'lg'\n * @attr {string} variant - Inherited from ore-tabs: 'solid' | 'flat' | 'bordered' | 'ghost' | 'glass' | 'frost'\n * @attr {string} color - Inherited from ore-tabs: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n *\n * @slot prefix - Icon or content before the label\n * @slot - Tab label\n * @slot suffix - Badge or count after the label\n *\n * @cssprop --tab-item-radius - Button border radius\n * @cssprop --tab-item-transition - Transition duration/easing\n * @cssprop --tab-item-padding - Button padding\n * @cssprop --tab-item-font-size - Button font size\n * @cssprop --tab-item-color - Default text color\n * @cssprop --tab-item-hover-bg - Background on hover\n * @cssprop --tab-item-active-bg - Background when active/selected\n * @cssprop --tab-item-active-color - Text color when active/selected\n * @cssprop --tab-item-active-shadow - Box shadow when active/selected\n * @part tab - Tab trigger element.\n * @example\n * ```html\n * <ore-tab-item slot=\"tabs\" value=\"overview\">Overview</ore-tab-item>\n * <ore-tab-item slot=\"tabs\" value=\"settings\" disabled>Settings</ore-tab-item>\n * ```\n */\nexport const TAB_ITEM_TAG = 'ore-tab-item' as const;\ndefine<OreTabItemProps>(TAB_ITEM_TAG, {\n props: {\n ...disablableBundle,\n active: prop.bool(false),\n color: prop.string<ThemeColor>(),\n size: prop.string<ComponentSize>(),\n value: prop.string(''),\n variant: prop.string<SurfaceVariant>(),\n },\n setup(props, { bind, el, watch }) {\n const tabsCtx = inject(TABS_CTX);\n\n if (tabsCtx) {\n watch(() => {\n const color = tabsCtx.color.value;\n const size = tabsCtx.size.value;\n const variant = tabsCtx.variant.value;\n\n if (color !== undefined) el.setAttribute('color', color);\n\n if (size !== undefined) el.setAttribute('size', size);\n\n if (variant !== undefined) el.setAttribute('variant', variant);\n });\n }\n\n const isActive = computed(() =>\n tabsCtx ? !!tabsCtx.value.value && tabsCtx.value.value === props.value.value : props.active.value,\n );\n const isDisabled = () => Boolean(props.disabled.value);\n\n bind({\n attr: {\n active: () => (isActive.value ? true : undefined),\n },\n });\n\n const handleClick = (event: MouseEvent) => {\n event.stopPropagation();\n\n if (isDisabled()) {\n event.preventDefault();\n\n return;\n }\n\n el.dispatchEvent(new CustomEvent('click', { bubbles: true, detail: { value: props.value.value } }));\n };\n\n const tabId = () => `tab-${props.value.value}`;\n const controlsAttr = () => `tabpanel-${props.value.value}`;\n\n return html`\n <button\n role=\"tab\"\n type=\"button\"\n part=\"tab\"\n :id=\"${tabId}\"\n aria-selected=\"${isActive}\"\n tabindex=\"${() => (isActive.value ? '0' : '-1')}\"\n aria-disabled=\"${isDisabled}\"\n :aria-controls=\"${controlsAttr}\"\n @click=\"${handleClick}\">\n <slot name=\"prefix\"></slot>\n <slot></slot>\n <slot name=\"suffix\"></slot>\n </button>\n `;\n },\n styles: [colorThemeMixin, forcedColorsFocusMixin('button'), coarsePointerMixin, styles],\n});\n","@layer refine.base {\n :host {\n display: none;\n width: 100%;\n }\n\n :host([active]) {\n display: flex;\n flex: 1;\n flex-direction: column;\n min-height: 0;\n }\n\n .panel {\n box-sizing: border-box;\n flex: 1;\n height: 100%;\n min-height: 0;\n padding: var(--tab-panel-padding, var(--size-4));\n overflow: auto;\n font-size: var(--tab-panel-font-size, var(--text-sm));\n color: var(--text-color-body);\n animation: var(--_motion-animation, tab-panel-in var(--transition-normal) var(--ease-out) both);\n }\n}\n\n@layer refine.variants {\n @keyframes tab-panel-in {\n from {\n opacity: 0;\n translate: 0 4px;\n }\n\n to {\n opacity: 1;\n translate: 0 0;\n }\n }\n}\n","import { define, html, inject, prop } from '@vielzeug/ore';\nimport { styleMap, when } from '@vielzeug/ore/directives';\nimport { computed, signal } from '@vielzeug/ripple';\n\nimport { reducedMotionMixin } from '../../styles';\nimport { TABS_CTX } from '../tabs/tabs';\nimport styles from './tab-panel.css?inline';\n\nconst TAB_PANEL_PADDING_PRESET: Record<string, string> = {\n '2xl': 'var(--size-12)',\n lg: 'var(--size-6)',\n md: 'var(--size-4)',\n none: '0',\n sm: 'var(--size-2)',\n xl: 'var(--size-8)',\n xs: 'var(--size-1)',\n};\n\nexport type OreTabPanelProps = {\n /** Active state (managed by ore-tabs) */\n active?: boolean;\n /** When true, the panel content is not rendered until first activation (preserves resources) */\n lazy?: boolean;\n /** Panel padding size: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' (default: 'md' = var(--size-4)) */\n padding?: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n /** Must match the `value` of its corresponding ore-tab-item */\n value: string;\n};\n\n/**\n * Content panel for a tab. Shown when its `value` matches the selected tab.\n *\n * @element ore-tab-panel\n *\n * @attr {string} value - Must match the corresponding ore-tab-item value\n * @attr {boolean} active - Toggled by the parent ore-tabs\n * @attr {string} padding - Panel padding: 'none' | 'xs' | 'sm' | 'md' (default) | 'lg' | 'xl' | '2xl'\n *\n * @slot - Panel content\n *\n * @cssprop --tab-panel-padding - Inner padding of the panel content area\n * @cssprop --tab-panel-font-size - Font size of the panel content\n * @part panel - Panel container.\n * @example\n * ```html\n * <ore-tab-panel value=\"overview\"><p>Overview content here</p></ore-tab-panel>\n * <ore-tab-panel value=\"settings\" padding=\"lg\"><p>Large padding</p></ore-tab-panel>\n * <ore-tab-panel value=\"code\" padding=\"none\"><pre>No padding for code</pre></ore-tab-panel>\n * ```\n */\nexport const TAB_PANEL_TAG = 'ore-tab-panel' as const;\ndefine<OreTabPanelProps>(TAB_PANEL_TAG, {\n props: {\n active: prop.bool(false),\n lazy: prop.bool(false),\n padding: prop.oneOf(['none', 'xs', 'sm', 'md', 'lg', 'xl', '2xl'] as const, 'md'),\n value: prop.string(''),\n },\n setup(props, { bind, watch }) {\n const tabsCtx = inject(TABS_CTX);\n const isActive = computed(() =>\n tabsCtx ? !!tabsCtx.value.value && tabsCtx.value.value === props.value.value : props.active.value,\n );\n\n bind({\n attr: {\n active: () => (isActive.value ? true : undefined),\n },\n });\n\n // Map padding prop to CSS variable\n const paddingValue = computed(() => {\n const key = props.padding.value ?? 'md';\n\n return TAB_PANEL_PADDING_PRESET[key] ?? TAB_PANEL_PADDING_PRESET.md;\n });\n // Track whether the panel has ever been active (for lazy rendering)\n const hasBeenActive = signal(false);\n\n watch(() => {\n if (isActive.value) hasBeenActive.value = true;\n });\n\n // shouldRender: true if not lazy OR has been active at least once\n const shouldRender = computed(() => !props.lazy.value || hasBeenActive.value);\n const panelStyle = styleMap({ '--tab-panel-padding': paddingValue });\n const panelId = () => `tabpanel-${props.value.value}`;\n const labelledById = () => `tab-${props.value.value}`;\n\n return html`\n <div\n class=\"panel\"\n part=\"panel\"\n role=\"tabpanel\"\n id=\"${() => panelId()}\"\n aria-labelledby=\"${() => labelledById()}\"\n aria-hidden=\"${() => String(!isActive.value)}\"\n :style=\"${panelStyle}\"\n tabindex=\"0\">\n ${when(shouldRender, () => html`<slot></slot>`)}\n </div>\n `;\n },\n styles: [reducedMotionMixin, styles],\n});\n","@layer refine.base {\n :host {\n --_color: var(--async-color, var(--color-contrast-500));\n --_icon-size: var(--async-icon-size, var(--size-12));\n --_gap: var(--async-gap, var(--size-3));\n\n display: block;\n }\n\n /* ── Status regions ─────────────────────────────────────────────── */\n\n /* All regions always exist in the shadow DOM; only one is visible at a time. */\n .region {\n display: none;\n }\n\n :host([status='idle']) .region-idle,\n :host([status='loading']) .region-loading,\n :host([status='empty']) .region-empty,\n :host([status='error']) .region-error,\n :host([status='success']) .region-success,\n :host(:not([status])) .region-success {\n display: block;\n }\n\n /* ── Empty state ─────────────────────────────────────────────────── */\n\n .empty-state {\n display: flex;\n flex-direction: column;\n gap: var(--_gap);\n align-items: center;\n justify-content: center;\n padding: var(--size-10) var(--size-6);\n color: var(--_color);\n text-align: center;\n }\n\n .empty-state .icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--_icon-size);\n height: var(--_icon-size);\n opacity: 0.4;\n }\n\n .empty-state .icon svg {\n width: 100%;\n height: 100%;\n }\n\n .empty-state .icon ore-icon {\n display: flex;\n width: 100%;\n height: 100%;\n }\n\n .empty-state .title {\n font-size: var(--text-sm);\n font-weight: var(--font-semibold);\n color: var(--color-contrast-700);\n }\n\n .empty-state .description {\n max-width: 28ch;\n font-size: var(--text-sm);\n line-height: var(--leading-relaxed);\n opacity: 0.75;\n }\n\n /* ── Error state ─────────────────────────────────────────────────── */\n\n .error-state {\n display: flex;\n flex-direction: column;\n gap: var(--_gap);\n align-items: center;\n justify-content: center;\n padding: var(--size-10) var(--size-6);\n color: var(--color-error-600);\n text-align: center;\n }\n\n .error-state .icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--_icon-size);\n height: var(--_icon-size);\n opacity: 0.7;\n }\n\n .error-state .icon svg {\n width: 100%;\n height: 100%;\n }\n\n .error-state .icon ore-icon {\n display: flex;\n width: 100%;\n height: 100%;\n }\n\n .error-state .title {\n font-size: var(--text-sm);\n font-weight: var(--font-semibold);\n color: var(--color-error-700);\n }\n\n .error-state .description {\n max-width: 32ch;\n font-size: var(--text-sm);\n line-height: var(--leading-relaxed);\n opacity: 0.85;\n }\n\n .error-state .retry-btn {\n display: inline-flex;\n gap: var(--size-1-5);\n align-items: center;\n padding: var(--size-2) var(--size-4);\n font-size: var(--text-sm);\n font-weight: var(--font-medium);\n color: var(--color-error-700);\n cursor: pointer;\n background: none;\n border: 1px solid currentcolor;\n border-radius: var(--rounded-md);\n transition: var(--_motion-transition, background var(--transition-fast), opacity var(--transition-fast));\n }\n\n .error-state .retry-btn ore-icon {\n flex: none;\n }\n\n .error-state .retry-btn:hover {\n background: color-mix(in oklch, var(--color-error-500) 10%, transparent);\n }\n\n .error-state .retry-btn:focus-visible {\n outline: 2px solid var(--color-error-500);\n outline-offset: 2px;\n }\n\n /* ── Loading (fallback skeleton block) ───────────────────────────── */\n\n .loading-default {\n display: flex;\n flex-direction: column;\n gap: var(--size-2);\n padding: var(--size-4);\n }\n}\n","import { define, html, prop } from '@vielzeug/ore';\nimport { when } from '@vielzeug/ore/directives';\nimport { type Readable, signal } from '@vielzeug/ripple';\n\nimport { reducedMotionMixin } from '../../styles';\nimport componentStyles from './async.css?inline';\n\nexport type AsyncStatus = 'idle' | 'loading' | 'empty' | 'error' | 'success';\n\nexport type OreAsyncEvents = {\n retry: void;\n};\n\nexport type OreAsyncProps = {\n 'empty-description'?: string;\n 'empty-label'?: string;\n 'error-description'?: string;\n 'error-label'?: string;\n retryable?: boolean;\n status?: AsyncStatus;\n};\n\n/**\n * A container for handling asynchronous states (loading, empty, error, success).\n * Simplifies data fetching UI by providing consistent fallbacks.\n *\n * @element ore-async\n *\n * @attr {string} status - current state: 'idle' | 'loading' | 'empty' | 'error' | 'success' (default: 'success')\n * @attr {boolean} retryable - show retry button in error state (default: false)\n * @attr {string} empty-label - title for empty state (default: 'No content yet')\n * @attr {string} empty-description - optional text for empty state\n * @attr {string} error-label - title for error state (default: 'Something went wrong')\n * @attr {string} error-description - optional text for error state\n *\n * @fires retry - Emitted when the retry button is clicked (no detail payload)\n *\n * @slot - default content shown in 'success' state\n * @slot loading - custom loading UI (overrides default skeletons)\n * @slot empty - custom empty UI (overrides default icon/label)\n * @slot error - custom error UI (overrides default icon/label)\n *\n * @cssprop --async-color - Text/icon color used by default async state content\n * @cssprop --async-gap - Vertical spacing between icon, title, description, and actions\n * @cssprop --async-icon-size - Icon size for built-in loading/empty/error visuals\n * @example\n * ```html\n * <!-- Success state: default slot is shown -->\n * <ore-async status=\"success\">\n * <ul><li>Item one</li><li>Item two</li></ul>\n * </ore-async>\n *\n * <!-- Loading state: shows skeleton placeholders -->\n * <ore-async status=\"loading\"></ore-async>\n *\n * <!-- Empty state with custom message -->\n * <ore-async status=\"empty\" empty-label=\"No results\" empty-description=\"Try adjusting your filters.\"></ore-async>\n *\n * <!-- Error state with retry button -->\n * <ore-async status=\"error\" retryable error-label=\"Failed to load\" error-description=\"Check your connection.\"></ore-async>\n * ```\n */\nexport const ASYNC_TAG = 'ore-async' as const;\ndefine<OreAsyncProps, OreAsyncEvents>(ASYNC_TAG, {\n props: {\n 'empty-description': prop.string(),\n 'empty-label': prop.string('No content yet'),\n 'error-description': prop.string(),\n 'error-label': prop.string('Something went wrong'),\n retryable: prop.bool(false),\n status: prop.oneOf(['idle', 'loading', 'empty', 'error', 'success'] as const, 'success'),\n },\n setup(props, { bind, emit }) {\n const hasLoadingSlot = signal(false);\n const hasEmptySlot = signal(false);\n const hasErrorSlot = signal(false);\n\n // Reflect status onto the host so CSS can show/hide each region.\n // ARIA attributes are driven reactively by bind().\n bind({\n attr: {\n ariaBusy: () => (props.status.value === 'loading' ? 'true' : 'false'),\n ariaLabel: () => (props.status.value === 'loading' ? 'Loading…' : null),\n ariaLive: () => (props.status.value === 'error' ? 'assertive' : 'polite'),\n status: props.status,\n },\n });\n\n const renderText = (className: 'title' | 'description', text: Readable<string | undefined> | undefined) => () =>\n text?.value ? html`<p class=\"${className}\">${text}</p>` : '';\n\n // All four regions are always in the shadow DOM — CSS on :host([status=\"…\"])\n // toggles their visibility. This means:\n // - No DOM churn on status transitions (no teardown/rebuild of slot elements).\n // - Live regions are always present, so screen readers announce correctly.\n // - focus is never lost across status changes.\n return html`\n <div class=\"region region-idle\" role=\"presentation\"></div>\n\n <div class=\"region region-loading\" role=\"status\">\n <slot\n name=\"loading\"\n @slotchange=${(e: Event) => {\n hasLoadingSlot.value = (e.target as HTMLSlotElement).assignedNodes().length > 0;\n }}></slot>\n ${when(\n hasLoadingSlot,\n () => html``,\n () => html`\n <div class=\"loading-default\" aria-hidden=\"true\">\n <ore-skeleton variant=\"text\" lines=\"1\" width=\"40%\"></ore-skeleton>\n <ore-skeleton variant=\"text\" lines=\"3\" width=\"100%\"></ore-skeleton>\n <ore-skeleton variant=\"text\" lines=\"1\" width=\"60%\"></ore-skeleton>\n </div>\n `,\n )}\n </div>\n\n <div class=\"region region-empty\">\n <slot\n name=\"empty\"\n @slotchange=${(e: Event) => {\n hasEmptySlot.value = (e.target as HTMLSlotElement).assignedNodes().length > 0;\n }}></slot>\n ${when(\n hasEmptySlot,\n () => html``,\n () => html`\n <div class=\"empty-state\" role=\"status\">\n <div class=\"icon\">\n <ore-icon name=\"inbox\" size=\"100%\" stroke-width=\"1.75\" aria-hidden=\"true\"></ore-icon>\n </div>\n ${renderText('title', props['empty-label'])} ${renderText('description', props['empty-description'])}\n </div>\n `,\n )}\n </div>\n\n <div class=\"region region-error\">\n <slot\n name=\"error\"\n @slotchange=${(e: Event) => {\n hasErrorSlot.value = (e.target as HTMLSlotElement).assignedNodes().length > 0;\n }}></slot>\n ${when(\n hasErrorSlot,\n () => html``,\n () => html`\n <div class=\"error-state\" role=\"alert\">\n <div class=\"icon\">\n <ore-icon name=\"triangle-alert\" size=\"100%\" stroke-width=\"1.75\" aria-hidden=\"true\"></ore-icon>\n </div>\n ${renderText('title', props['error-label'])} ${renderText('description', props['error-description'])}\n ${when(\n () => Boolean(props.retryable.value),\n () => html`\n <button class=\"retry-btn\" type=\"button\" @click=${() => emit('retry')}>\n <ore-icon name=\"refresh-cw\" size=\"1em\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n Try again\n </button>\n `,\n )}\n </div>\n `,\n )}\n </div>\n\n <div class=\"region region-success\" role=\"presentation\">\n <slot></slot>\n </div>\n `;\n },\n styles: [reducedMotionMixin, componentStyles],\n});\n","/**\n * Waits for a CSS exit animation or transition to finish, then calls `onDone`.\n *\n * Uses the Web Animations API (`element.getAnimations()`) when available for\n * precise, synchronous detection. Falls back to a single microtask + immediate\n * call when no relevant animations are running (e.g. `prefers-reduced-motion`\n * or overridden styles).\n *\n * @param el - The element whose animations/transitions to observe.\n * @param onDone - Callback invoked exactly once when all animations end.\n * @param type - `'animation'` (default) or `'transition'`.\n */\nexport function awaitExit(el: Element, onDone: () => void, type: 'animation' | 'transition' = 'animation'): void {\n // Force a synchronous style recalc so that any CSS class changes applied\n // immediately before this call (e.g. adding 'closing') are committed and\n // CSSTransition / CSSAnimation instances appear in getAnimations().\n // Reading getComputedStyle() is the lightest layout-flush trigger available;\n // in jsdom it is a no-op stub so test timing is unaffected.\n if (typeof getComputedStyle === 'function') void getComputedStyle(el).opacity;\n\n queueMicrotask(() => {\n const getAnimations = typeof el.getAnimations === 'function' ? () => el.getAnimations() : () => [];\n const relevant = getAnimations().filter((a) => {\n if (type === 'animation') return a instanceof CSSAnimation;\n\n if (type === 'transition') return a instanceof CSSTransition;\n\n return false;\n });\n\n if (relevant.length === 0) {\n onDone();\n\n return;\n }\n\n let done = false;\n const finish = () => {\n if (done) return;\n\n done = true;\n onDone();\n };\n\n // Resolve when ALL relevant animations are finished or cancelled.\n Promise.allSettled(relevant.map((a) => a.finished)).then(finish);\n });\n}\n","@layer refine.base {\n :host {\n --_bg: var(--alert-bg, var(--_theme-backdrop));\n --_color: var(--alert-color, var(--_theme-base));\n --_border-color: var(--alert-border-color, var(--_theme-border));\n --_radius: var(--alert-radius, var(--rounded-lg));\n --_padding: var(--alert-padding, var(--size-4));\n --_gap: var(--alert-gap, var(--size-3));\n --_font-size: var(--alert-font-size, var(--text-sm));\n --_shadow: var(--alert-shadow, var(--shadow-none));\n\n display: block;\n }\n\n .sr-announce {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n white-space: nowrap;\n border-width: 0;\n clip-path: inset(50%);\n }\n\n :host([dismissed]) {\n display: none;\n }\n\n :host([dismissing]) {\n overflow: hidden;\n pointer-events: none;\n animation: var(--_motion-animation, ore-alert-exit var(--transition-slow) var(--ease-in-out) forwards);\n }\n\n @keyframes ore-alert-exit {\n 0% {\n /* Use a large enough value to cover any realistic alert height. */\n max-height: 600px;\n margin-bottom: var(--size-3);\n opacity: 1;\n transform: scaleY(1);\n }\n\n 60% {\n opacity: 0;\n transform: scaleY(0.8);\n }\n\n 100% {\n max-height: 0;\n padding-top: 0;\n padding-bottom: 0;\n margin-bottom: 0;\n opacity: 0;\n transform: scaleY(0);\n }\n }\n\n .alert {\n display: grid;\n grid-template-columns: auto 1fr auto;\n row-gap: var(--size-1);\n padding: var(--_padding);\n overflow: hidden;\n font-size: var(--_font-size);\n line-height: var(--leading-normal);\n color: var(--_color);\n background: var(--_bg);\n border: var(--border) solid var(--_border-color);\n border-radius: var(--_radius);\n box-shadow: var(--_shadow);\n transition:\n background var(--transition-normal),\n border-color var(--transition-normal),\n box-shadow var(--transition-normal),\n color var(--transition-normal);\n }\n\n /* ── Icon ──────────────────────────────────────── */\n\n .icon {\n display: inline-flex;\n grid-row: 1;\n grid-column: 1;\n align-items: center;\n align-self: start;\n justify-content: center;\n margin-inline-end: var(--_gap);\n }\n\n /* Without heading: icon aligns with the body content */\n .alert:has(.header[hidden]) .icon {\n align-self: center;\n }\n\n .icon[hidden] {\n display: none;\n }\n\n /* ── Header row (heading + meta) ───────────────── */\n\n .header {\n display: flex;\n grid-row: 1;\n grid-column: 2;\n gap: var(--size-2);\n align-items: baseline;\n }\n\n .header[hidden] {\n display: none;\n }\n\n .heading {\n overflow: hidden;\n text-overflow: ellipsis;\n font-weight: var(--font-semibold);\n line-height: var(--leading-normal);\n white-space: nowrap;\n }\n\n .meta {\n margin-inline-start: auto;\n font-size: var(--text-xs);\n white-space: nowrap;\n opacity: 0.7;\n }\n\n :host(:not(:has([slot='meta']))) .meta {\n display: none;\n }\n\n /* ── Body ──────────────────────────────────────── */\n\n .body {\n grid-row: 2;\n grid-column: 1 / -1;\n min-width: 0;\n margin-top: var(--size-1);\n }\n\n /* Without heading: body moves up to share row with icon and close */\n .alert:has(.header[hidden]) .body {\n grid-row: 1;\n grid-column: 2;\n margin-top: 0;\n }\n\n /* ── Content ───────────────────────────────────── */\n\n .content {\n line-height: var(--leading-relaxed);\n }\n\n /* ── Actions ───────────────────────────────────── */\n\n .actions {\n display: flex;\n flex-wrap: wrap;\n grid-row: 3;\n grid-column: 1 / -1;\n gap: var(--size-2);\n margin-top: var(--size-2);\n }\n\n /* Without heading: actions move to row 2 */\n .alert:has(.header[hidden]) .actions {\n grid-row: 2;\n }\n\n .actions[hidden] {\n display: none;\n }\n\n /* Horizontal mode: 4-column grid — icon | body | actions | close */\n :host([horizontal]) .alert {\n grid-template-columns: auto 1fr auto auto;\n }\n\n :host([horizontal]) .body {\n grid-row: 1;\n grid-column: 2;\n align-self: center;\n margin-top: 0;\n }\n\n :host([horizontal]) .actions:not([hidden]) {\n flex-wrap: nowrap;\n grid-row: 1;\n grid-column: 3;\n margin-inline-start: var(--_gap);\n margin-top: 0;\n }\n\n :host([horizontal]) .close {\n grid-column: 4;\n align-self: center;\n }\n\n /* ── Close button ──────────────────────────────── */\n\n .close {\n display: inline-flex;\n grid-row: 1;\n grid-column: 3;\n align-items: center;\n align-self: start;\n justify-content: center;\n width: var(--size-5);\n min-width: var(--_touch-target);\n height: var(--size-5);\n min-height: var(--_touch-target);\n padding: 0;\n margin-inline-start: var(--_gap);\n color: inherit;\n cursor: pointer;\n background: transparent;\n border: none;\n border-radius: var(--rounded-sm);\n opacity: 0.7;\n transition:\n opacity var(--transition-fast),\n background var(--transition-fast);\n }\n\n .close[hidden] {\n display: none;\n }\n\n .close:hover {\n background: color-mix(in oklch, currentcolor 12%, transparent);\n opacity: 1;\n }\n\n .close:focus-visible {\n outline: var(--border-2) solid currentcolor;\n outline-offset: var(--border-2);\n opacity: 1;\n }\n\n /* Accented left border for flat and bordered variants */\n :host([variant='flat'][accented]) .alert,\n :host([variant='bordered'][accented]) .alert {\n border-inline-start-width: var(--border-4, 4px);\n }\n}\n\n@layer refine.variants {\n /* Flat (Default) — canvas background, theme-colored border and text */\n :host(:not([variant])),\n :host([variant='flat']) {\n --_bg: var(--alert-bg, var(--color-canvas));\n --_color: var(--alert-color, var(--_theme-base));\n --_border-color: var(--alert-border-color, var(--_theme-base));\n --_shadow: var(--alert-shadow, var(--shadow-none));\n }\n\n /* Solid — fully filled with theme color */\n :host([variant='solid']) {\n --_bg: var(--alert-bg, var(--_theme-base));\n --_color: var(--alert-color, var(--_theme-contrast));\n --_border-color: var(--alert-border-color, var(--_theme-base));\n --_shadow: var(--alert-shadow, var(--shadow-xs));\n }\n\n /* Bordered — tinted background with a subtle themed border */\n :host([variant='bordered']) {\n --_bg: var(--alert-bg, color-mix(in oklch, var(--_theme-backdrop), var(--color-canvas)));\n --_color: var(--alert-color, var(--_theme-base));\n --_border-color: var(--alert-border-color, color-mix(in oklch, var(--_theme-focus) 30%, transparent));\n --_shadow: var(--alert-shadow, var(--inset-shadow-2xs));\n }\n}\n","import { define, html, prop } from '@vielzeug/ore';\n\nimport type { ComponentSize, RoundedSize, ThemeColor } from '../../types';\n\nimport '../../content/icon/icon';\nimport { awaitExit } from '../../overlay/shared/await-exit';\nimport { roundableBundle, sizableBundle, themableBundle } from '../../shared';\nimport {\n coarsePointerMixin,\n colorThemeMixin,\n forcedColorsMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n sizeVariantMixin,\n} from '../../styles';\nimport componentStyles from './alert.css?inline';\n\nexport type OreAlertEvents = {\n dismiss: { originalEvent: MouseEvent };\n};\n\nexport type OreAlertProps = {\n /** Show a left accent border (for flat/bordered variants) */\n accented?: boolean;\n /** Theme color */\n color?: ThemeColor;\n /** Show a dismissible (×) button */\n dismissible?: boolean;\n /** Heading text shown above the content */\n heading?: string;\n /** Position action buttons to the right instead of below */\n horizontal?: boolean;\n /** Border radius */\n rounded?: RoundedSize | '';\n /** Alert size */\n size?: ComponentSize;\n /** Visual style variant */\n variant?: 'solid' | 'flat' | 'bordered';\n};\n\n/**\n * A status/feedback banner with optional heading, icon slot, and dismiss button.\n *\n * @element ore-alert\n *\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} variant - Visual style: 'flat' | 'solid' | 'bordered'\n * @attr {string} size - Size: 'sm' | 'md' | 'lg'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n * @attr {string} heading - Bold heading text above the content\n * @attr {boolean} dismissible - Show a close (×) button\n * @attr {boolean} accented - Add a left accent border (flat/bordered only)\n * @attr {boolean} horizontal - Position action buttons to the right instead of below\n *\n * @fires dismiss - Fired when the alert is dismissed. detail: { originalEvent: MouseEvent }\n *\n * @slot - Default slot for the alert message content\n * @slot icon - Icon on the left side\n * @slot meta - Metadata displayed alongside the heading (lighter, right-aligned)\n * @slot actions - Action buttons shown below the message\n *\n * @cssprop --alert-bg - Background color\n * @cssprop --alert-color - Text/icon color\n * @cssprop --alert-border-color - Border color\n * @cssprop --alert-shadow - Box shadow\n * @cssprop --alert-radius - Border radius\n * @cssprop --alert-padding - Padding\n * @cssprop --alert-gap - Gap between icon, body, and close button\n * @cssprop --alert-font-size - Font size\n *\n * @part alert - Alert root container.\n * @part icon - Icon container.\n * @part header - Header container.\n * @part heading - Heading text element.\n * @part meta - Meta text container.\n * @part body - Body content container.\n * @part content - Content container.\n * @part actions - Actions slot container.\n * @part close - Close action control.\n * @example\n * ```html\n * <ore-alert color=\"success\">Your changes have been saved.</ore-alert>\n * <ore-alert color=\"error\" variant=\"solid\" dismissible heading=\"Something went wrong\">\n * Please try again later.\n * </ore-alert>\n * ```\n */\nexport const ALERT_TAG = 'ore-alert' as const;\ndefine<OreAlertProps, OreAlertEvents>(ALERT_TAG, {\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...roundableBundle,\n accented: prop.bool(false),\n dismissible: prop.bool(false),\n heading: prop.string(),\n horizontal: prop.bool(false),\n variant: prop.string<'solid' | 'flat' | 'bordered'>(),\n },\n setup(props, { bind: _bind, el, emit, slots }) {\n let announceEl: HTMLElement | null = null;\n\n const announce = (message: string) => {\n if (!announceEl) return;\n\n announceEl.textContent = '';\n requestAnimationFrame(() => {\n if (announceEl) announceEl.textContent = message;\n });\n };\n\n const handleDismiss = (e: MouseEvent) => {\n if (!props.dismissible.value) return;\n\n el.setAttribute('dismissing', '');\n awaitExit(el, () => {\n el.removeAttribute('dismissing');\n el.setAttribute('dismissed', '');\n announce('Alert dismissed');\n emit('dismiss', { originalEvent: e });\n });\n };\n\n const alertRole = () => (props.color.value === 'error' ? 'alert' : 'status');\n\n return html`\n <span\n class=\"sr-announce\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n ref=\"${(ref: HTMLElement) => {\n announceEl = ref;\n }}\"></span>\n <div class=\"alert\" :role=\"${alertRole}\" part=\"alert\">\n <span class=\"icon\" part=\"icon\" aria-hidden=\"true\" ?hidden=\"${() => !slots.has('icon').value}\">\n <slot name=\"icon\"></slot>\n </span>\n <div class=\"header\" part=\"header\" ?hidden=\"${() => !props.heading.value}\">\n <span class=\"heading\" part=\"heading\">${props.heading}</span>\n <span class=\"meta\" part=\"meta\">\n <slot name=\"meta\"></slot>\n </span>\n </div>\n <div class=\"body\" part=\"body\">\n <div class=\"content\" part=\"content\">\n <slot></slot>\n </div>\n </div>\n <div class=\"actions\" part=\"actions\" ?hidden=\"${() => !slots.has('actions').value}\">\n <slot name=\"actions\"></slot>\n </div>\n <button\n class=\"close\"\n part=\"close\"\n type=\"button\"\n aria-label=\"Dismiss alert\"\n ?hidden=\"${() => !props.dismissible.value}\"\n @click=\"${handleDismiss}\">\n <ore-icon name=\"x\" size=\"16\" stroke-width=\"2.5\" aria-hidden=\"true\"></ore-icon>\n </button>\n </div>\n `;\n },\n styles: [\n colorThemeMixin,\n coarsePointerMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n forcedColorsMixin,\n sizeVariantMixin({\n lg: { '--_padding': 'var(--size-4) var(--size-5)', fontSize: 'var(--text-base)', gap: 'var(--size-3-5)' },\n sm: { '--_padding': 'var(--size-2) var(--size-3)', fontSize: 'var(--text-xs)', gap: 'var(--size-2)' },\n }),\n componentStyles,\n ],\n});\n","@layer refine.base {\n :host {\n --_bg: var(--badge-bg, var(--_theme-backdrop));\n --_color: var(--badge-color, var(--_theme-base));\n --_border-color: var(--badge-border-color, var(--_theme-border));\n --_radius: var(--badge-radius, var(--rounded-lg));\n --_font-size: var(--badge-font-size, var(--text-xs));\n --_font-weight: var(--badge-font-weight, var(--font-semibold));\n --_padding-x: var(--badge-padding-x, var(--size-1-5));\n --_padding-y: var(--badge-padding-y, var(--size-0-5));\n --_gap: var(--badge-gap, var(--size-1));\n\n display: inline-flex;\n vertical-align: middle;\n }\n\n .badge {\n display: inline-flex;\n gap: var(--_gap);\n align-items: center;\n justify-content: center;\n\n /* Dot-only (no text slot) gets circular shape */\n min-width: var(--size-2);\n max-width: var(--badge-max-width, 24ch);\n padding: var(--_padding-y) var(--_padding-x);\n overflow: hidden;\n text-overflow: ellipsis;\n font-size: var(--_font-size);\n font-weight: var(--_font-weight);\n line-height: 1;\n color: var(--_color);\n white-space: nowrap;\n background: var(--_bg);\n border: var(--border) solid var(--_border-color);\n border-radius: var(--_radius);\n }\n\n .badge-label {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n ::slotted([slot='icon']) {\n display: inline-flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n width: 1em;\n height: 1em;\n }\n}\n\n@layer refine.variants {\n /* Solid (Default) - Full theme color background */\n :host(:not([variant])),\n :host([variant='solid']) {\n --_bg: var(--badge-bg, var(--_theme-base));\n --_color: var(--badge-color, var(--_theme-contrast));\n --_border-color: var(--badge-border-color, var(--_theme-base));\n }\n\n /* Flat - Subtle background with theme color text */\n :host([variant='flat']) {\n --_bg: var(--badge-bg, color-mix(in oklch, var(--_theme-backdrop) 25%, var(--color-contrast-100)));\n --_color: var(--badge-color, var(--_theme-base));\n --_border-color: var(--badge-border-color, color-mix(in oklch, var(--_theme-focus) 20%, transparent));\n }\n\n /* Bordered - Outlined with filled background */\n :host([variant='bordered']) {\n --_bg: var(--badge-bg, var(--_theme-backdrop));\n --_color: var(--badge-color, var(--_theme-base));\n --_border-color: var(--badge-border-color, var(--_theme-border));\n }\n\n /* Outline - Transparent with colored border */\n :host([variant='outline']) {\n --_bg: var(--badge-bg, transparent);\n --_color: var(--badge-color, var(--_theme-base));\n --_border-color: var(--badge-border-color, var(--_theme-base));\n }\n\n /* Dot-only mode */\n :host([dot]) .badge {\n min-width: unset;\n padding: var(--_dot-padding, var(--size-1));\n line-height: 0;\n }\n}\n\n@layer refine.sizes {\n :host([size='xs']) {\n --_padding-x: var(--size-1);\n --_padding-y: 0px;\n --_font-size: var(--text-2xs);\n --_dot-padding: var(--size-0-5);\n }\n}\n\n@layer refine.overrides {\n /* Dot — always force badge background and border regardless of variant */\n :host([dot]) {\n --_bg: var(--badge-bg, var(--_theme-base));\n --_border-color: var(--badge-border-color, var(--_theme-base));\n }\n\n /* ========================================\n Anchor overlay mode\n ======================================== */\n\n :host([anchor]) {\n position: relative;\n display: inline-flex;\n }\n\n /*\n * Per-direction multiplier: +1 in LTR, -1 in RTL.\n * Used to flip the translateX offset so the badge always overflows\n * the correct physical edge that corresponds to its logical corner.\n */\n :host {\n --_dir: 1;\n }\n\n :host(:dir(rtl)) {\n --_dir: -1;\n }\n\n /* Default position: top-end */\n :host([anchor]) .badge {\n position: absolute;\n inset-inline-end: 0;\n top: 0;\n z-index: 1;\n transform: translate(calc(var(--_dir) * 30%), -30%);\n }\n\n :host([anchor='top-start']) .badge {\n inset-inline-start: 0;\n inset-inline-end: unset;\n transform: translate(calc(var(--_dir) * -30%), -30%);\n }\n\n :host([anchor='bottom-end']) .badge {\n top: unset;\n bottom: 0;\n transform: translate(calc(var(--_dir) * 30%), 30%);\n }\n\n :host([anchor='bottom-start']) .badge {\n inset-inline-start: 0;\n inset-inline-end: unset;\n top: unset;\n bottom: 0;\n transform: translate(calc(var(--_dir) * -30%), 30%);\n }\n}\n","import { define, html, prop } from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\n\nimport type { RoundedSize, ThemeColor, VisualVariant } from '../../types';\n\nimport { roundableBundle, themableBundle } from '../../shared';\nimport {\n colorThemeMixin,\n forcedColorsMixin,\n frostVariantMixin,\n roundedVariantMixin,\n sizeVariantMixin,\n} from '../../styles';\nimport componentStyles from './badge.css?inline';\n\ntype BadgeVariant = Extract<VisualVariant, 'solid' | 'flat' | 'bordered' | 'outline' | 'frost'>;\ntype BadgeSize = 'xs' | 'sm' | 'md' | 'lg';\n\n/** Badge component properties */\nexport type OreBadgeProps = {\n /**\n * When set, switches to overlay mode: the host becomes `position:relative`\n * and the badge pins to a corner over the slotted content.\n * Value controls which corner: 'top-end' (default) | 'top-start' | 'bottom-end' | 'bottom-start'\n */\n anchor?: 'top-end' | 'top-start' | 'bottom-end' | 'bottom-start';\n /** Theme color */\n color?: ThemeColor;\n /** Numeric count to display */\n count?: number;\n /** Render as a small dot with no label */\n dot?: boolean;\n /** Accessible label for assistive technology. Recommended for count-only and dot mode. */\n label?: string;\n /** Max count — displays \"<max>+\" when count exceeds this value */\n max?: number;\n /** Border radius override */\n rounded?: RoundedSize;\n /** Badge size */\n size?: BadgeSize;\n /** Visual style variant */\n variant?: BadgeVariant;\n};\n\n/**\n * A compact badge/chip for counts, statuses, and labels.\n * Supports numeric counts with overflow, dot mode, and icon slots.\n *\n * @element ore-badge\n *\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'outline' | 'frost'\n * @attr {string} size - Component size: 'xs' | 'sm' | 'md' | 'lg'\n * @attr {number} count - Numeric count to display\n * @attr {number} max - Max count before showing \"<max>+\"\n * @attr {boolean} dot - Render as a dot indicator (no text)\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'full' etc.\n *\n * @slot - Badge label text\n * @slot icon - Icon displayed before the label\n * @slot target - Element the badge is anchored to (used with the anchor attribute)\n *\n * @cssprop --badge-bg - Badge background color\n * @cssprop --badge-color - Badge text color\n * @cssprop --badge-border-color - Badge border color\n * @cssprop --badge-radius - Border radius\n * @cssprop --badge-font-size - Font size\n * @cssprop --badge-font-weight - Font weight\n * @cssprop --badge-padding-x - Horizontal padding\n * @cssprop --badge-padding-y - Vertical padding\n * @cssprop --badge-gap - Gap between icon and label\n *\n * @part badge - Shadow part for the `badge` element.\n * @example\n * ```html\n * <ore-badge color=\"primary\">New</ore-badge>\n * <ore-badge color=\"error\" count=\"5\"></ore-badge>\n * <ore-badge color=\"error\" count=\"120\" max=\"99\"></ore-badge>\n * <ore-badge color=\"success\" dot></ore-badge>\n * <ore-badge color=\"warning\" variant=\"flat\">Beta</ore-badge>\n * ```\n */\nexport const BADGE_TAG = 'ore-badge' as const;\ndefine<OreBadgeProps>(BADGE_TAG, {\n props: {\n ...themableBundle,\n size: prop.string<BadgeSize>(),\n ...roundableBundle,\n anchor: prop.string<'top-end' | 'top-start' | 'bottom-end' | 'bottom-start'>(),\n count: prop.number(),\n dot: prop.bool(false),\n label: prop.string(),\n max: prop.number(),\n variant: prop.string<BadgeVariant>(),\n },\n setup(props) {\n const label = computed(() => {\n const count = props.count.value != null ? Number(props.count.value) : undefined;\n const max = props.max.value != null ? Number(props.max.value) : undefined;\n\n if (count === undefined || Number.isNaN(count)) return undefined;\n\n if (max !== undefined && !Number.isNaN(max) && count > max) return `${max}+`;\n\n return String(count);\n });\n\n const ariaLabel = computed(() => {\n if (props.label.value) return props.label.value;\n\n if (props.dot.value) return undefined;\n\n if (label.value != null) return `${label.value} notifications`;\n\n return undefined;\n });\n\n return html`<span class=\"badge\" part=\"badge\" :aria-label=\"${ariaLabel}\">\n <slot name=\"icon\"></slot>\n <span ?hidden=\"${() => label.value == null}\">${label}</span>\n <span class=\"badge-label\" ?hidden=\"${() => label.value != null}\"><slot></slot></span>\n </span>\n <slot name=\"target\"></slot>`;\n },\n styles: [\n colorThemeMixin,\n forcedColorsMixin,\n roundedVariantMixin,\n frostVariantMixin('.badge'),\n sizeVariantMixin({\n lg: { '--_padding-x': 'var(--size-2-5)', '--_padding-y': 'var(--size-1)', fontSize: 'var(--text-sm)' },\n md: { '--_padding-x': 'var(--size-2)', '--_padding-y': 'var(--size-0-5)', fontSize: 'var(--text-xs)' },\n sm: { '--_padding-x': 'var(--size-1-5)', '--_padding-y': 'var(--size-px)', fontSize: 'var(--text-xs)' },\n }),\n componentStyles,\n ],\n});\n","@layer refine.base {\n :host {\n --_bg: var(--chip-bg, var(--color-contrast-150));\n --_color: var(--chip-color, var(--color-contrast-800));\n --_border-color: var(--chip-border-color, transparent);\n --_radius: var(--chip-radius, var(--rounded-lg));\n --_font-size: var(--chip-font-size, var(--text-sm));\n --_font-weight: var(--chip-font-weight, var(--font-medium));\n --_padding-x: var(--chip-padding-x, var(--size-2-5));\n --_padding-y: var(--chip-padding-y, var(--size-0-5));\n --_gap: var(--chip-gap, var(--size-1));\n\n display: inline-flex;\n align-items: center;\n max-width: 100%;\n vertical-align: middle;\n }\n\n .chip {\n position: relative;\n box-sizing: border-box;\n display: inline-flex;\n gap: var(--_gap);\n align-items: center;\n max-width: 100%;\n padding: var(--_padding-y) var(--_padding-x);\n font-size: var(--_font-size);\n font-weight: var(--_font-weight);\n line-height: 1.2;\n color: var(--_color);\n white-space: nowrap;\n background: var(--_bg);\n border: var(--border) solid var(--_border-color);\n border-radius: var(--_radius);\n transition:\n background var(--transition-fast),\n border-color var(--transition-fast),\n box-shadow var(--transition-fast),\n color var(--transition-fast);\n }\n\n .label {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n /* ========================================\n Remove Button\n ======================================== */\n\n .remove-btn {\n display: inline-flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n width: 1.35em;\n height: 1.35em;\n padding: 0;\n margin-inline: var(--size-0-5) calc(var(--size-2) * -1);\n color: inherit;\n cursor: pointer;\n background: color-mix(in oklch, currentcolor 12%, transparent);\n border: none;\n border-radius: var(--_radius);\n opacity: 0.7;\n transition:\n background var(--transition-fast),\n opacity var(--transition-fast);\n }\n\n .remove-btn:hover {\n background: color-mix(in oklch, currentcolor 28%, transparent);\n opacity: 1;\n }\n\n .remove-btn:focus-visible {\n outline: 2px solid currentcolor;\n outline-offset: 1px;\n opacity: 1;\n }\n\n /* ========================================\n Icon slot\n ======================================== */\n\n ::slotted([slot='icon']) {\n display: inline-flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n width: 1em;\n height: 1em;\n }\n\n .chip-btn {\n display: inline-flex;\n width: 100%;\n padding: 0;\n margin: 0;\n font: inherit;\n color: inherit;\n text-align: inherit;\n cursor: pointer;\n background: none;\n border: none;\n }\n\n .chip-btn:disabled {\n cursor: not-allowed;\n }\n\n :host([mode='selectable'][checked]) .chip {\n outline: var(--border-2) solid var(--_theme-base, currentColor);\n outline-offset: -2px;\n }\n\n :host([mode='selectable']:not([disabled])) .chip,\n :host([mode='action']:not([disabled])) .chip {\n cursor: pointer;\n }\n\n .chip-btn:focus-visible {\n outline: 2px solid var(--_theme-base, currentColor);\n outline-offset: 2px;\n border-radius: var(--_radius);\n }\n}\n\n@layer refine.variants {\n /* Solid (Default) — full theme color fill */\n :host(:not([variant])),\n :host([variant='solid']) {\n --_bg: var(--chip-bg, var(--_theme-base, var(--color-contrast-700)));\n --_color: var(--chip-color, var(--_theme-contrast, var(--color-contrast-50)));\n --_border-color: var(--chip-border-color, transparent);\n --_hover-bg: var(--chip-hover-bg, var(--_theme-focus, var(--color-contrast-800)));\n --_active-bg: var(--chip-active-bg, color-mix(in oklch, var(--_theme-focus, var(--color-contrast-800)) 85%, black));\n }\n\n /* Flat — subtle tint */\n :host([variant='flat']) {\n --_bg: var(--chip-bg, color-mix(in oklch, var(--_theme-backdrop, var(--color-contrast-200)) 55%, transparent));\n --_color: var(--chip-color, var(--_theme-base, var(--color-contrast-800)));\n --_border-color: var(--chip-border-color, transparent);\n --_hover-bg: var(--chip-hover-bg, var(--_theme-focus, var(--color-contrast-700)));\n --_hover-color: var(--chip-hover-color, var(--_theme-contrast, var(--color-contrast-50)));\n --_active-bg: var(--chip-active-bg, color-mix(in oklch, var(--_theme-focus, var(--color-contrast-800)) 85%, black));\n --_active-color: var(--chip-active-color, var(--_theme-contrast, var(--color-contrast-50)));\n }\n\n /* Bordered — backdrop fill with themed border */\n :host([variant='bordered']) {\n --_bg: var(--chip-bg, var(--_theme-backdrop, var(--color-contrast-50)));\n --_color: var(--chip-color, var(--_theme-base, var(--color-contrast-900)));\n --_border-color: var(--chip-border-color, var(--_theme-border, var(--color-contrast-300)));\n --_remove-bg: var(--chip-remove-bg, var(--_theme-focus, var(--color-contrast-700)));\n --_remove-color: var(--chip-remove-color, var(--_theme-backdrop, var(--color-contrast-50)));\n --_hover-bg: var(--chip-hover-bg, var(--_theme-focus, var(--color-contrast-700)));\n --_hover-color: var(--chip-hover-color, var(--_theme-contrast, var(--color-contrast-50)));\n --_hover-border-color: var(--chip-hover-border-color, var(--_theme-focus, var(--color-contrast-700)));\n --_active-bg: var(--chip-active-bg, color-mix(in oklch, var(--_theme-focus, var(--color-contrast-800)) 85%, black));\n --_active-color: var(--chip-active-color, var(--_theme-contrast, var(--color-contrast-50)));\n }\n\n /* Outline — transparent with colored border */\n :host([variant='outline']) {\n --_bg: var(--chip-bg, transparent);\n --_color: var(--chip-color, var(--_theme-base, var(--color-contrast-900)));\n --_border-color: var(--chip-border-color, var(--_theme-base, var(--color-contrast-400)));\n --_remove-bg: var(--chip-remove-bg, var(--_theme-focus, var(--color-contrast-700)));\n --_remove-color: var(--chip-remove-color, var(--_theme-backdrop, var(--color-contrast-50)));\n --_hover-bg: var(--chip-hover-bg, var(--_theme-backdrop, var(--color-contrast-100)));\n --_hover-border-color: var(--chip-hover-border-color, var(--_theme-focus, var(--color-contrast-700)));\n --_active-bg: var(--chip-active-bg, var(--_theme-base, var(--color-contrast-700)));\n --_active-color: var(--chip-active-color, var(--_theme-contrast, var(--color-contrast-50)));\n }\n\n /* Ghost — transparent, no border */\n :host([variant='ghost']) {\n --_bg: var(--chip-bg, transparent);\n --_color: var(--chip-color, var(--_theme-base, var(--color-contrast-900)));\n --_border-color: var(--chip-border-color, transparent);\n --_hover-bg: var(--chip-hover-bg, var(--_theme-backdrop, var(--color-contrast-100)));\n --_active-bg: var(--chip-active-bg, var(--_theme-base, var(--color-contrast-700)));\n --_active-color: var(--chip-active-color, var(--_theme-contrast, var(--color-contrast-50)));\n }\n\n /* ── Remove button theming (tokens set per-variant above) ── */\n\n :host([variant='bordered']) .remove-btn,\n :host([variant='outline']) .remove-btn {\n color: var(--_remove-color);\n background: var(--_remove-bg);\n border: var(--border) solid var(--_remove-bg);\n }\n\n :host([variant='bordered']) .remove-btn:hover,\n :host([variant='outline']) .remove-btn:hover {\n background: var(--chip-remove-hover-bg, color-mix(in oklch, var(--_remove-bg) 80%, var(--color-contrast-900)));\n opacity: 1;\n }\n\n :host([variant='ghost']) .remove-btn {\n border: var(--border) solid var(--_theme-focus, var(--color-contrast-400));\n }\n\n :host([variant='ghost']) .remove-btn:hover {\n background: var(--chip-remove-hover-bg, color-mix(in oklch, currentcolor 15%, transparent));\n }\n\n /* ========================================\n Hover / Active Feedback — interactive modes\n ======================================== */\n\n :host(\n :is(\n :not([variant]),\n [variant='solid'],\n [variant='flat'],\n [variant='bordered'],\n [variant='outline'],\n [variant='ghost']\n ):is([mode='selectable'], [mode='action']):not([disabled])\n )\n .chip-btn:hover\n .chip {\n color: var(--_hover-color, var(--_color));\n background: var(--_hover-bg, var(--_bg));\n border-color: var(--_hover-border-color, var(--_border-color));\n }\n\n :host(\n :is(\n :not([variant]),\n [variant='solid'],\n [variant='flat'],\n [variant='bordered'],\n [variant='outline'],\n [variant='ghost']\n ):is([mode='selectable'], [mode='action']):not([disabled])\n )\n .chip-btn:active\n .chip {\n color: var(--_active-color, var(--_color));\n background: var(--_active-bg, var(--_bg));\n box-shadow: var(--inset-shadow-2xs);\n }\n}\n","import { define, html, prop } from '@vielzeug/ore';\nimport { computed, signal, watch } from '@vielzeug/ripple';\n\nimport type { ComponentSize, RoundedSize, ThemeColor, VisualVariant } from '../../types';\n\nimport '../../content/icon/icon';\nimport {\n colorThemeMixin,\n disabledStateMixin,\n forcedColorsMixin,\n roundedVariantMixin,\n sizeVariantMixin,\n} from '../../styles';\n// ============================================\n// Styles\n// ============================================\nimport componentStyles from './chip.css?inline';\n\n// ============================================\n// Types\n// ============================================\n\n/** Chip component properties */\ntype ChipBaseProps = {\n /** Theme color */\n color?: ThemeColor;\n /** Disable interactions */\n disabled?: boolean;\n /** Accessible label (required for icon-only chips) */\n label?: string;\n /** Border radius override */\n rounded?: RoundedSize | '';\n /** Component size */\n size?: ComponentSize;\n /** Value associated with this chip — included in emitted event detail */\n value?: string;\n /** Visual style variant */\n variant?: Exclude<VisualVariant, 'text' | 'frost'>;\n};\n\ntype OreChipMode = 'static' | 'removable' | 'selectable' | 'action';\n\n/** Read-only presentation chip */\ntype StaticChipProps = {\n mode?: Extract<OreChipMode, 'static'>;\n};\n\n/** Removable chip mode */\ntype RemovableChipProps = {\n mode: Extract<OreChipMode, 'removable'>;\n};\n\n/** Selectable chip mode */\ntype SelectableChipProps = {\n /** Controlled checked state for `mode=\"selectable\"` */\n checked?: boolean | undefined;\n /** Initial checked state for uncontrolled `mode=\"selectable\"` */\n 'default-checked'?: boolean;\n mode: Extract<OreChipMode, 'selectable'>;\n};\n\n/** Action chip mode — behaves like a button, fires a click event without maintaining state */\ntype ActionChipProps = {\n mode: Extract<OreChipMode, 'action'>;\n};\n\ntype OreChipComponentProps = ChipBaseProps & {\n checked?: boolean | undefined;\n 'default-checked'?: boolean;\n mode?: OreChipMode;\n};\n\nexport type OreChipEvents = {\n change: { checked: boolean; originalEvent: Event; value: string | undefined };\n click: { originalEvent: MouseEvent; value: string | undefined };\n remove: { originalEvent: MouseEvent; value: string | undefined };\n};\n\nexport type OreChipProps = ChipBaseProps &\n (StaticChipProps | RemovableChipProps | SelectableChipProps | ActionChipProps);\n\n/**\n * A compact, styled label element. Supports icons, a remove button, colors, sizes, and variants.\n * Commonly used to represent tags, filters, or selected options in a multiselect field.\n *\n * @element ore-chip\n *\n * @attr {string} label - Accessible label (required for icon-only chips)\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'outline' | 'ghost'\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n * @attr {string} mode - Interaction mode: 'static' | 'removable' | 'selectable' | 'action'\n * @attr {boolean} disabled - Disable the chip\n * @attr {string} value - Value included in emitted event detail\n * @attr {boolean} checked - Controlled checked state for selectable chips\n * @attr {boolean} default-checked - Initial checked state for uncontrolled selectable chips\n *\n * @fires remove - Fired when the remove button is clicked. detail: { value: string, originalEvent: MouseEvent }\n * @fires change - Fired when a selectable chip toggles. detail: { checked: boolean, value: string, originalEvent: Event }\n * @fires click - Fired when an action chip is clicked. detail: { value: string, originalEvent: MouseEvent }\n *\n * @slot - Chip label text\n * @slot icon - Leading icon or decoration\n *\n * @cssprop --chip-bg - Background color\n * @cssprop --chip-color - Text color\n * @cssprop --chip-border-color - Border color\n * @cssprop --chip-radius - Border radius\n * @cssprop --chip-font-size - Font size\n * @cssprop --chip-font-weight - Font weight\n * @cssprop --chip-padding-x - Horizontal padding\n * @cssprop --chip-padding-y - Vertical padding\n * @cssprop --chip-gap - Gap between icon, label and remove button\n * @cssprop --chip-hover-bg - Background on hover (interactive modes)\n * @cssprop --chip-hover-color - Text color on hover (interactive modes)\n * @cssprop --chip-hover-border-color - Border color on hover (interactive modes)\n * @cssprop --chip-active-bg - Background when pressed (interactive modes)\n * @cssprop --chip-active-color - Text color when pressed (interactive modes)\n * @cssprop --chip-remove-bg - Remove button background (bordered/outline variants)\n * @cssprop --chip-remove-color - Remove button icon color (bordered/outline variants)\n * @cssprop --chip-remove-hover-bg - Remove button background on hover\n *\n * @part remove-btn - Remove action button.\n * @part chip-btn - Shadow part for the `chip-btn` element.\n * @part chip - Shadow part for the `chip` element.\n * @example\n * ```html\n * <!-- Static chip (read-only) -->\n * <ore-chip color=\"primary\">Design</ore-chip>\n *\n * <!-- Removable chip -->\n * <ore-chip color=\"success\" variant=\"flat\" mode=\"removable\" value=\"ts\">\n * TypeScript\n * </ore-chip>\n *\n * <!-- Selectable chip (controlled) -->\n * <ore-chip color=\"info\" variant=\"flat\" mode=\"selectable\" checked value=\"ui\">\n * UI\n * </ore-chip>\n *\n * <!-- Selectable chip (uncontrolled) -->\n * <ore-chip color=\"info\" variant=\"flat\" mode=\"selectable\" default-checked value=\"ui\">\n * UI\n * </ore-chip>\n *\n * <!-- Action chip (acts like a button) -->\n * <ore-chip color=\"warning\" mode=\"action\" value=\"add\">\n * <svg slot=\"icon\" ...></svg>\n * Add Item\n * </ore-chip>\n *\n * <!-- Icon-only chip -->\n * <ore-chip color=\"error\" mode=\"action\" label=\"Delete\">\n * <svg slot=\"icon\" ...></svg>\n * </ore-chip>\n * ```\n */\nexport const CHIP_TAG = 'ore-chip' as const;\ndefine<OreChipComponentProps, OreChipEvents>(CHIP_TAG, {\n props: {\n checked: {\n default: undefined as OreChipComponentProps['checked'],\n parse: (value: string | null) => (value == null ? undefined : value !== 'false'),\n reflect: false,\n },\n color: prop.string<ThemeColor>(),\n 'default-checked': prop.bool(false),\n disabled: prop.bool(false),\n label: prop.string(),\n mode: prop.oneOf(['static', 'removable', 'selectable', 'action'] as const, 'static'),\n rounded: prop.string<RoundedSize | ''>(),\n size: prop.string<ComponentSize>(),\n value: prop.string(),\n variant: prop.string<Exclude<VisualVariant, 'text' | 'frost'>>(),\n },\n\n setup(props, { bind, el: _el, emit }) {\n // ============================================\n // State Management\n // ============================================\n // Once a checked prop is provided, treat the chip as controlled for the rest of its lifecycle.\n const isControlled = signal(props.checked.value !== undefined);\n // Internal tracking for uncontrolled selectable chips; seeded from default-checked.\n const checkedState = signal(!isControlled.value && props['default-checked'].value);\n\n watch(props.checked, (value) => {\n if (value !== undefined) {\n isControlled.value = true;\n }\n });\n\n // Effective checked value — reactive to checked prop changes in controlled mode.\n const isChecked = computed(() => {\n if (props.mode.value !== 'selectable') return false;\n\n if (isControlled.value) {\n return props.checked.value ?? false;\n }\n\n return checkedState.value;\n });\n\n bind({\n attr: {\n checked: () => (props.mode.value === 'selectable' && isChecked.value ? true : undefined),\n },\n });\n // ============================================\n // Event Handlers\n // ============================================\n function handleRemove(e: MouseEvent) {\n if (props.disabled.value) return;\n\n emit('remove', { originalEvent: e, value: props.value.value });\n }\n\n function handleSelectableActivate(e: MouseEvent) {\n e.stopPropagation();\n\n if (props.disabled.value) return;\n\n const nextChecked = !isChecked.value;\n\n if (!isControlled.value) {\n checkedState.value = nextChecked;\n }\n\n emit('change', { checked: nextChecked, originalEvent: e, value: props.value.value });\n }\n\n function handleActionClick(e: MouseEvent) {\n if (props.disabled.value) return;\n\n emit('click', { originalEvent: e, value: props.value.value });\n }\n\n // ============================================\n // Template Helpers\n // ============================================\n const renderChipContent = () => html`\n <slot name=\"icon\"></slot>\n <span class=\"label\"><slot></slot></span>\n `;\n\n const removeBtnLabel = () => {\n const label = props.label.value || props.value.value;\n\n return label ? `Remove ${label}` : 'Remove';\n };\n\n const renderRemoveButton = () => html`\n <button\n class=\"remove-btn\"\n part=\"remove-btn\"\n type=\"button\"\n :aria-label=\"${removeBtnLabel}\"\n ?hidden=\"${() => props.mode.value !== 'removable'}\"\n :disabled=\"${props.disabled}\"\n @click=\"${handleRemove}\">\n <ore-icon name=\"x\" size=\"12\" stroke-width=\"2.5\" aria-hidden=\"true\"></ore-icon>\n </button>\n `;\n\n const renderSelectableChip = () => html`\n <button\n class=\"chip-btn\"\n part=\"chip-btn\"\n type=\"button\"\n role=\"checkbox\"\n :aria-checked=\"${() => String(isChecked.value)}\"\n :aria-label=\"${props.label}\"\n :disabled=\"${props.disabled}\"\n @click=\"${handleSelectableActivate}\">\n <span class=\"chip\" part=\"chip\"> ${renderChipContent()} </span>\n </button>\n `;\n\n const renderActionChip = () => html`\n <button\n class=\"chip-btn\"\n part=\"chip-btn\"\n type=\"button\"\n :aria-label=\"${props.label}\"\n :disabled=\"${props.disabled}\"\n @click=\"${handleActionClick}\">\n <span class=\"chip\" part=\"chip\"> ${renderChipContent()} </span>\n </button>\n `;\n\n const renderStaticChip = () => html` <span class=\"chip\" part=\"chip\"> ${renderChipContent()} </span> `;\n\n const renderRemovableChip = () => html`\n <span class=\"chip\" part=\"chip\"> ${renderChipContent()} ${renderRemoveButton()} </span>\n `;\n\n // ============================================\n // Render\n // ============================================\n return html`\n ${() => {\n const mode = props.mode.value;\n\n if (mode === 'selectable') return renderSelectableChip();\n\n if (mode === 'action') return renderActionChip();\n\n if (mode === 'removable') return renderRemovableChip();\n\n return renderStaticChip();\n }}\n `;\n },\n styles: [\n colorThemeMixin,\n disabledStateMixin,\n roundedVariantMixin,\n sizeVariantMixin({\n lg: {\n '--_font-size': 'var(--text-sm)',\n '--_gap': 'var(--size-1-5)',\n '--_padding-x': 'var(--size-3)',\n '--_padding-y': 'var(--size-1)',\n },\n sm: {\n '--_font-size': 'var(--text-xs)',\n '--_gap': 'var(--size-0-5)',\n '--_padding-x': 'var(--size-2-5)',\n '--_padding-y': 'var(--size-px)',\n },\n }),\n forcedColorsMixin,\n componentStyles,\n ],\n});\n","@layer refine.base {\n :host {\n --_height: var(--password-strength-height, 0.375rem);\n --_gap: var(--password-strength-gap, var(--space-1, 0.25rem));\n --_radius: var(--password-strength-radius, var(--rounded-full));\n --_track-bg: var(--password-strength-track-bg, var(--color-contrast-300, #d1d5db));\n --_track-border: var(--password-strength-track-border, var(--color-contrast-400, #9ca3af));\n --_active-color: var(--password-strength-weak-color, var(--color-warning-500, #f59e0b));\n\n display: grid;\n gap: var(--space-1, 0.25rem);\n width: 100%;\n }\n\n :host([data-level='fair']) {\n --_active-color: var(--password-strength-fair-color, var(--color-warning-600, #d97706));\n }\n\n :host([data-level='good']) {\n --_active-color: var(--password-strength-good-color, var(--color-success-500, #22c55e));\n }\n\n :host([data-level='strong']) {\n --_active-color: var(--password-strength-strong-color, var(--color-success-600, #16a34a));\n }\n\n .meter {\n width: 100%;\n min-width: 10rem;\n }\n\n .segments {\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n gap: var(--_gap);\n }\n\n .segment {\n height: var(--_height);\n min-height: 0.35rem;\n background: var(--_track-bg);\n border: 1px solid var(--_track-border);\n border-radius: var(--_radius);\n transition: var(--_motion-transition, background-color var(--transition-fast), border-color var(--transition-fast));\n }\n\n .segment.active {\n background: var(--_active-color);\n border-color: var(--_active-color);\n }\n\n .level-label {\n min-height: 1.25em;\n font-size: var(--password-strength-label-size, var(--text-sm, 0.875rem));\n line-height: 1.25;\n color: var(--password-strength-label-color, currentColor);\n }\n}\n","import { define, html, prop } from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\n\nimport { reducedMotionMixin } from '../../styles';\nimport componentStyles from './password-strength.css?inline';\n\n/** Scoring levels for password strength. */\nexport type PasswordStrengthLevel = 'empty' | 'weak' | 'fair' | 'good' | 'strong';\n\n/** Props accepted by <ore-password-strength>. */\nexport type OrePasswordStrengthProps = {\n /** Accessible name for assistive technology. Default: 'Password strength'. */\n label?: string;\n /**\n * Optional level labels in order: empty, weak, fair, good, strong.\n * If omitted or invalid length, defaults are used.\n */\n labels?: string[];\n /**\n * Optional score override (0..4). Use this to integrate external scorers\n * such as zxcvbn while keeping block rendering and accessibility behavior.\n * -1 means no override (default).\n */\n score?: number;\n /** Whether to render visible textual feedback. Default: true. */\n 'show-label'?: boolean;\n /** Password string to evaluate. */\n value?: string;\n};\n\n/**\n * Strong password meter with segmented progress visualization.\n *\n * Built-in scoring is heuristic and conservative:\n * - length < 6 => weak\n * - length >= 8 with mixed case => fair\n * - + digit or symbol => good\n * - length >= 12 with mixed case, digit and symbol => strong\n *\n * @element ore-password-strength\n *\n * @attr {string} value - Password string to evaluate\n * @attr {number} score - Optional score override (0..4). Use -1 for no override (default: -1)\n * @attr {boolean} show-label - Show visible feedback label (default: true)\n * @attr {string} label - Accessible name (default: 'Password strength')\n *\n * @cssprop --password-strength-height Segment bar height\n * @cssprop --password-strength-gap Gap between segments\n * @cssprop --password-strength-radius Segment corner radius\n * @cssprop --password-strength-track-bg Inactive segment color\n * @cssprop --password-strength-label-size Visible label font size\n * @cssprop --password-strength-label-color Visible label color\n * @cssprop --password-strength-weak-color Weak state segment color\n * @cssprop --password-strength-fair-color Fair state segment color\n * @cssprop --password-strength-good-color Good state segment color\n * @cssprop --password-strength-strong-color Strong state segment color\n *\n * @example\n * ```html\n * <!-- Pair with an ore-input to evaluate in real time -->\n * <ore-input type=\"password\" label=\"Password\" name=\"password\" id=\"pwd\"></ore-input>\n * <ore-password-strength id=\"meter\"></ore-password-strength>\n * <script type=\"module\">\n * document.getElementById('pwd').addEventListener('input', (e) => {\n * document.getElementById('meter').value = e.target.value;\n * });\n * </script>\n *\n * <!-- Fixed score display (e.g. from a server-side score) -->\n * <ore-password-strength score=\"3\"></ore-password-strength>\n * ```\n */\nexport const PASSWORD_STRENGTH_TAG = 'ore-password-strength' as const;\ndefine<OrePasswordStrengthProps>(PASSWORD_STRENGTH_TAG, {\n props: {\n label: prop.string('Password strength'),\n labels: prop.json(undefined as string[] | undefined),\n score: prop.number(-1),\n 'show-label': prop.bool(true),\n value: prop.string(),\n },\n\n setup(props, { bind, el: _el }) {\n const defaultLabels: Record<PasswordStrengthLevel, string> = {\n empty: '',\n fair: 'Fair',\n good: 'Good',\n strong: 'Strong',\n weak: 'Weak',\n };\n\n const levels: PasswordStrengthLevel[] = ['empty', 'weak', 'fair', 'good', 'strong'];\n\n const computeScore = (password: string): 0 | 1 | 2 | 3 | 4 => {\n if (!password) return 0;\n\n if (password.length < 6) return 1;\n\n const hasLower = /[a-z]/.test(password);\n const hasUpper = /[A-Z]/.test(password);\n const hasDigit = /\\d/.test(password);\n const hasSymbol = /[^a-zA-Z0-9]/.test(password);\n const long = password.length >= 12;\n\n if (long && hasLower && hasUpper && hasDigit && hasSymbol) return 4;\n\n if ((hasLower || hasUpper) && (hasDigit || hasSymbol) && password.length >= 8) return 3;\n\n if ((hasLower || hasUpper) && password.length >= 8) return 2;\n\n return 1;\n };\n\n const computeLevel = (): PasswordStrengthLevel => {\n const external = props.score.value ?? -1;\n const finalScore =\n external >= 0 ? Math.max(0, Math.min(4, Math.trunc(external))) : computeScore(props.value.value ?? '');\n\n return levels[finalScore];\n };\n\n const score = computed<0 | 1 | 2 | 3 | 4>(() => {\n // score >= 0 means an external override was provided\n const external = props.score.value ?? -1;\n\n if (external >= 0) {\n return Math.max(0, Math.min(4, Math.trunc(external))) as 0 | 1 | 2 | 3 | 4;\n }\n\n return computeScore(props.value.value ?? '');\n });\n\n const levelLabel = computed<string>(() => {\n const custom = props.labels.value;\n\n if (Array.isArray(custom) && custom.length === 5) return String(custom[score.value] ?? '');\n\n return defaultLabels[computeLevel()];\n });\n\n const ariaValueText = computed<string | null>(() => {\n if (score.value === 0) return null;\n\n return levelLabel.value || null;\n });\n\n // Sync level change to data-level attribute reactively\n bind({\n attr: {\n 'data-level': () => computeLevel(),\n },\n });\n\n const segClass = (threshold: number) => () => `segment${score.value >= threshold ? ' active' : ''}`;\n\n return html`\n <div\n class=\"meter\"\n role=\"meter\"\n :aria-label=\"${props.label}\"\n aria-valuemin=\"0\"\n aria-valuemax=\"4\"\n :aria-valuenow=\"${() => String(score.value)}\"\n :aria-valuetext=\"${() => ariaValueText.value}\">\n <div class=\"segments\" aria-hidden=\"true\">\n <div class=\"${segClass(1)}\"></div>\n <div class=\"${segClass(2)}\"></div>\n <div class=\"${segClass(3)}\"></div>\n <div class=\"${segClass(4)}\"></div>\n </div>\n </div>\n ${() =>\n props['show-label'].value\n ? html`<span class=\"level-label\" aria-live=\"polite\" aria-atomic=\"true\">${() => levelLabel.value}</span>`\n : ''}\n `;\n },\n\n styles: [reducedMotionMixin, componentStyles],\n});\n","import{onCleanup as e,signal as t}from\"@vielzeug/ripple\";var n=(n,r)=>{let i=t(null),a=new IntersectionObserver(([e])=>{e&&(i.value=e)},r);return a.observe(n),e(()=>a.disconnect()),i};export{n as intersectionObserver};\n//# sourceMappingURL=intersection-observe.js.map","import{onCleanup as e,signal as t}from\"@vielzeug/ripple\";var n=n=>{let r=t({height:0,width:0}),i=new ResizeObserver(([e])=>{if(!e)return;let t=e.contentBoxSize[0];t&&(r.value={height:t.blockSize,width:t.inlineSize})});return i.observe(n),e(()=>i.disconnect()),r};export{n as resizeObserver};\n//# sourceMappingURL=resize-observe.js.map","@layer refine.base {\n :host {\n --_bg: var(--skeleton-bg, var(--color-contrast-200));\n --_highlight: var(--skeleton-highlight, var(--color-contrast-100));\n --_radius: var(--skeleton-radius, var(--rounded-lg));\n --_circle-size: var(--skeleton-size, var(--size-10));\n --_width: var(--skeleton-width, 100%);\n --_height: var(--skeleton-height, var(--size-4));\n --_line-gap: var(--skeleton-line-gap, var(--size-2));\n --_last-line-width: var(--skeleton-last-line-width, 60%);\n --_duration: var(--skeleton-duration, 1.6s);\n --_stripe-size: var(--skeleton-stripe-size, 8px);\n\n display: inline-block;\n width: var(--_width);\n height: var(--_height);\n }\n\n .stack {\n display: grid;\n gap: var(--_line-gap);\n width: 100%;\n height: 100%;\n }\n\n .bone {\n position: relative;\n width: 100%;\n height: 100%;\n overflow: hidden;\n background: var(--_bg);\n border-radius: var(--_radius);\n }\n\n .bone::after {\n position: absolute;\n inset: 0;\n content: '';\n background: linear-gradient(90deg, var(--_bg) 0%, var(--_highlight) 50%, var(--_bg) 100%);\n transform: translateX(-100%);\n animation: var(--_motion-animation, ore-skeleton-shimmer var(--_duration) linear infinite);\n }\n\n :host([data-animated='false']) .bone::after {\n display: none;\n }\n\n /* Pause shimmer when scrolled out of the viewport — no visible effect, saves GPU */\n :host([data-paused]) .bone::after {\n animation-play-state: paused;\n }\n\n @keyframes ore-skeleton-shimmer {\n to {\n transform: translateX(100%);\n }\n }\n\n /* In RTL the shimmer should sweep right-to-left */\n :host(:dir(rtl)) .bone::after {\n animation-direction: reverse;\n }\n}\n\n@layer refine.variants {\n /* Circle variant — avatars, icons */\n :host([variant='circle']) {\n --_radius: var(--rounded-full);\n\n width: var(--skeleton-width, var(--_circle-size));\n height: var(--skeleton-height, var(--_circle-size));\n aspect-ratio: 1 / 1;\n }\n\n /* Text variant — thinner, for inline text lines */\n :host([variant='text']) {\n --_height: var(--size-3);\n --_radius: var(--rounded-sm);\n\n height: auto;\n }\n\n :host([variant='text']) .stack {\n height: auto;\n }\n\n :host([variant='text']) .bone {\n height: var(--_height);\n }\n\n :host([variant='text']) .bone[data-last='true'] {\n width: var(--_last-line-width);\n }\n}\n\n@layer refine.striped {\n :host([striped]) .stack {\n width: 99%;\n }\n\n :host([striped]) .bone {\n --_stripe-color: var(--skeleton-stripe-color, var(--color-contrast-400));\n\n background-color: transparent;\n border: var(--border) dashed var(--_stripe-color);\n }\n\n :host([striped]) .bone::before {\n --_stripe-color: var(--skeleton-stripe-color, var(--color-contrast-300));\n\n position: absolute;\n inset: 0;\n content: '';\n background-color: var(--_stripe-color);\n mask-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cline x1='0' y1='8' x2='8' y2='0' stroke='white' stroke-width='1'/%3E%3C/svg%3E\");\n mask-size: var(--_stripe-size) var(--_stripe-size);\n }\n\n :host([striped]) .bone::after {\n display: none;\n }\n}\n\n@layer refine.utilities {\n :host([size='sm']) {\n --_height: var(--size-3);\n --_circle-size: var(--size-8);\n }\n\n :host([size='md']) {\n --_height: var(--size-4);\n --_circle-size: var(--size-10);\n }\n\n :host([size='lg']) {\n --_height: var(--size-6);\n --_circle-size: var(--size-14);\n }\n}\n\n@media (forced-colors: active) {\n .bone {\n background: ButtonFace;\n border: 1px solid ButtonText;\n }\n\n .bone::after {\n display: none;\n }\n}\n","import { define, html, prop } from '@vielzeug/ore';\nimport { intersectionObserver } from '@vielzeug/ore/observers';\nimport { computed, signal, watch } from '@vielzeug/ripple';\n\nimport type { ComponentSize } from '../../types';\n\nimport { sizableBundle } from '../../shared';\nimport { reducedMotionMixin } from '../../styles';\nimport { safeCSSLength } from '../../utils';\nimport componentStyles from './skeleton.css?inline';\n\n/** Skeleton loader component properties */\nexport type OreSkeletonProps = {\n /** Toggle shimmer animation */\n animated?: boolean;\n /** Height override (e.g. '1rem', '3rem') */\n height?: string;\n /** Number of text lines for `variant='text'` */\n lines?: number;\n /** Radius override (e.g. '9999px', 'var(--rounded-xl)') */\n radius?: string;\n /** Size preset controlling line height and circle size */\n size?: ComponentSize;\n /** Render diagonal stripes instead of the shimmer — useful as a design-mode placeholder */\n striped?: boolean;\n /** Visual variant: 'rect' (default), 'circle', or 'text' */\n variant?: 'rect' | 'circle' | 'text';\n /** Width override (e.g. '12rem', '70%') */\n width?: string;\n};\n\n/**\n * A shimmer placeholder that represents loading content.\n * Control dimensions via the `--skeleton-width` and `--skeleton-height` CSS custom properties,\n * or via `width` / `height` inline styles.\n *\n * @element ore-skeleton\n *\n * @attr {string} variant - Shape: 'rect' (default) | 'circle' | 'text'\n * @attr {string} size - Height/circle preset: 'sm' | 'md' | 'lg'\n * @attr {string} width - Width override (CSS length/percentage)\n * @attr {string} height - Height override (CSS length)\n * @attr {string} radius - Radius override\n * @attr {boolean} animated - Disable with `animated=\"false\"`\n * @attr {number} lines - Text line count (only for `variant='text'`)\n * @attr {boolean} striped - Replace shimmer with diagonal stripes\n *\n * @cssprop --skeleton-bg - Base shimmer color\n * @cssprop --skeleton-highlight - Shimmer highlight color\n * @cssprop --skeleton-radius - Border radius\n * @cssprop --skeleton-size - Circle fallback size\n * @cssprop --skeleton-width - Width (default: 100%)\n * @cssprop --skeleton-height - Height (default: var(--size-4))\n * @cssprop --skeleton-line-gap - Vertical gap between text lines\n * @cssprop --skeleton-last-line-width - Width of the final text line\n * @cssprop --skeleton-duration - Shimmer animation duration\n * @cssprop --skeleton-stripe-size - Width of each diagonal stripe (default: 6px)\n *\n * @part stack - Stack container.\n * @part bone - Skeleton bone element.\n * @example\n * ```html\n * <!-- Paragraph lines -->\n * <ore-skeleton variant=\"text\" lines=\"3\" width=\"100%\"></ore-skeleton>\n *\n * <!-- Avatar -->\n * <ore-skeleton variant=\"circle\" size=\"md\"></ore-skeleton>\n *\n * <!-- Card image -->\n * <ore-skeleton width=\"100%\" height=\"10rem\"></ore-skeleton>\n * ```\n */\nexport const SKELETON_TAG = 'ore-skeleton' as const;\ndefine<OreSkeletonProps>(SKELETON_TAG, {\n props: {\n ...sizableBundle,\n animated: prop.bool(true),\n height: prop.string(),\n lines: prop.number(1),\n radius: prop.string(),\n striped: prop.bool(false),\n variant: prop.oneOf(['rect', 'circle', 'text'] as const, 'rect'),\n width: prop.string(),\n },\n setup(props, { bind, el, onMounted }) {\n const isPaused = signal(false);\n const lineCount = () => {\n const value = Math.floor(Number(props.lines.value));\n\n return Number.isFinite(value) && value > 0 ? value : 1;\n };\n const renderLineCount = () => (props.variant.value === 'text' ? lineCount() : 1);\n const styleDeps = () =>\n `${props.width.value ?? ''}|${props.height.value ?? ''}|${props.radius.value ?? ''}|${props.animated.value === false ? '0' : '1'}`;\n\n watch(\n computed(styleDeps),\n () => {\n const safeWidth = safeCSSLength(props.width.value);\n const safeHeight = safeCSSLength(props.height.value);\n const safeRadius = safeCSSLength(props.radius.value);\n\n if (safeWidth) el.style.setProperty('--skeleton-width', safeWidth);\n else el.style.removeProperty('--skeleton-width');\n\n if (safeHeight) el.style.setProperty('--skeleton-height', safeHeight);\n else el.style.removeProperty('--skeleton-height');\n\n if (safeRadius) el.style.setProperty('--skeleton-radius', safeRadius);\n else el.style.removeProperty('--skeleton-radius');\n\n const rawAnimated = el.getAttribute('animated');\n const isAnimated = rawAnimated !== 'false' && props.animated.value !== false;\n\n el.setAttribute('data-animated', isAnimated ? 'true' : 'false');\n },\n { immediate: true },\n );\n\n bind({\n attr: {\n 'data-paused': () => (isPaused.value ? true : undefined),\n },\n });\n\n onMounted(() => {\n const entry = intersectionObserver(el, { threshold: 0 });\n\n watch(entry, (e) => {\n const paused =\n typeof e === 'object' && e !== null && 'isIntersecting' in e\n ? !(e as IntersectionObserverEntry).isIntersecting\n : false;\n\n isPaused.value = paused;\n });\n });\n\n return html`\n <div class=\"stack\" part=\"stack\">\n ${() =>\n Array.from({ length: renderLineCount() }, (_, index) => {\n const isLastLine =\n props.variant.value === 'text' && renderLineCount() > 1 && index === renderLineCount() - 1;\n\n return html`<div\n class=\"bone\"\n part=\"bone\"\n aria-hidden=\"true\"\n :data-last=\"${() => (isLastLine ? 'true' : null)}\"></div>`;\n })}\n </div>\n `;\n },\n styles: [reducedMotionMixin, componentStyles],\n});\n","@layer refine.base {\n :host {\n --_position: var(--toast-position, fixed);\n --_inset-top: var(--toast-inset-top, auto);\n --_inset-bottom: var(--toast-inset-bottom, 1rem);\n --_inset-right: var(--toast-inset-right, 1rem);\n --_inset-left: var(--toast-inset-left, auto);\n --_z-index: var(--toast-z-index, 9999);\n --_max-width: var(--toast-max-width, 400px);\n --_gap: var(--toast-gap, 0.5rem);\n\n position: var(--_position);\n inset: var(--_inset-top) var(--_inset-right) var(--_inset-bottom) var(--_inset-left);\n z-index: var(--_z-index);\n display: flex;\n flex-direction: column;\n gap: var(--_gap);\n max-width: var(--_max-width);\n pointer-events: none;\n }\n\n /* ── Position variants ────────────────────────────────────────────────── */\n\n :host([position='top-left']) {\n --_inset-top: 1rem;\n --_inset-bottom: auto;\n --_inset-left: 1rem;\n --_inset-right: auto;\n }\n\n :host([position='top-center']) {\n --_inset-top: 1rem;\n --_inset-bottom: auto;\n --_inset-left: 50%;\n --_inset-right: auto;\n\n transform: translateX(-50%);\n }\n\n :host([position='top-right']) {\n --_inset-top: 1rem;\n --_inset-bottom: auto;\n --_inset-right: 1rem;\n --_inset-left: auto;\n }\n\n :host([position='bottom-left']) {\n --_inset-bottom: 1rem;\n --_inset-left: 1rem;\n --_inset-right: auto;\n --_inset-top: auto;\n }\n\n :host([position='bottom-center']) {\n --_inset-bottom: 1rem;\n --_inset-left: 50%;\n --_inset-right: auto;\n --_inset-top: auto;\n\n transform: translateX(-50%);\n }\n\n :host([position='bottom-right']) {\n --_inset-bottom: 1rem;\n --_inset-right: 1rem;\n --_inset-left: auto;\n --_inset-top: auto;\n }\n\n /* ── Container ────────────────────────────────────────────────────────── */\n\n .toast-container {\n display: grid;\n grid-template-rows: 1fr;\n grid-template-columns: 1fr;\n row-gap: 0;\n perspective: 1200px;\n perspective-origin: center center;\n transition: row-gap var(--transition-normal);\n }\n\n /* ARIA live regions are layout-transparent. */\n .toast-live-region {\n display: contents;\n }\n\n :host(.hovered) .toast-container {\n row-gap: var(--_gap);\n }\n\n /* ── Wrapper (layout / stacking only — no animation) ─────────────────── */\n\n /* .toast-wrapper owns: grid position, z-index, stacking transforms. */\n\n /* It never has opacity or transition set on it directly. */\n\n /* This keeps stacking rules and animation rules on separate elements, */\n\n /* eliminating all specificity conflicts and !important usage. */\n\n :host(:not(.hovered)) .toast-wrapper {\n grid-row: 1;\n grid-column: 1;\n align-self: end;\n }\n\n :host([position^='top']:not(.hovered)) .toast-wrapper {\n align-self: start;\n }\n\n .toast-wrapper {\n position: relative;\n pointer-events: auto;\n touch-action: pan-y;\n }\n\n /* Stacking (collapsed) — 3D perspective stack */\n :host(:not(.hovered)) .toast-wrapper:nth-last-child(1) {\n z-index: 3;\n transform: translateY(0) scale(1);\n }\n\n :host(:not(.hovered)) .toast-wrapper:nth-last-child(2) {\n z-index: 2;\n pointer-events: none;\n transform: translateY(-8px) scale(0.95);\n }\n\n :host(:not(.hovered)) .toast-wrapper:nth-last-child(3) {\n z-index: 1;\n pointer-events: none;\n transform: translateY(-14px) scale(0.9);\n }\n\n :host(:not(.hovered)) .toast-wrapper:nth-last-child(n + 4) {\n visibility: hidden;\n pointer-events: none;\n }\n\n /* Top positions: reverse stacking direction */\n :host([position^='top']) .toast-wrapper {\n transform-origin: center top;\n }\n\n :host([position^='top']:not(.hovered)) .toast-wrapper:nth-last-child(2) {\n transform: translateY(8px) scale(0.95);\n }\n\n :host([position^='top']:not(.hovered)) .toast-wrapper:nth-last-child(3) {\n transform: translateY(14px) scale(0.9);\n }\n\n /* Expanded (hovered) — stacking transforms are released per wrapper */\n :host(.hovered) .toast-wrapper {\n z-index: auto;\n visibility: visible;\n grid-row: auto;\n grid-column: 1;\n align-self: stretch;\n pointer-events: auto;\n transform: none;\n }\n\n /* Staggered expand delays (applied to wrapper transform only) */\n :host(.hovered) .toast-wrapper:nth-last-child(2) {\n transition-delay: var(--duration-75);\n }\n\n :host(.hovered) .toast-wrapper:nth-last-child(3) {\n transition-delay: var(--duration-100);\n }\n\n :host(.hovered) .toast-wrapper:nth-last-child(n + 4) {\n transition-delay: var(--duration-150);\n }\n\n /* ── Inner (animation target only — no layout role) ──────────────────── */\n\n /* .toast-inner owns: opacity, entry/exit transitions. */\n\n /* It never participates in stacking (that's the wrapper's job). */\n\n /* Swipe gesture also animates .toast-inner to keep wrapper state clean. */\n\n .toast-inner {\n position: relative;\n opacity: 1;\n transition: opacity var(--toast-exit-duration, 300ms) var(--ease-out);\n }\n\n /* Entry: snap to invisible with no transition, then rely on class removal to animate in */\n .toast-inner.entering {\n opacity: 0;\n transition: none;\n }\n\n /* Exit: fade out — wrapper stays in-flow so grid doesn't snap shut prematurely */\n .toast-inner.exiting {\n pointer-events: none;\n opacity: 0;\n }\n\n /* ── Alert inside toast ───────────────────────────────────────────────── */\n\n ::slotted(ore-alert),\n ore-alert {\n width: 100%;\n margin: 0;\n box-shadow: var(--shadow-lg);\n\n /* Suppress ore-alert's own collapse animation — the toast-inner opacity\n fade is the canonical exit. Passing --motion-animation: none overrides\n the @keyframes ore-alert-exit that fires on [dismissing]. */\n --_motion-animation: none;\n }\n\n /* ── Action buttons ───────────────────────────────────────────────────── */\n\n .toast-actions {\n display: flex;\n gap: var(--size-4);\n justify-content: flex-end;\n }\n\n /* ── Responsive: small screens ────────────────────────────────────────── */\n\n @media (width <= 480px) {\n :host {\n --_max-width: calc(100vw - var(--size-4));\n --_inset-right: var(--size-2);\n --_inset-left: var(--size-2);\n }\n\n :host([position='top-center']),\n :host([position='bottom-center']) {\n --_inset-left: var(--size-2);\n\n inset-inline-start: var(--size-2);\n transform: none;\n }\n }\n}\n","import { uuid } from '@vielzeug/arsenal';\nimport { define, html, prop, ref } from '@vielzeug/ore';\nimport { computed, signal, watch } from '@vielzeug/ripple';\n\nimport type { SwipeControl } from '../../headless';\nimport type { ComponentSize, RoundedSize, ThemeColor } from '../../types';\n\nimport { warn } from '../../_dev';\nimport { createSwipeControl } from '../../headless';\nimport { reducedMotionMixin } from '../../styles';\nimport componentStyles from './toast.css?inline';\n\n// ---------------------------------------------------------------------------\n// NOTE: Architecture\n//\n// Each toast has two DOM layers:\n// .toast-wrapper — layout / stacking / grid positioning (no animation)\n// .toast-inner — animation target (opacity fade in/out)\n//\n// This separation means stacking rules (nth-last-child, hover) and animation\n// rules never fight over the same element. No !important needed anywhere.\n//\n// State: a single signal<ToastEntry[]> owns all per-toast state (data, phase,\n// timer). There are no parallel Sets or Maps tracking lifecycle separately.\n//\n// Exit animation: .toast-inner.exiting fades opacity → 0.\n// The wrapper stays in-flow during the fade so the grid doesn't snap shut.\n// After transitionend (or TOAST_EXIT_MS fallback), finalize() removes the\n// toast from the entries array which removes the wrapper from the DOM.\n//\n// Swipe gesture animates .toast-inner (not .toast-wrapper) to avoid\n// polluting the wrapper's transition state used by the exit animation.\n// Swipe commit calls finalizeRemoval() directly — it owns the animation,\n// so the normal removeToast() path is not involved.\n//\n// Close button: owned by the toast template, not ore-alert. ore-alert renders\n// content only. This keeps ore-alert a pure presentational component with no\n// animation lifecycle coupling.\n//\n// Max eviction: when adding would exceed max, oldest non-exiting toasts are\n// dismissed via removeToast() — animated, with onDismiss callback + event.\n//\n// Dismiss queue: removed. Each toast exits independently in parallel.\n// ---------------------------------------------------------------------------\n\n/** Duration (ms) of the CSS opacity exit transition on .toast-inner.\n * Must match the value in toast.css: `transition: opacity 300ms`. */\nconst TOAST_EXIT_MS = 300;\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\nexport type OreToastEvents = {\n add: { id: string };\n dismiss: { id: string };\n};\n\nexport type OreToastProps = {\n max?: number;\n position?: 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';\n};\n\n/** Individual toast notification */\nexport type ToastItem = {\n actions?: Array<{\n color?: ThemeColor;\n label: string;\n onClick?: () => void;\n variant?: 'solid' | 'flat' | 'bordered';\n }>;\n color?: ThemeColor;\n dismissible?: boolean;\n /** Auto-dismiss delay in ms. Set to 0 for persistent toasts (default: 5000) */\n duration?: number;\n heading?: string;\n /** Show message and actions side-by-side (horizontal layout) */\n horizontal?: boolean;\n /** Auto-generated via crypto.randomUUID() if omitted */\n id?: string;\n message: string;\n /** Metadata text (e.g. timestamp) shown in the alert meta slot */\n meta?: string;\n /** Called after the toast is fully dismissed and removed */\n onDismiss?: () => void;\n rounded?: RoundedSize | '';\n size?: ComponentSize;\n /**\n * Urgency level for screen readers.\n * - `'polite'` (default): announced after the user finishes their current action.\n * - `'assertive'`: interrupts the user immediately. Use only for critical errors.\n */\n urgency?: 'polite' | 'assertive';\n variant?: 'solid' | 'flat' | 'bordered';\n};\n\ntype ToastPhase = 'entering' | 'active' | 'exiting';\n\ntype ToastTimer = {\n remaining: number;\n startedAt: number;\n timeoutId: ReturnType<typeof setTimeout>;\n};\n\n/** Internal: a ToastItem that has been normalized and given a lifecycle phase. */\ntype ToastEntry = Required<Pick<ToastItem, 'dismissible' | 'duration' | 'id'>> &\n Omit<ToastItem, 'dismissible' | 'duration' | 'id'> & {\n id: string;\n phase: ToastPhase;\n timer: ToastTimer | null;\n };\n\n/** Public API of the ore-toast element */\nexport interface ToastElement extends HTMLElement {\n add: (toast: ToastItem) => string;\n clear: () => void;\n dismiss: (id: string) => void;\n update: (id: string, updates: Partial<ToastItem>) => void;\n}\n\n// ─── Component ───────────────────────────────────────────────────────────────\n\n/**\n * An accessible toast stack with polite/assertive live regions and hover expansion.\n * Stacks up to 3 notifications with a 3D effect.\n *\n * @element ore-toast\n *\n * @attr {string} position - 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'\n * @attr {number} max - Max toasts in DOM at once (default: 5)\n *\n * @fires add - When a toast is added `{ id }`\n * @fires dismiss - When a toast is dismissed `{ id }`\n *\n * @slot - Manually placed `ore-alert` elements\n *\n * @cssprop --toast-position - Position type (default: fixed)\n * @cssprop --toast-inset-top - Top inset\n * @cssprop --toast-inset-bottom - Bottom inset\n * @cssprop --toast-inset-left - Left inset\n * @cssprop --toast-inset-right - Right inset\n * @cssprop --toast-z-index - Z-index (default: 9999)\n * @cssprop --toast-max-width - Max width (default: 400px)\n * @cssprop --toast-gap - Gap between expanded toasts (default: 0.5rem)\n * @cssprop --toast-exit-duration - Exit animation duration (default: 300ms)\n *\n * @example\n * ```html\n * <!-- Declarative: place once in HTML -->\n * <ore-toast position=\"bottom-right\"></ore-toast>\n *\n * <!-- Programmatic: use the singleton service -->\n * <script type=\"module\">\n * import { toast } from '@vielzeug/refine';\n * toast.success('Changes saved!');\n * </script>\n * ```\n */\n\n/** Renders the action buttons for a toast entry. */\nfunction renderToastActions(entry: ToastEntry, onDismiss: () => void) {\n if (!entry.actions?.length) return '';\n\n return html`\n <div slot=\"actions\" class=\"toast-actions\">\n ${entry.actions.map(\n (action) => html`\n <ore-button\n size=\"sm\"\n color=${action.color || entry.color || 'primary'}\n variant=${action.variant || 'solid'}\n @click=${() => {\n action.onClick?.();\n onDismiss();\n }}\n >${action.label}</ore-button\n >\n `,\n )}\n </div>\n `;\n}\n\nexport const TOAST_TAG = 'ore-toast' as const;\ndefine<OreToastProps, OreToastEvents>(TOAST_TAG, {\n props: {\n max: prop.number(5),\n position: prop.oneOf(\n ['top-left', 'top-center', 'top-right', 'bottom-left', 'bottom-center', 'bottom-right'] as const,\n 'bottom-right',\n ),\n },\n setup(props, { el, emit, onCleanup, onMounted }) {\n // Single source of truth for all toast state.\n const entries = signal<ToastEntry[]>([]);\n const containerRef = ref<HTMLDivElement>();\n\n // Per-toast swipe-to-dismiss controls (keyed by id, cleaned up in finalizeRemoval).\n const swipeControls = new Map<string, SwipeControl>();\n\n // Pause state is reactive so computed derivations and watches can observe it.\n const hoverPaused = signal(false);\n const focusPaused = signal(false);\n const paused = computed(() => hoverPaused.value || focusPaused.value);\n\n // ── Helpers ────────────────────────────────────────────────────────────\n\n const updateEntry = (id: string, patch: Partial<ToastEntry>) => {\n entries.value = entries.value.map((e) => (e.id === id ? { ...e, ...patch } : e));\n };\n\n const getEntry = (id: string) => entries.value.find((e) => e.id === id);\n\n const getInner = (wrapperOrEvent: HTMLElement | Event): HTMLElement | null => {\n const wrapper = wrapperOrEvent instanceof Event ? (wrapperOrEvent.currentTarget as HTMLElement) : wrapperOrEvent;\n\n return wrapper.querySelector<HTMLElement>('.toast-inner');\n };\n\n // ── Timer management ───────────────────────────────────────────────────\n\n const clearEntryTimer = (entry: ToastEntry): ToastEntry => {\n if (entry.timer) clearTimeout(entry.timer.timeoutId);\n\n return { ...entry, timer: null };\n };\n\n const scheduleTimer = (id: string, remaining: number) => {\n if (remaining <= 0) return;\n\n const timeoutId = setTimeout(() => removeToast(id), remaining);\n\n updateEntry(id, { timer: { remaining, startedAt: Date.now(), timeoutId } });\n };\n\n const pauseTimers = () => {\n entries.value = entries.value.map((e) => {\n if (!e.timer) return e;\n\n clearTimeout(e.timer.timeoutId);\n\n return {\n ...e,\n timer: { ...e.timer, remaining: Math.max(0, e.timer.remaining - (Date.now() - e.timer.startedAt)) },\n };\n });\n };\n\n const resumeTimers = () => {\n for (const e of entries.value) {\n if (!e.timer || e.timer.remaining <= 0) continue;\n\n const timeoutId = setTimeout(() => removeToast(e.id), e.timer.remaining);\n\n updateEntry(e.id, { timer: { ...e.timer, startedAt: Date.now(), timeoutId } });\n }\n };\n\n // Watch reactive pause state — automatically pauses/resumes all timers.\n watch(paused, (isPaused) => {\n if (isPaused) pauseTimers();\n else resumeTimers();\n });\n\n // ── Swipe gesture ──────────────────────────────────────────────────────\n // Animates .toast-inner to avoid polluting the wrapper transition state.\n // On commit, calls finalizeRemoval() directly (swipe owns the animation).\n\n const createToastSwipe = (id: string): SwipeControl => {\n // Same reset behavior whether the swipe was interrupted by the platform\n // (onCancel) or simply released without crossing the commit threshold\n // (onRelease) — the toast snaps back to rest either way.\n const resetSwipeStyles = ({ event }: { event: PointerEvent }): void => {\n const inner = getInner(event);\n\n if (!inner) return;\n\n inner.style.transition = '';\n inner.style.transform = '';\n inner.style.opacity = '';\n };\n\n return createSwipeControl({\n axis: () => 'x',\n // Do not capture pointers for toast swipe gestures; capture can steal\n // close-button clicks when the gesture does not move.\n captureTarget: () => null,\n disabled: computed(() => !(getEntry(id)?.dismissible ?? true)),\n onCancel: resetSwipeStyles,\n onCommit: ({ distance, event }) => {\n const inner = getInner(event);\n\n if (!inner) return;\n\n const dir = distance >= 0 ? 1 : -1;\n const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n const finish = () => finalizeRemoval(id);\n\n if (reducedMotion) {\n inner.style.opacity = '0';\n finish();\n\n return;\n }\n\n inner.style.transition = 'transform 0.22s ease-out, opacity 0.22s ease-out';\n void inner.offsetWidth;\n inner.style.transform = `translateX(${dir * 120}%)`;\n inner.style.opacity = '0';\n\n const onTransitionEnd = (e: TransitionEvent) => {\n if (e.target !== inner || e.propertyName !== 'transform') return;\n\n inner.removeEventListener('transitionend', onTransitionEnd);\n clearTimeout(fallback);\n finish();\n };\n\n const fallback = setTimeout(() => {\n inner.removeEventListener('transitionend', onTransitionEnd);\n finish();\n }, 300);\n\n inner.addEventListener('transitionend', onTransitionEnd);\n },\n onMove: ({ distance, event }) => {\n const inner = getInner(event);\n\n if (!inner) return;\n\n inner.style.transition = 'none';\n inner.style.transform = `translateX(${distance}px)`;\n inner.style.opacity = String(Math.max(0, 1 - Math.abs(distance) / 200));\n },\n onRelease: resetSwipeStyles,\n });\n };\n\n // ── Toast lifecycle ────────────────────────────────────────────────────\n\n /** Remove all per-entry resources and fire callbacks. Does not animate. */\n const finalizeRemoval = (id: string) => {\n const entry = getEntry(id);\n\n // Clean up timer and swipe control before removing from signal.\n if (entry?.timer) clearTimeout(entry.timer.timeoutId);\n\n swipeControls.delete(id);\n entries.value = entries.value.filter((e) => e.id !== id);\n entry?.onDismiss?.();\n emit('dismiss', { id });\n };\n\n const addToast = (item: ToastItem): string => {\n const id = item.id || uuid();\n const maxToasts = props.max?.value ?? 5;\n\n // Evict oldest non-exiting toasts to stay within max — animated, with callbacks.\n const active = entries.value.filter((e) => e.phase !== 'exiting');\n const overflow = active.length - (maxToasts - 1);\n\n if (overflow > 0) {\n for (const evicted of active.slice(0, overflow)) removeToast(evicted.id);\n }\n\n const entry: ToastEntry = {\n dismissible: true,\n duration: 5000,\n ...item,\n id,\n phase: 'entering',\n timer: null,\n };\n\n swipeControls.set(id, createToastSwipe(id));\n entries.value = [...entries.value, entry];\n emit('add', { id });\n\n requestAnimationFrame(() => {\n // Guard: if the toast was dismissed before this rAF fired (e.g. evicted\n // by max), do not overwrite its exiting phase back to active.\n if (getEntry(id)?.phase === 'entering') updateEntry(id, { phase: 'active' });\n });\n\n if (entry.duration > 0) scheduleTimer(id, entry.duration);\n\n return id;\n };\n\n const removeToast = (id: string) => {\n const entry = getEntry(id);\n\n // Already animating out or not found — ignore.\n if (!entry || entry.phase === 'exiting') return;\n\n // Clear the auto-dismiss timer: the user (or max-eviction) is dismissing now.\n updateEntry(id, { ...clearEntryTimer(entry), phase: 'exiting' });\n\n // Force a layout flush on the current inner element (if in DOM now) so the\n // browser snapshots the current opacity as the animation start value.\n const innerEl = containerRef.value?.querySelector<HTMLElement>(`[data-toast-id=\"${id}\"] .toast-inner`);\n\n void innerEl?.offsetHeight;\n\n let done = false;\n const onDone = () => {\n if (done) return;\n\n done = true;\n finalizeRemoval(id);\n };\n\n // TOAST_EXIT_MS is the built-in default, matching the CSS opacity transition's own\n // default. Read the *actual* computed duration so a consumer-customized\n // `--toast-exit-duration` doesn't get cut off by a shorter hardcoded fallback.\n // Fallback fires if transitionend never arrives (jsdom, reduced-motion, etc.).\n const computedExitMs = innerEl ? parseFloat(getComputedStyle(innerEl).transitionDuration) * 1000 : NaN;\n const exitMs = Number.isFinite(computedExitMs) && computedExitMs > 0 ? computedExitMs : TOAST_EXIT_MS;\n const fallback = setTimeout(onDone, exitMs + 50);\n\n // Listen on the container with event delegation so we are immune to\n // ore re-rendering the entries list (e.g. rAF phase transitions that\n // rebuild DOM after our listener would have been set up).\n // transitionend bubbles, so it reaches the container regardless of which\n // generation of .toast-inner element fires it.\n const onTransitionEnd = (e: TransitionEvent) => {\n const wrapper = (e.target as HTMLElement | null)?.closest?.(`[data-toast-id=\"${id}\"]`);\n\n if (!wrapper) return;\n\n containerRef.value?.removeEventListener('transitionend', onTransitionEnd);\n clearTimeout(fallback);\n onDone();\n };\n\n containerRef.value?.addEventListener('transitionend', onTransitionEnd);\n };\n\n const updateToast = (id: string, updates: Partial<ToastItem>) => {\n const entry = getEntry(id);\n\n if (!entry) return;\n\n const cleared = updates.duration !== undefined ? clearEntryTimer(entry) : entry;\n\n updateEntry(id, { ...cleared, ...updates, id });\n\n if (updates.duration !== undefined && updates.duration > 0) scheduleTimer(id, updates.duration);\n };\n\n const clearAll = () => {\n // Fire all removals concurrently — parallel fades are visually correct.\n for (const e of entries.value) {\n if (e.phase !== 'exiting') removeToast(e.id);\n }\n };\n\n // ── Derived lists for live regions ─────────────────────────────────────\n\n const urgencyOf = (e: ToastEntry) => e.urgency ?? (e.color === 'error' ? 'assertive' : 'polite');\n const politeEntries = computed(() => entries.value.filter((e) => urgencyOf(e) === 'polite'));\n const assertiveEntries = computed(() => entries.value.filter((e) => urgencyOf(e) === 'assertive'));\n\n // ── Cleanup on disconnect ──────────────────────────────────────────────\n\n onCleanup(() => {\n for (const e of entries.value) {\n if (e.timer) clearTimeout(e.timer.timeoutId);\n }\n\n swipeControls.clear();\n });\n\n // ── Template ───────────────────────────────────────────────────────────\n\n const renderEntry = (entry: ToastEntry) => {\n const dismiss = () => removeToast(entry.id);\n\n return html`\n <div\n class=\"toast-wrapper\"\n data-toast-id=${entry.id}\n part=\"toast-wrapper\"\n @pointerdown=${(e: PointerEvent) => swipeControls.get(entry.id)?.handlePointerDown(e)}\n @pointermove=${(e: PointerEvent) => swipeControls.get(entry.id)?.handlePointerMove(e)}\n @pointerup=${(e: PointerEvent) => swipeControls.get(entry.id)?.handlePointerUp(e)}\n @pointercancel=${(e: PointerEvent) => swipeControls.get(entry.id)?.handlePointerCancel(e)}>\n <div class=\"${() => `toast-inner${entry.phase !== 'active' ? ` ${entry.phase}` : ''}`}\" part=\"toast-inner\">\n <ore-alert\n color=${entry.color || (entry.urgency === 'assertive' ? 'error' : 'primary')}\n variant=${entry.variant || 'solid'}\n size=${entry.size || 'md'}\n rounded=${entry.rounded || 'md'}\n ?horizontal=${entry.horizontal}\n heading=${entry.heading || ''}\n ?dismissible=${entry.dismissible !== false}\n @dismiss=${dismiss}>\n ${entry.meta ? html`<span slot=\"meta\">${entry.meta}</span>` : ''} ${entry.message}\n ${renderToastActions(entry, dismiss)}\n </ore-alert>\n </div>\n </div>\n `;\n };\n\n // Expose imperative API directly on mount — calls made before mount are\n // safe because ore mounts synchronously on connectedCallback.\n onMounted(() => {\n const toastEl = el as ToastElement;\n\n toastEl.add = addToast;\n toastEl.clear = clearAll;\n toastEl.dismiss = removeToast;\n toastEl.update = updateToast;\n });\n\n return html`\n <div\n class=\"toast-container\"\n ref=${containerRef}\n @pointerenter=${() => {\n hoverPaused.value = true;\n el.classList.add('hovered');\n }}\n @pointerleave=${() => {\n hoverPaused.value = false;\n el.classList.remove('hovered');\n }}\n @focusin=${() => {\n focusPaused.value = true;\n }}\n @focusout=${() => {\n focusPaused.value = false;\n }}\n part=\"container\">\n <!-- Polite live region: normal informational toasts -->\n <div\n role=\"region\"\n aria-live=\"polite\"\n aria-relevant=\"additions removals\"\n aria-atomic=\"false\"\n aria-label=\"Notifications\"\n class=\"toast-live-region\">\n ${() => politeEntries.value.map(renderEntry)}\n </div>\n <!-- Assertive live region: critical errors that interrupt immediately -->\n <div\n role=\"region\"\n aria-live=\"assertive\"\n aria-relevant=\"additions removals\"\n aria-atomic=\"false\"\n aria-label=\"Critical notifications\"\n class=\"toast-live-region\">\n ${() => assertiveEntries.value.map(renderEntry)}\n </div>\n <slot></slot>\n </div>\n `;\n },\n styles: [reducedMotionMixin, componentStyles],\n});\n\n// ─── Toast service ────────────────────────────────────────────────────────────\n\nexport type ToastServiceConfig = OreToastProps;\n\nexport interface ToastService {\n /** Add a toast and return its id */\n add(item: ToastItem): string;\n /** Dismiss all toasts (animated, in parallel) */\n clear(): void;\n /**\n * Configure the auto-created container.\n * Has no effect if called after the first `add()` — logs a dev warning in that case.\n */\n configure(config: ToastServiceConfig): void;\n /** Dismiss a toast by id (animated) */\n dismiss(id: string): void;\n /** Shortcut: error toast with red color (assertive live region) */\n error(message: string, opts?: Partial<ToastItem>): string;\n /** Shortcut: info toast */\n info(message: string, opts?: Partial<ToastItem>): string;\n /**\n * Shows a loading toast tied to a promise.\n * Updates to success/error when the promise settles.\n */\n promise<T>(\n promise: Promise<T>,\n messages: {\n error: string | ((err: unknown) => string);\n loading: string;\n success: string | ((data: T) => string);\n },\n ): Promise<T>;\n /** Shortcut: success toast with green color */\n success(message: string, opts?: Partial<ToastItem>): string;\n /** Update an existing toast in-place */\n update(id: string, updates: Partial<ToastItem>): void;\n /** Shortcut: warning toast */\n warning(message: string, opts?: Partial<ToastItem>): string;\n}\n\n/**\n * Creates a scoped toast service backed by an `ore-toast` element.\n *\n * The service lazily creates an `<ore-toast>` element inside `root` on first\n * use. Pass a custom root to scope notifications to a sub-tree (e.g. a drawer),\n * or use the pre-built `toast` singleton which targets `document.body`.\n *\n * @example\n * ```ts\n * // Scoped instance\n * const drawerToast = createToastService(drawerEl);\n * drawerToast.success('Saved inside drawer');\n *\n * // The default singleton\n * import { toast } from '@vielzeug/refine';\n * toast.success('Saved!');\n * ```\n */\nexport function createToastService(root: ParentNode = document.body): ToastService {\n let host: ToastElement | null = null;\n let configured = false;\n let pendingConfig: ToastServiceConfig | null = null;\n\n const getHost = (): ToastElement => {\n if (host?.isConnected) return host;\n\n // Re-use an existing element in the root (supports declarative placement).\n host = (root instanceof Element ? root : (root as Document | ShadowRoot)).querySelector<ToastElement>('ore-toast');\n\n if (!host) {\n host = document.createElement('ore-toast') as ToastElement;\n\n if (pendingConfig) {\n if (pendingConfig.position) host.setAttribute('position', pendingConfig.position);\n\n if (pendingConfig.max != null) host.setAttribute('max', String(pendingConfig.max));\n\n pendingConfig = null;\n }\n\n (root as Element | Document).appendChild(host);\n }\n\n configured = true;\n\n return host;\n };\n\n const service: ToastService = {\n add(item) {\n return getHost().add(item);\n },\n\n clear() {\n getHost().clear();\n },\n\n configure(config) {\n if (configured) {\n warn('toast.configure() called after the container was already created; options ignored.');\n\n return;\n }\n\n pendingConfig = { ...pendingConfig, ...config };\n },\n\n dismiss(id) {\n getHost().dismiss(id);\n },\n\n error(message, opts) {\n return service.add({ color: 'error', ...opts, message });\n },\n\n info(message, opts) {\n return service.add({ color: 'info', ...opts, message });\n },\n\n async promise(promise, messages) {\n const id = service.add({ color: 'primary', dismissible: false, duration: 0, message: messages.loading });\n\n try {\n const data = await promise;\n\n service.update(id, {\n color: 'success',\n dismissible: true,\n duration: 5000,\n message: typeof messages.success === 'function' ? messages.success(data) : messages.success,\n });\n\n return data;\n } catch (err) {\n service.update(id, {\n color: 'error',\n dismissible: true,\n duration: 5000,\n message: typeof messages.error === 'function' ? messages.error(err) : messages.error,\n });\n throw err;\n }\n },\n\n success(message, opts) {\n return service.add({ color: 'success', ...opts, message });\n },\n\n update(id, updates) {\n getHost().update(id, updates);\n },\n\n warning(message, opts) {\n return service.add({ color: 'warning', ...opts, message });\n },\n };\n\n return service;\n}\n\n/**\n * Singleton toast service — finds or creates a single `<ore-toast>` on `document.body`.\n *\n * @example\n * ```ts\n * import { toast } from '@vielzeug/refine';\n *\n * toast.success('Changes saved!');\n * toast.error('Upload failed', { duration: 0 });\n *\n * const id = toast.add({ message: 'Uploading…', duration: 0, dismissible: false });\n * toast.update(id, { message: 'Done!', color: 'success', duration: 3000, dismissible: true });\n *\n * await toast.promise(uploadFile(), {\n * loading: 'Uploading…',\n * success: (url) => `Uploaded to ${url}`,\n * error: 'Upload failed',\n * });\n * ```\n */\nexport const toast: ToastService = createToastService();\n","@layer refine.base {\n :host {\n display: block;\n }\n\n fieldset {\n min-width: 0;\n padding: 0;\n margin: 0;\n border: none;\n }\n\n legend {\n padding: 0;\n margin-bottom: var(--size-2);\n font-size: var(--text-sm);\n font-weight: var(--font-medium);\n color: var(--color-contrast-600);\n }\n\n legend[hidden] {\n display: none;\n }\n\n .checkbox-group-items {\n display: flex;\n flex-direction: var(--checkbox-group-direction, column);\n gap: var(--checkbox-group-gap, var(--size-2));\n }\n\n .helper-text[hidden] {\n display: none;\n }\n\n .helper-text {\n padding-inline: 2px;\n margin-top: var(--size-1-5);\n font-size: var(--text-xs);\n line-height: var(--leading-tight);\n color: var(--color-contrast-500);\n }\n\n .error-text {\n padding-inline: 2px;\n margin-top: var(--size-1-5);\n font-size: var(--text-xs);\n line-height: var(--leading-tight);\n color: var(--color-error);\n }\n}\n\n@layer refine.variants {\n :host([orientation='horizontal']) .checkbox-group-items {\n --checkbox-group-direction: row;\n\n flex-wrap: wrap;\n }\n}\n","import { createContext, createStableId, define, useField, html, inject, prop } from '@vielzeug/ore';\nimport { when } from '@vielzeug/ore/directives';\nimport { computed, type Readable, signal } from '@vielzeug/ripple';\n\nimport type { ComponentSize, ThemeColor } from '../../types';\n\nimport {\n type ChoiceChangeDetail,\n lifecycleSignal,\n createChoiceField,\n getChoiceLabel,\n getLightChildrenByTag,\n} from '../../headless';\nimport { disablableBundle, sizableBundle, themableBundle } from '../../shared';\nimport { colorThemeMixin, disabledStateMixin, sizeVariantMixin } from '../../styles';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport componentStyles from './checkbox-group.css?inline';\n\n// ─── Context ──────────────────────────────────────────────────────────────────\n\nexport type CheckboxGroupContext = {\n color: Readable<ThemeColor | undefined>;\n disabled: Readable<boolean>;\n size: Readable<ComponentSize | undefined>;\n toggle: (value: string, originalEvent?: Event) => void;\n values: Readable<string[]>;\n};\n\nexport const CHECKBOX_GROUP_CTX = createContext<CheckboxGroupContext>('CheckboxGroupContext');\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport type OreCheckboxGroupProps = {\n /** Theme color — propagated to all child ore-checkbox elements */\n color?: ThemeColor;\n /** Disable all checkboxes in the group */\n disabled?: boolean;\n /** Error message shown below the group */\n error?: string;\n /** Helper text shown below the group */\n helper?: string;\n /** Legend / label for the fieldset. Required for accessibility. */\n label?: string;\n /** Form field name used during submission */\n name?: string;\n /** Layout direction of the checkbox options */\n orientation?: 'vertical' | 'horizontal';\n /** Mark the group as required */\n required?: boolean;\n /** Size — propagated to all child ore-checkbox elements */\n size?: ComponentSize;\n /** Comma-separated list of currently checked values */\n values?: string;\n};\n\nexport type OreCheckboxGroupEvents = {\n change: ChoiceChangeDetail;\n};\n\n/**\n * A fieldset wrapper that groups `ore-checkbox` elements, provides shared\n * `color` and `size` via context, and manages multi-value selection state.\n *\n * @element ore-checkbox-group\n *\n * @attr {string} label - Legend text (required for a11y)\n * @attr {string} values - Comma-separated list of checked values\n * @attr {boolean} disabled - Disable all checkboxes in the group\n * @attr {string} error - Error message\n * @attr {string} helper - Helper text\n * @attr {string} name - Form field name\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} orientation - Layout: 'vertical' | 'horizontal'\n * @attr {boolean} required - Required field\n *\n * @fires change - Emitted when selection changes. detail: { value: string, values: string[], labels: string[], originalEvent?: Event }\n *\n * @slot - Place `ore-checkbox` elements here\n *\n * @cssprop --checkbox-group-direction - Flex direction of the items list ('row' | 'column')\n * @cssprop --checkbox-group-gap - Gap between checkbox items\n * @part items - Items container.\n * @example\n * ```html\n * <ore-checkbox-group name=\"fruits\" label=\"Favourite fruits\" required>\n * <ore-checkbox value=\"apple\">Apple</ore-checkbox>\n * <ore-checkbox value=\"banana\">Banana</ore-checkbox>\n * <ore-checkbox value=\"cherry\">Cherry</ore-checkbox>\n * </ore-checkbox-group>\n * <ore-checkbox-group name=\"options\" orientation=\"horizontal\" color=\"primary\">\n * <ore-checkbox value=\"a\">Option A</ore-checkbox>\n * <ore-checkbox value=\"b\">Option B</ore-checkbox>\n * </ore-checkbox-group>\n * ```\n */\nexport const CHECKBOX_GROUP_TAG = 'ore-checkbox-group' as const;\ndefine<OreCheckboxGroupProps, OreCheckboxGroupEvents>(CHECKBOX_GROUP_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n error: prop.string(),\n helper: prop.string(),\n label: prop.string(),\n name: prop.string(),\n orientation: prop.string('vertical'),\n required: prop.bool(false),\n values: prop.string(),\n },\n setup(props, { bind, el, emit, onCleanup, provide, slots, watch }) {\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(bind, props, formCtx);\n\n let _formField: { reportValidity(): void } | null = null;\n const choice = createChoiceField({\n disabled: fCtxProps.disabled,\n error: props.error,\n getFormField: () => _formField,\n helper: props.helper,\n multiple: signal(true),\n prefix: 'checkbox-group',\n signal: lifecycleSignal(onCleanup),\n validateOn: formCtx?.validateOn,\n value: props.values,\n });\n\n _formField = useField<string>({ disabled: choice.disabled, toFormValue: (v) => v, value: choice.formValue });\n\n const checkedValues = choice.selectedValues;\n\n const getCheckboxes = (): HTMLElement[] => getLightChildrenByTag(el, 'ore-checkbox');\n const getLabelForValue = (value: string): string => getChoiceLabel(getCheckboxes(), value);\n const emitChange = (originalEvent?: Event) => {\n const values = checkedValues.value;\n\n const labels = values.map(getLabelForValue);\n\n emit('change', { labels, originalEvent, values });\n };\n\n const toggleCheckbox = (val: string, originalEvent?: Event) => {\n choice.toggleValue(val);\n el.setAttribute('values', choice.formValue.value);\n choice.triggerValidation('change');\n emitChange(originalEvent);\n };\n\n provide(CHECKBOX_GROUP_CTX, {\n color: props.color,\n disabled: computed(() => Boolean(props.disabled.value)),\n size: props.size,\n toggle: toggleCheckbox,\n values: checkedValues,\n });\n\n // Sync checked state + color/size/disabled onto slotted ore-checkbox children\n const syncChildren = () => {\n const values = checkedValues.value;\n const color = props.color.value;\n const size = props.size.value;\n const disabled = props.disabled.value;\n const checkboxes = getCheckboxes();\n\n for (const checkbox of checkboxes) {\n const val = checkbox.getAttribute('value') ?? '';\n\n checkbox.toggleAttribute('checked', values.includes(val));\n\n if (color) checkbox.setAttribute('color', color);\n else checkbox.removeAttribute('color');\n\n if (size) checkbox.setAttribute('size', size);\n else checkbox.removeAttribute('size');\n\n checkbox.toggleAttribute('disabled', Boolean(disabled));\n }\n };\n\n watch(() => {\n void slots.elements().value;\n syncChildren();\n });\n\n watch(() => {\n void slots.elements().value;\n\n const listeners = getCheckboxes().map((checkbox) => {\n const handler = (event: Event) => {\n event.stopPropagation();\n\n const val = (checkbox.getAttribute('value') ?? '').trim();\n\n if (!val) return;\n\n toggleCheckbox(val, event);\n };\n\n checkbox.addEventListener('change', handler);\n\n return () => {\n checkbox.removeEventListener('change', handler);\n };\n });\n\n return () => {\n for (const dispose of listeners) dispose();\n };\n });\n\n const legendId = createStableId('checkbox-group-legend');\n const errorId = `${legendId}-error`;\n const helperId = `${legendId}-helper`;\n const hasError = () => Boolean(props.error.value);\n const hasHelper = () => Boolean(props.helper.value) && !hasError();\n\n bind({ attr: { size: fCtxProps.size } });\n\n return html`\n <fieldset\n role=\"group\"\n aria-required=\"${() => String(Boolean(props.required.value))}\"\n aria-invalid=\"${() => String(hasError())}\"\n aria-errormessage=\"${() => (hasError() ? errorId : null)}\"\n aria-describedby=\"${() => (hasError() ? errorId : hasHelper() ? helperId : null)}\">\n <legend id=\"${legendId}\" ?hidden=${() => !props.label.value}>\n ${props.label}${when(\n () => Boolean(props.required.value),\n () => html`<span aria-hidden=\"true\"> *</span>`,\n )}\n </legend>\n <div class=\"checkbox-group-items\" part=\"items\">\n <slot></slot>\n </div>\n <div class=\"error-text\" id=\"${errorId}\" role=\"alert\" ?hidden=${() => !hasError()}>${props.error}</div>\n <div class=\"helper-text\" id=\"${helperId}\" ?hidden=${() => !hasHelper()}>${props.helper}</div>\n </fieldset>\n `;\n },\n styles: [colorThemeMixin, sizeVariantMixin(), disabledStateMixin, componentStyles],\n});\n","@layer refine.base {\n /* ========================================\n Base Styles & Defaults\n ======================================== */\n\n :host {\n --_size: var(--checkbox-size, var(--size-5));\n --_radius: var(--checkbox-radius, var(--rounded-lg));\n --_font-size: var(--checkbox-font-size, var(--text-sm));\n --_bg: var(--checkbox-bg, var(--color-contrast-200));\n --_border: var(--checkbox-border-color, var(--color-contrast-300));\n\n display: inline-flex;\n flex-wrap: wrap;\n gap: var(--_gap, var(--size-2));\n align-items: center;\n min-height: var(--_touch-target);\n cursor: pointer;\n user-select: none;\n }\n\n .checkbox-wrapper {\n position: relative;\n display: block;\n flex-shrink: 0;\n width: var(--_size);\n height: var(--_size);\n }\n\n .box {\n position: relative;\n box-sizing: border-box;\n width: var(--_size);\n height: var(--_size);\n background: var(--_bg);\n border: var(--border-2) solid var(--_border);\n border-radius: var(--_radius);\n transition:\n background var(--transition-normal),\n border-color var(--transition-normal),\n box-shadow var(--transition-normal);\n }\n\n /* ========================================\n Focus State\n ======================================== */\n\n input:focus-visible + .box {\n box-shadow: var(--_focus-shadow);\n }\n\n /* ========================================\n Icons (Checkmark & Dash)\n ======================================== */\n\n .checkmark,\n .dash {\n position: absolute;\n top: 50%;\n left: 50%;\n color: var(--_icon-color);\n opacity: 0;\n transform: translate(-50%, -50%) scale(0.5);\n transition:\n opacity var(--transition-spring),\n transform var(--transition-spring);\n }\n\n .checkmark::part(svg),\n .dash::part(svg) {\n width: calc(var(--_size) * 0.6);\n height: calc(var(--_size) * 0.6);\n fill: none;\n stroke: currentcolor;\n stroke-width: 3;\n stroke-linecap: round;\n stroke-linejoin: round;\n }\n\n /* ========================================\n Label\n ======================================== */\n\n .label {\n font-size: var(--_font-size);\n color: var(--color-contrast);\n }\n\n /* ========================================\n Helper / Error Text\n ======================================== */\n\n .helper-text[hidden] {\n display: none;\n }\n\n .helper-text {\n width: 100%;\n padding-inline-start: calc(var(--_size) + var(--size-2));\n font-size: var(--text-xs);\n line-height: var(--leading-tight);\n color: var(--color-contrast-500);\n }\n\n .helper-text[role='alert'] {\n color: var(--color-error);\n }\n}\n\n@layer refine.overrides {\n /* Map theme variables to checkbox-specific variables */\n :host {\n --_active-bg: var(--checkbox-checked-bg, var(--_theme-base));\n --_icon-color: var(--checkbox-color, var(--_theme-contrast));\n --_focus-shadow: var(--_theme-shadow);\n }\n\n /* ========================================\n Checked & Indeterminate States\n ======================================== */\n\n :host([checked]) .box,\n :host([indeterminate]) .box {\n background: var(--_active-bg);\n border-color: var(--_active-bg);\n }\n\n :host([checked]) .checkmark,\n :host([indeterminate]:not([checked])) .dash {\n opacity: 1;\n transform: translate(-50%, -50%) scale(1);\n }\n}\n","import { define, useField, html, inject, prop } from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\n\nimport type { CheckableProps, ComponentSize, ThemeColor } from '../../types';\n\nimport { type CheckableChangePayload, lifecycleSignal, createCheckable } from '../../headless';\nimport '../../content/icon/icon';\nimport { CONTROL_SIZE_PRESET, disablableBundle, sizableBundle, themableBundle } from '../../shared';\nimport {\n coarsePointerMixin,\n colorThemeMixin,\n disabledStateMixin,\n forcedColorsFormControlMixin,\n sizeVariantMixin,\n} from '../../styles';\nimport { CHECKBOX_GROUP_CTX } from '../checkbox-group/checkbox-group';\nimport { applyCheckableBinding } from '../shared/field-binding';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport { renderHelperRegion } from '../shared/templates';\nimport componentStyles from './checkbox.css?inline';\n\nexport type OreCheckboxEvents = {\n change: CheckableChangePayload;\n};\n\nexport type OreCheckboxProps = CheckableProps & {\n /** Theme color */\n color?: ThemeColor;\n /** Disable interaction */\n disabled?: boolean;\n /** Error message (marks field as invalid) */\n error?: string;\n /** Helper text displayed below the checkbox */\n helper?: string;\n /** Indeterminate state (partially checked) */\n indeterminate?: boolean;\n /** Component size */\n size?: ComponentSize;\n};\n\n/**\n * A customizable checkbox component with theme colors, sizes, and indeterminate state support.\n *\n * @element ore-checkbox\n *\n * @attr {boolean} checked - Checked state\n * @attr {boolean} disabled - Disable checkbox interaction\n * @attr {boolean} indeterminate - Indeterminate (partially checked) state\n * @attr {string} value - Field value submitted with forms\n * @attr {string} name - Form field name\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - Checkbox size: 'sm' | 'md' | 'lg'\n * @attr {string} error - Error message (marks field as invalid)\n * @attr {string} helper - Helper text displayed below the checkbox\n *\n * @fires change - Emitted when checkbox is toggled. detail: { checked: boolean, value: string, originalEvent?: Event }\n *\n * @slot - Checkbox label text\n *\n * @cssprop --checkbox-size - Control size (width and height)\n * @cssprop --checkbox-radius - Control border radius\n * @cssprop --checkbox-bg - Unchecked background color\n * @cssprop --checkbox-border-color - Unchecked border color\n * @cssprop --checkbox-checked-bg - Checked/indeterminate background color\n * @cssprop --checkbox-color - Checkmark icon color\n * @cssprop --checkbox-font-size - Label font size\n * @part checkbox - The checkbox wrapper element\n * @part box - The visual checkbox box\n * @part label - The label element\n * @part helper-text - The helper/error text element\n *\n * @example\n * ```html\n * <ore-checkbox name=\"agree\" required>I agree to the terms</ore-checkbox>\n * <ore-checkbox checked color=\"primary\" size=\"lg\">Enabled by default</ore-checkbox>\n * <ore-checkbox error=\"This field is required\" helper=\"Check to continue\">Accept</ore-checkbox>\n * ```\n */\nexport const CHECKBOX_TAG = 'ore-checkbox' as const;\ndefine<OreCheckboxProps, OreCheckboxEvents>(CHECKBOX_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n checked: prop.bool(false),\n error: prop.string(),\n helper: prop.string(),\n indeterminate: prop.bool(false),\n name: prop.string(),\n value: prop.string('on'),\n },\n setup(props, { bind, emit, onCleanup }) {\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(bind, props, formCtx);\n const groupCtx = inject(CHECKBOX_GROUP_CTX);\n\n let _formField: { reportValidity(): void } | null = null;\n const checkable = createCheckable({\n checked: props.checked,\n clearIndeterminateFirst: true,\n disabled: computed(() => fCtxProps.disabled.value || Boolean(groupCtx?.disabled.value)),\n error: props.error,\n getFormField: () => _formField,\n group: groupCtx,\n helper: props.helper,\n indeterminate: props.indeterminate,\n onToggle: (payload) => {\n checkable.triggerValidation('change');\n\n // In a checkbox-group, the group owns change emission/state updates.\n // Emitting here would bubble to the group and toggle a second time.\n if (groupCtx) return;\n\n emit('change', payload);\n },\n prefix: 'checkbox',\n signal: lifecycleSignal(onCleanup),\n validateOn: formCtx?.validateOn,\n value: props.value,\n });\n\n _formField = useField<string | null>({\n disabled: checkable.disabled,\n toFormValue: (v) => v,\n value: checkable.checkableFormValue,\n });\n\n const {\n assistiveId,\n checked,\n disabled,\n errorText,\n handleClick,\n handleKeydown,\n helperText,\n indeterminate,\n labelId,\n } = checkable;\n\n applyCheckableBinding(\n bind,\n fCtxProps.size,\n { assistiveId, checked, disabled, errorText, handleClick, handleKeydown, helperText, indeterminate, labelId },\n 'checkbox',\n );\n\n return html`\n <div class=\"checkbox-wrapper\" part=\"checkbox\">\n <div class=\"box\" part=\"box\">\n <ore-icon class=\"checkmark\" name=\"check\" size=\"14\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n <ore-icon class=\"dash\" name=\"minus\" size=\"14\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </div>\n </div>\n <span class=\"label\" part=\"label\" id=\"${labelId}\"><slot></slot></span>\n ${renderHelperRegion(assistiveId, errorText, helperText)}\n `;\n },\n styles: [\n colorThemeMixin,\n forcedColorsFormControlMixin,\n disabledStateMixin,\n coarsePointerMixin,\n sizeVariantMixin(CONTROL_SIZE_PRESET),\n componentStyles,\n ],\n});\n","import type { ComboboxOptionItem } from './combobox.types';\n\nexport function parseSlottedOptions(elements: Element[]): ComboboxOptionItem[] {\n return elements\n .filter((el) => el.localName === 'ore-combobox-option')\n .map((el) => ({\n disabled: el.hasAttribute('disabled'),\n iconEl: el.querySelector('[slot=\"icon\"]'),\n label:\n el.getAttribute('label') ||\n [...el.childNodes]\n .filter((node) => node.nodeType === Node.TEXT_NODE)\n .map((node) => node.textContent?.trim())\n .filter(Boolean)\n .join(' ') ||\n '',\n value: el.getAttribute('value') ?? '',\n }));\n}\n\nexport function filterOptions(options: ComboboxOptionItem[], query: string, noFilter: boolean): ComboboxOptionItem[] {\n if (noFilter) return options;\n\n const normalizedQuery = query.toLowerCase().trim();\n\n if (!normalizedQuery) return options;\n\n return options.filter(\n (option) =>\n option.label.toLowerCase().includes(normalizedQuery) || option.value.toLowerCase().includes(normalizedQuery),\n );\n}\n\nexport function getCreatableLabel(query: string, creatable: boolean, filteredOptions: ComboboxOptionItem[]): string {\n if (!creatable) return '';\n\n const trimmedQuery = query.trim();\n\n if (!trimmedQuery) return '';\n\n const exactMatch = filteredOptions.some((option) => option.label.toLowerCase() === trimmedQuery.toLowerCase());\n\n return exactMatch ? '' : `Create \"${trimmedQuery}\"`;\n}\n\nexport function makeCreatableValue(query: string): string {\n return `__new__:${query.trim()}`;\n}\n","@layer refine.base {\n /* ========================================\n Base Styles & Defaults\n ======================================== */\n\n :host {\n --_font-size: var(--input-font-size, var(--text-sm));\n --_gap: var(--input-gap, var(--size-2));\n --_field-height: var(--input-height, var(--size-10));\n --_padding: var(--input-padding, var(--size-1-5) var(--size-3));\n --_radius: var(--input-radius, var(--rounded-lg));\n --_placeholder: var(--input-placeholder-color, var(--color-contrast-500));\n --_bg: var(--input-bg, var(--color-contrast-100));\n --_border-color: var(--input-border-color, var(--color-contrast-300));\n\n display: inline-flex;\n flex-direction: column;\n align-items: stretch;\n }\n\n .input-wrapper {\n display: flex;\n flex-direction: column;\n gap: 0;\n width: 100%;\n }\n\n .field {\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: 0;\n align-items: stretch;\n justify-content: center;\n height: var(--_field-height);\n min-height: var(--_field-height);\n padding: var(--_padding);\n background: var(--_bg);\n border: var(--border) solid var(--_border-color);\n border-radius: var(--_radius);\n box-shadow: var(--_shadow, var(--shadow-2xs));\n transition: var(\n --_motion-transition,\n background var(--transition-fast),\n backdrop-filter var(--transition-fast),\n border-color var(--transition-fast),\n box-shadow var(--transition-fast)\n );\n }\n\n /* Expand height to fit inset label + input row */\n .input-wrapper:has(.label:not([hidden])) .field {\n height: auto;\n }\n\n /* Outside placement: label is above the field (natural flow) */\n\n /* Inset placement (default): label appears inside the field border */\n :host(:not([label-placement='outside'])) .input-wrapper {\n position: relative;\n }\n\n :host(:not([label-placement='outside'])) .label {\n position: absolute;\n inset-block-start: var(--size-2);\n inset-inline-start: var(--_padding-x, var(--size-3));\n z-index: 1;\n pointer-events: none;\n }\n\n :host(:not([label-placement='outside'])) .input-wrapper:has(.label:not([hidden])) .field {\n padding-block-start: calc(var(--size-2) + 1lh + 2px);\n }\n\n .input-row {\n display: flex;\n flex: 1;\n gap: var(--_gap);\n align-items: center;\n }\n\n /* ========================================\n Label Styles\n ======================================== */\n\n .label,\n label.label {\n margin-bottom: 2px;\n overflow: hidden;\n text-overflow: ellipsis;\n font-size: var(--text-xs);\n font-weight: var(--font-medium);\n line-height: var(--leading-tight);\n color: var(--color-contrast-500);\n white-space: nowrap;\n cursor: pointer;\n user-select: none;\n transition: var(--_motion-transition, color var(--transition-fast));\n }\n\n /* Outside placement: label moves outside the field via CSS */\n :host([label-placement='outside']) .label,\n :host([label-placement='outside']) label.label {\n order: -1;\n margin-bottom: 0;\n font-size: var(--text-sm);\n line-height: var(--leading-none);\n }\n\n /* ========================================\n Helper Text\n ======================================== */\n\n .helper-text {\n padding-inline: 2px;\n margin-top: var(--size-1-5);\n font-size: var(--text-xs);\n line-height: var(--leading-tight);\n color: var(--color-contrast-500);\n overflow-wrap: anywhere;\n }\n\n .helper-text[hidden] {\n display: none;\n }\n\n /* ========================================\n Slotted Prefix/Suffix Icons\n ======================================== */\n\n ::slotted(svg) {\n flex-shrink: 0;\n width: var(--_icon-size, var(--leading-6));\n height: var(--_icon-size, var(--leading-6));\n }\n}\n\n@layer refine.overrides {\n /* ========================================\n Input Element\n ======================================== */\n\n input {\n flex: 1;\n min-width: 0;\n font: inherit;\n font-size: var(--_font-size);\n line-height: var(--leading-normal);\n\n /* No all: unset needed - reset layer handles it */\n color: var(--color-contrast-900);\n outline: none;\n background: transparent;\n border: none;\n }\n\n input::placeholder {\n color: var(--_placeholder);\n transition: color var(--transition-fast);\n }\n\n input:focus-visible {\n outline: none;\n }\n\n /* ========================================\n Hover & Focus States\n ======================================== */\n\n :host(:not([disabled], [variant='bordered'], [variant='flat'])) .field:hover {\n border-color: var(--color-contrast-400);\n }\n\n :host(:not([disabled], [variant='text'], [variant='flat'])) .field:focus-within {\n background: var(--color-canvas);\n border-color: var(--_theme-focus);\n box-shadow: var(--_theme-shadow, var(--color-primary-focus-shadow));\n }\n\n :host(:not([disabled])) .field:focus-within .label {\n color: var(--_theme-focus);\n }\n\n :host(:not([disabled])) .field:focus-within ::slotted([slot='prefix']),\n :host(:not([disabled])) .field:focus-within ::slotted([slot='suffix']) {\n color: var(--_theme-focus);\n }\n\n /* ========================================\n Clear button\n ======================================== */\n\n .clear-btn {\n display: none;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n width: var(--size-5);\n min-width: var(--_touch-target);\n height: var(--size-5);\n min-height: var(--_touch-target);\n padding: 0;\n color: var(--color-contrast-500);\n cursor: pointer;\n background: transparent;\n border: none;\n border-radius: var(--rounded-sm);\n transition: var(--_motion-transition, color var(--transition-fast));\n }\n\n .clear-btn:hover {\n color: var(--color-contrast-900);\n }\n\n .clear-btn:focus-visible {\n outline: var(--border-2) solid var(--_theme-focus);\n outline-offset: var(--border);\n }\n\n :host([clearable]) .clear-btn {\n display: flex;\n }\n\n :host([clearable]:not([has-value])) .clear-btn {\n visibility: hidden;\n pointer-events: none;\n }\n\n /* ========================================\n Password visibility toggle\n ======================================== */\n\n .pwd-toggle-btn {\n display: none;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n width: var(--size-5);\n min-width: var(--_touch-target);\n height: var(--size-5);\n min-height: var(--_touch-target);\n padding: 0;\n color: var(--color-contrast-500);\n cursor: pointer;\n background: transparent;\n border: none;\n border-radius: var(--rounded-sm);\n transition: var(--_motion-transition, color var(--transition-fast));\n }\n\n .pwd-toggle-btn:hover {\n color: var(--color-contrast-900);\n }\n\n .pwd-toggle-btn:focus-visible {\n outline: var(--border-2) solid var(--_theme-focus);\n outline-offset: var(--border);\n }\n\n :host([type='password']) .pwd-toggle-btn {\n display: flex;\n }\n\n /* ========================================\n Character counter\n ======================================== */\n\n .char-counter {\n padding-inline: 2px;\n font-size: var(--text-xs);\n line-height: var(--leading-tight);\n color: var(--color-contrast-400);\n text-align: end;\n white-space: nowrap;\n }\n\n .char-counter[data-near-limit] {\n color: var(--color-warning, #f59e0b);\n }\n\n .char-counter[data-at-limit] {\n color: var(--color-error);\n }\n\n /* ========================================\n Error State\n ======================================== */\n\n :host([error]:not([error=''])) .field {\n border-color: var(--color-error);\n }\n\n :host([error]:not([error=''])) .field:focus-within {\n border-color: var(--color-error);\n box-shadow: var(--color-error-focus-shadow);\n }\n\n :host([error]:not([error=''])) .label-inset,\n :host([error]:not([error=''])) .label-outside {\n color: var(--color-error);\n }\n\n .helper-text[role='alert'] {\n color: var(--color-error);\n }\n}\n\n@layer refine.variants {\n /* ========================================\n Visual Variants\n ======================================== */\n\n /* Solid (Default) */\n :host(:not([variant])),\n :host([variant='solid']) {\n --_bg: var(--input-bg, var(--color-contrast-50));\n --_border-color: var(--input-border-color, var(--color-contrast-300));\n }\n\n :host(:not([variant])) .field,\n :host([variant='solid']) .field {\n box-shadow: var(--shadow-2xs);\n }\n\n :host(:not([variant], [disabled])) .field:focus-within,\n :host([variant='solid']:not([disabled])) .field:focus-within {\n box-shadow: var(--_theme-shadow);\n }\n\n /* Flat */\n :host([variant='flat']) {\n --_bg: var(--input-bg, var(--color-contrast-100));\n --_border-color: var(--input-border-color, var(--_theme-border));\n }\n\n :host([variant='flat']) .field {\n box-shadow: var(--inset-shadow-2xs);\n }\n\n :host([variant='flat']) .field:hover {\n background: var(--input-hover-bg, color-mix(in oklch, var(--_theme-base) 6%, var(--color-contrast-100)));\n border-color: var(\n --input-hover-border-color,\n color-mix(in oklch, var(--_theme-base) 35%, var(--color-contrast-300))\n );\n }\n\n :host([variant='flat']) .field:focus-within {\n background: var(--input-focus-bg, color-mix(in oklch, var(--_theme-base) 8%, var(--color-canvas)));\n border-color: var(--input-focus-border-color, color-mix(in oklch, var(--_theme-focus) 60%, transparent));\n box-shadow: var(--_theme-shadow);\n }\n\n /* Bordered */\n :host([variant='bordered']) {\n --_bg: var(--input-bg, var(--_theme-backdrop));\n --_border-color: var(--input-border-color, color-mix(in oklch, var(--_theme-focus) 70%, transparent));\n }\n\n :host([variant='bordered']) .field:hover {\n border-color: var(--input-hover-border-color, var(--_theme-focus));\n }\n\n /* Outline */\n :host([variant='outline']) {\n --_bg: var(--input-bg, transparent);\n }\n\n :host([variant='outline']) .field {\n box-shadow: none;\n }\n\n :host([variant='outline']:not([disabled])) .field:focus-within {\n box-shadow: var(--_theme-shadow);\n }\n\n /* Ghost */\n :host([variant='ghost']) {\n --_bg: var(--input-bg, transparent);\n --_border-color: var(--input-border-color, transparent);\n }\n\n :host([variant='ghost']) .field {\n box-shadow: none;\n }\n\n :host([variant='ghost']) .field:hover {\n background: var(--input-hover-bg, var(--color-contrast-100));\n }\n\n :host([variant='ghost']:not([disabled])) .field:focus-within {\n box-shadow: var(--_theme-shadow);\n }\n\n /* Text — underline style */\n :host([variant='text']) {\n --_bg: var(--input-bg, transparent);\n --_border-color: var(--input-border-color, var(--color-contrast-300));\n }\n\n :host([variant='text']) .field {\n border: none;\n border-bottom: var(--border) solid var(--_border-color);\n border-radius: 0;\n box-shadow: none;\n }\n\n :host([variant='text']) .field:focus-within {\n border-bottom: var(--border-2) solid var(--input-focus-border-color, var(--_theme-focus));\n }\n}\n\n@layer refine.utilities {\n /* Full width */\n :host([fullwidth]) {\n width: 100%;\n }\n}\n","import { define, useField, html, inject, prop, ref } from '@vielzeug/ore';\nimport { live } from '@vielzeug/ore/directives';\nimport { computed, signal, watch } from '@vielzeug/ripple';\n\nimport type { TextFieldProps } from '../../shared';\nimport type { InputType, VisualVariant } from '../../types';\n\nimport { lifecycleSignal, createTextField } from '../../headless';\nimport { disablableBundle, FIELD_SIZE_PRESET, roundableBundle, sizableBundle, themableBundle } from '../../shared';\nimport '../../content/icon/icon';\nimport { fieldMixins, forcedColorsFocusMixin, sizeVariantMixin } from '../../styles';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport componentStyles from './input.css?inline';\n\n/** Input component properties */\n\nexport type OreInputEvents = {\n change: { originalEvent: Event; value: string };\n input: { originalEvent: Event; value: string };\n};\n\nexport type OreInputProps = TextFieldProps<Exclude<VisualVariant, 'frost'>> & {\n /** Autocomplete hint */\n autocomplete?: string;\n /** Show a clear (×) button when the field has a value */\n clearable?: boolean;\n /** Virtual keyboard hint for mobile devices */\n inputmode?: 'none' | 'text' | 'decimal' | 'numeric' | 'tel' | 'search' | 'email' | 'url';\n /** Maximum character length — shows a counter below the input */\n maxlength?: number;\n /** Minimum character length */\n minlength?: number;\n /** HTML pattern attribute for client-side validation */\n pattern?: string;\n /**\n * JS-only callback fired with the inner `<input>` element when it mounts,\n * and with `null` when it unmounts. Intended for composed components that\n * need imperative access to the raw input element.\n * Set as a JS property: `bitInput.ref = (el) => { ... }`.\n */\n ref?: ((el: HTMLInputElement | null) => void) | null;\n /** HTML input type */\n type?: InputType;\n};\n\nconst VALID_INPUT_TYPES = [\n 'text',\n 'email',\n 'password',\n 'search',\n 'url',\n 'tel',\n 'number',\n 'date',\n 'time',\n 'datetime-local',\n 'month',\n 'week',\n] as const;\n\n/**\n * A customizable text input component with multiple variants, label placements, and form features.\n *\n * @element ore-input\n *\n * @attr {string} label - Label text\n * @attr {string} label-placement - Label placement: 'inset' | 'outside'\n * @attr {string} type - HTML input type: 'text' | 'email' | 'password' | 'number' | 'tel' | 'url' | 'search'\n * @attr {string} value - Current input value\n * @attr {string} placeholder - Placeholder text\n * @attr {string} name - Form field name\n * @attr {string} helper - Helper text displayed below the input (fallback when the `helper` slot is empty)\n * @attr {string} error - Error message — marks the field as invalid (fallback when the `error` slot is empty)\n * @attr {boolean} disabled - Disable input interaction\n * @attr {boolean} readonly - Make the input read-only\n * @attr {boolean} required - Mark the field as required\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'outline' | 'ghost' | 'text'\n * @attr {string} size - Input size: 'sm' | 'md' | 'lg'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n *\n * @fires input - Emitted when input value changes (on every keystroke). detail: { value: string; originalEvent: Event }\n * @fires change - Emitted when input loses focus with changed value. detail: { value: string; originalEvent: Event }\n *\n * @slot prefix - Content before the input (e.g., icons)\n * @slot suffix - Content after the input (e.g., clear button, validation icon)\n * @slot label - Replaces the label text — slotted content takes precedence over the `label` prop\n * @slot helper - Replaces the helper text — slotted content takes precedence over the `helper` prop\n * @slot error - Replaces the error text — slotted content takes precedence over the `error` prop\n *\n * @part wrapper - The input wrapper element\n * @part label - The label element (inset or outside)\n * @part field - The field container element\n * @part input-row - The input row container element\n * @part input - The input element\n * @part helper - The helper text element\n *\n * @cssprop --input-bg - Background color\n * @cssprop --input-color - Text color\n * @cssprop --input-border-color - Border color\n * @cssprop --input-placeholder-color - Placeholder text color\n * @cssprop --input-radius - Border radius\n * @cssprop --input-padding - Inner padding (block inline)\n * @cssprop --input-gap - Gap between prefix/suffix icons and input text\n * @cssprop --input-font-size - Font size\n * @cssprop --input-height - Field height\n * @cssprop --input-hover-bg - Field background on hover (flat/ghost variants)\n * @cssprop --input-hover-border-color - Field border on hover (flat/bordered variants)\n * @cssprop --input-focus-bg - Field background when focused (flat variant)\n * @cssprop --input-focus-border-color - Field border when focused (flat/text variants)\n *\n * @example\n * ```html\n * <ore-input type=\"email\" label=\"Email\" placeholder=\"you@example.com\" />\n * <ore-input label=\"Name\" variant=\"bordered\" color=\"primary\" />\n * ```\n */\nexport const INPUT_TAG = 'ore-input' as const;\ndefine<OreInputProps, OreInputEvents>(INPUT_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n ...roundableBundle,\n autocomplete: prop.string(),\n clearable: prop.bool(false),\n error: prop.string(),\n fullwidth: prop.bool(false),\n helper: prop.string(),\n inputmode: prop.string<'none' | 'text' | 'decimal' | 'numeric' | 'tel' | 'search' | 'email' | 'url'>(),\n label: prop.string(),\n 'label-placement': prop.oneOf(['inset', 'outside'] as const, 'inset'),\n maxlength: prop.json(undefined as number | undefined),\n minlength: prop.json(undefined as number | undefined),\n name: prop.string(),\n pattern: prop.string(),\n placeholder: prop.string(),\n readonly: prop.bool(false),\n ref: prop.json(undefined as ((el: HTMLInputElement | null) => void) | null | undefined),\n required: prop.bool(false),\n type: prop.oneOf(VALID_INPUT_TYPES, 'text'),\n value: prop.string(),\n variant: prop.string<'flat' | 'text' | 'solid' | 'bordered' | 'outline' | 'ghost'>(),\n },\n setup(props, { bind, emit, onCleanup, onElement, slots }) {\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(bind, props, formCtx);\n const showPassword = signal(false);\n const inputRef = ref<HTMLInputElement>();\n\n const hasLabel = computed(() => !!props.label.value || slots.has('label').value);\n\n const abortSignal = lifecycleSignal(onCleanup);\n let _formField: { reportValidity(): void } | null = null;\n const tf = createTextField({\n disabled: fCtxProps.disabled,\n error: props.error,\n getFormField: () => _formField,\n hasLabel,\n helper: props.helper,\n label: props.label,\n labelPlacement: props['label-placement'],\n maxLength: props.maxlength,\n onChange: (event: Event, value: string) => {\n emit('change', { originalEvent: event, value });\n },\n onInput: (event: Event, value: string) => {\n emit('input', { originalEvent: event, value });\n },\n prefix: 'input',\n signal: abortSignal,\n validateOn: formCtx?.validateOn,\n value: props.value,\n });\n\n _formField = useField<string>({ disabled: tf.disabled, toFormValue: (v) => v, value: tf.value });\n\n const {\n ariaDescribedBy,\n ariaErrorMessage,\n ariaInvalid,\n ariaLabelledBy,\n assistiveId,\n clear: clearValue,\n counter,\n errorId,\n errorText,\n fieldId: inputId,\n helperText,\n labelId,\n labelVisible,\n value: fieldValue,\n wire,\n } = tf;\n\n onElement(inputRef, (el) => {\n wire(el, abortSignal);\n\n // Immediate fire for when the prop is already set on mount.\n props.ref.value?.(el);\n\n // Reactive watcher so that if props.ref is set *after* the inner\n // <input> mounts (e.g. parent sets it via a ref callback after render),\n // the new callback still receives the live element.\n const sub = watch(props.ref, (cb) => {\n cb?.(el);\n });\n\n return () => {\n sub.dispose();\n props.ref.value?.(null);\n };\n });\n\n const clear = (event?: Event): void => {\n clearValue(event);\n inputRef.value?.focus();\n };\n\n const resolvedInputType = (): string =>\n props.type.value === 'password' && showPassword.value ? 'text' : (props.type.value ?? 'text');\n\n bind({\n attr: {\n error: () => errorText.value || undefined,\n 'has-value': () => (fieldValue.value ? true : undefined),\n size: fCtxProps.size,\n variant: fCtxProps.variant,\n },\n });\n\n const labelHidden = () => !labelVisible.value;\n const passwordToggleLabel = () => (showPassword.value ? 'Hide password' : 'Show password');\n const passwordTogglePressed = () => String(showPassword.value);\n const passwordToggleIcon = () =>\n showPassword.value\n ? html`<ore-icon name=\"eye-off\" size=\"14\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>`\n : html`<ore-icon name=\"eye\" size=\"14\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>`;\n const helperHidden = () => !!errorText.value || !helperText.value;\n const errorHidden = () => !errorText.value;\n const counterNearLimit = () => (counter?.value.counterNearLimit && !counter?.value.counterAtLimit ? '' : null);\n const counterAtLimit = () => (counter?.value.counterAtLimit ? '' : null);\n const counterHidden = () => !counter;\n const counterText = () => counter?.value.counterText ?? '';\n\n const clearTabIndex = () => (fieldValue.value ? '0' : '-1');\n const pwdToggleTabIndex = () => (props.type.value === 'password' ? '0' : '-1');\n\n const togglePassword = () => {\n showPassword.value = !showPassword.value;\n inputRef.value?.focus();\n };\n\n return html`\n <div class=\"input-wrapper\" part=\"wrapper\">\n <label class=\"label\" for=\"${inputId}\" id=\"${labelId}\" part=\"label\" ?hidden=\"${labelHidden}\"\n ><slot name=\"label\">${props.label}</slot></label\n >\n <div class=\"field\" part=\"field\">\n <div class=\"input-row\" part=\"input-row\">\n <slot name=\"prefix\"></slot>\n <input\n part=\"input\"\n id=\"${inputId}\"\n :type=\"${resolvedInputType}\"\n :name=\"${props.name}\"\n :placeholder=\"${props.placeholder}\"\n :autocomplete=\"${props.autocomplete}\"\n :inputmode=\"${props.inputmode}\"\n :maxlength=\"${props.maxlength}\"\n :minlength=\"${props.minlength}\"\n :pattern=\"${props.pattern}\"\n ?disabled=\"${props.disabled}\"\n ?readonly=\"${props.readonly}\"\n ?required=\"${props.required}\"\n :value=\"${live(fieldValue)}\"\n :aria-labelledby=\"${ariaLabelledBy}\"\n :aria-describedby=\"${ariaDescribedBy}\"\n :aria-errormessage=\"${ariaErrorMessage}\"\n :aria-invalid=\"${ariaInvalid}\"\n ref=\"${inputRef}\" />\n <slot name=\"suffix\"></slot>\n <button\n class=\"pwd-toggle-btn\"\n part=\"pwd-toggle\"\n type=\"button\"\n :aria-label=\"${passwordToggleLabel}\"\n :aria-pressed=\"${passwordTogglePressed}\"\n :tabindex=\"${pwdToggleTabIndex}\"\n @click=\"${togglePassword}\">\n ${passwordToggleIcon}\n </button>\n <button\n aria-label=\"Clear\"\n class=\"clear-btn\"\n part=\"clear\"\n type=\"button\"\n :tabindex=\"${clearTabIndex}\"\n @click=\"${clear}\">\n <ore-icon aria-hidden=\"true\" name=\"x\" size=\"12\" stroke-width=\"2.5\"></ore-icon>\n </button>\n </div>\n </div>\n <div class=\"helper-text\" aria-live=\"polite\" id=\"${assistiveId}\" part=\"helper\" ?hidden=\"${helperHidden}\">\n <slot name=\"helper\">${() => helperText.value}</slot>\n </div>\n <div class=\"helper-text\" id=\"${errorId}\" role=\"alert\" part=\"error\" ?hidden=\"${errorHidden}\">\n <slot name=\"error\">${() => errorText.value}</slot>\n </div>\n <div\n class=\"char-counter\"\n part=\"char-counter\"\n :data-near-limit=\"${counterNearLimit}\"\n :data-at-limit=\"${counterAtLimit}\"\n ?hidden=\"${counterHidden}\">\n ${counterText}\n </div>\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [...fieldMixins, sizeVariantMixin(FIELD_SIZE_PRESET), forcedColorsFocusMixin('input'), componentStyles],\n});\n","@layer refine.base {\n :host {\n --_dropdown-bg: var(--combobox-dropdown-bg, var(--color-canvas));\n --_dropdown-border-color: var(--combobox-dropdown-border-color, var(--color-contrast-200));\n --_option-hover-bg: var(--combobox-option-hover-bg, var(--color-contrast-100));\n --_option-focus-bg: var(\n --combobox-option-focus-bg,\n color-mix(in oklch, var(--_theme-base) 12%, var(--color-contrast-100))\n );\n --_option-selected-bg: var(\n --combobox-option-selected-bg,\n color-mix(in oklch, var(--_theme-base) 10%, var(--color-contrast-50))\n );\n --_option-selected-focus-bg: var(\n --combobox-option-selected-focus-bg,\n color-mix(in oklch, var(--_theme-base) 20%, var(--color-contrast-100))\n );\n\n display: inline-flex;\n flex-direction: column;\n align-items: stretch;\n min-width: 12rem;\n }\n\n :host([fullwidth]) {\n display: block;\n width: 100%;\n }\n\n /* .sr-only is provided by the shared srOnlyMixin (see styles: [...] in combobox.ts) */\n\n /* ore-input cursor override so the field still feels like a text input */\n .trigger::part(input) {\n cursor: text;\n }\n\n /* Allow the field to grow vertically when chips wrap to multiple rows. */\n .trigger::part(field) {\n height: auto;\n min-height: var(--input-height, var(--size-10));\n }\n\n /* Wrap chips + input across rows; suffix stays on same row as input.\n Only row-gap is set here — column spacing between chips is handled\n via margin on ore-chip so the empty prefix slot adds no extra offset\n (which would shift the input rightward vs the inset label). */\n .trigger::part(input-row) {\n flex-wrap: wrap;\n row-gap: var(--size-1);\n align-items: center;\n }\n\n /* ========================================\n Chips (prefix slot)\n ======================================== */\n\n /* display:contents removes chips-row from the flex layout so chips\n become direct flex items of input-row — no extra gap before input\n when there are no chips (fixes inset-label alignment). */\n .chips-row {\n display: contents;\n }\n\n /* chips-list is also display:contents so individual ore-chip elements\n are the direct flex items, wrapping inline with the search input. */\n .chips-list {\n display: contents;\n }\n\n /* Trailing space after each chip covers both inter-chip spacing and\n the gap between the last chip and the search input. */\n ore-chip {\n margin-inline-end: var(--size-1);\n }\n\n /* ========================================\n Suffix: clear button + loader + chevron\n ======================================== */\n\n .combobox-suffix {\n display: flex;\n flex-shrink: 0;\n gap: var(--size-1);\n align-items: center;\n }\n\n .clear-btn {\n display: inline-flex;\n flex-shrink: 0;\n align-items: center;\n padding: 0;\n color: var(--color-contrast-400);\n cursor: pointer;\n background: none;\n border: 0;\n }\n\n .clear-btn[hidden] {\n display: none;\n }\n\n .clear-btn:hover {\n color: var(--color-contrast-600);\n }\n\n .combobox-suffix-end {\n display: flex;\n gap: var(--size-1);\n align-items: center;\n color: var(--color-contrast-500);\n }\n\n .chevron {\n display: inline-flex;\n flex-shrink: 0;\n align-items: center;\n transition: var(--_motion-transition, transform var(--transition-fast));\n }\n\n :host([open]) .chevron {\n transform: rotate(180deg);\n }\n\n .loader {\n display: none;\n flex-shrink: 0;\n width: 1em;\n height: 1em;\n border: 2px solid currentcolor;\n border-inline-end-color: transparent;\n border-radius: 50%;\n animation: var(--_motion-animation, spin var(--transition-loader) infinite);\n }\n\n /* Keyframe must live in shadow DOM — @keyframes don't inherit across shadow roots */\n @keyframes spin {\n to {\n transform: rotate(360deg);\n }\n }\n\n :host([loading]) .loader {\n display: inline-block;\n }\n\n /* ========================================\n Dropdown / Listbox\n ======================================== */\n\n .dropdown {\n position: fixed;\n inset: 0 auto auto 0;\n z-index: calc(var(--z-popover, 1000) + 1);\n box-sizing: border-box;\n max-height: min(16rem, 50dvh);\n padding: var(--size-1);\n margin: 0;\n overflow-y: auto;\n overscroll-behavior: contain;\n text-align: start;\n pointer-events: none;\n scrollbar-width: thin;\n background: var(--_dropdown-bg);\n border: var(--border) solid var(--_dropdown-border-color);\n border-radius: var(--_radius);\n box-shadow: var(--shadow-lg);\n opacity: 0;\n backdrop-filter: blur(var(--blur-md));\n transform: translateY(var(--overlay-enter-translate-y));\n transition: var(\n --_motion-transition,\n opacity var(--transition-fast),\n transform var(--transition-fast),\n display var(--transition-fast) allow-discrete\n );\n }\n\n .dropdown[data-open] {\n pointer-events: auto;\n opacity: 1;\n transform: translateY(0);\n\n @starting-style {\n opacity: 0;\n transform: translateY(var(--overlay-enter-translate-y));\n }\n }\n\n /* ========================================\n Option Items\n ======================================== */\n\n .option {\n display: flex;\n gap: var(--size-2);\n align-items: center;\n padding: var(--size-1-5) var(--size-2-5);\n font-size: var(--text-sm);\n line-height: var(--leading-normal);\n cursor: pointer;\n border-radius: var(--rounded-sm);\n transition:\n background var(--transition-fast),\n color var(--transition-fast);\n }\n\n /* Truncate long labels so options always stay single-line (fixed virtualizer row height). */\n .option > span:not(.option-check, .option-icon) {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .option:hover:not([data-disabled]) {\n background: var(--_option-hover-bg);\n }\n\n .option[data-focused]:not([data-disabled]) {\n color: var(--_theme-base);\n background: var(--_option-focus-bg);\n }\n\n .option[data-selected],\n .option[aria-selected='true'] {\n font-weight: var(--font-medium);\n color: var(--_theme-base);\n background: var(--_option-selected-bg);\n }\n\n .option[data-selected][data-focused],\n .option[aria-selected='true'][data-focused] {\n background: var(--_option-selected-focus-bg);\n }\n\n .option[data-disabled] {\n color: var(--color-contrast-400);\n cursor: not-allowed;\n opacity: 0.6;\n }\n\n .option-check {\n display: inline-flex;\n flex-shrink: 0;\n margin-inline-start: auto;\n color: var(--_theme-base);\n opacity: 0;\n transition: opacity var(--transition-fast);\n }\n\n .option[data-selected] .option-check,\n .option[aria-selected='true'] .option-check {\n opacity: 1;\n }\n\n .no-results,\n .no-results-create,\n .dropdown-loading {\n padding: var(--size-3) var(--size-2-5);\n font-size: var(--text-sm);\n color: var(--color-contrast-400);\n text-align: center;\n }\n\n .no-results-create {\n display: flex;\n gap: var(--size-1-5);\n align-items: center;\n width: 100%;\n padding: var(--size-1-5) var(--size-2-5);\n font-size: var(--text-sm);\n color: var(--_theme-content, var(--color-primary-content));\n text-align: start;\n cursor: pointer;\n background: none;\n border: 0;\n border-radius: var(--rounded-sm);\n }\n\n .no-results-create:hover,\n .no-results-create[data-focused] {\n background: color-mix(in oklch, var(--_theme-base, var(--color-primary)) 10%, transparent);\n }\n\n /* ========================================\n Option Icon\n ======================================== */\n\n .option-icon {\n display: inline-flex;\n flex-shrink: 0;\n align-items: center;\n }\n\n /* ========================================\n Slotted option elements (hidden data nodes)\n ======================================== */\n\n ::slotted(ore-combobox-option) {\n display: none;\n }\n}\n","import { define, useField, html, inject, prop, ref } from '@vielzeug/ore';\nimport { computed, signal } from '@vielzeug/ripple';\n\nimport type { AddEventListeners, ComponentSize, RoundedSize, ThemeColor } from '../../types';\nimport type { OreComboboxEvents, OreComboboxProps, ComboboxOptionInput, ComboboxOptionItem } from './combobox.types';\n\nimport {\n lifecycleSignal,\n createChoiceField,\n createInteraction,\n createOptionList,\n type DialogCloseReason,\n type OverlayOpenReason,\n} from '../../headless';\nimport { reducedMotionMixin, srOnlyMixin } from '../../styles';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport { filterOptions, getCreatableLabel, makeCreatableValue, parseSlottedOptions } from './combobox-options';\nimport '../../feedback/chip/chip';\nimport '../input/input';\nimport componentStyles from './combobox.css?inline';\n\nexport type { OreComboboxEvents, OreComboboxProps } from './combobox.types';\n\n/**\n * A searchable select field with multiple selection, custom option creation, and large-list support.\n *\n * @element ore-combobox\n *\n * @attr {string} value - Selected value(s). Use comma-separated for multiple.\n * @attr {boolean} multiple - Enable multiple selection\n * @attr {boolean} creatable - Allow users to create custom options from search query\n * @attr {boolean} no-filter - Disable client-side filtering (useful for server-side search)\n * @attr {string} placeholder - Placeholder text\n *\n * @fires {CustomEvent} change - Emitted when selection changes. detail: { value: string | string[], values: string[], labels: string[] }\n * @fires {CustomEvent} search - Emitted when user types. detail: { query: string }\n *\n * @slot - Slotted combobox options and option groups\n * @cssprop --combobox-dropdown-bg - Dropdown panel background color\n * @cssprop --combobox-dropdown-border-color - Dropdown panel border color\n * @cssprop --combobox-option-hover-bg - Option background on hover\n * @cssprop --combobox-option-focus-bg - Option background when keyboard-focused\n * @cssprop --combobox-option-selected-bg - Option background when selected\n * @cssprop --combobox-option-selected-focus-bg - Option background when selected and focused\n * @cssprop --input-bg - Field background (passed through to ore-input)\n * @cssprop --input-border-color - Field border color (passed through to ore-input)\n *\n * @part wrapper - Root wrapper around the entire field\n * @part label - Label element shown inside or outside the field\n * @part field - Field container that holds the trigger input and clear button\n * @part input - Search input used to filter and select options\n * @part clear-btn - Button that clears the current selection/query\n * @part dropdown - Popup list container for options\n * @part helper-text - Helper text displayed below the field\n * @example\n * ```html\n * <ore-combobox label=\"Country\" name=\"country\">\n * <ore-combobox-option value=\"us\">United States</ore-combobox-option>\n * <ore-combobox-option value=\"gb\">United Kingdom</ore-combobox-option>\n * <ore-combobox-option value=\"de\" disabled>Germany</ore-combobox-option>\n * </ore-combobox>\n * ```\n */\nexport const COMBOBOX_TAG = 'ore-combobox' as const;\ndefine<OreComboboxProps, OreComboboxEvents>(COMBOBOX_TAG, {\n formAssociated: true,\n props: {\n autoclose: prop.bool(false),\n color: prop.string<ThemeColor>(),\n creatable: prop.bool(false),\n disabled: prop.bool(false),\n error: prop.string(),\n fullwidth: prop.bool(false),\n helper: prop.string(),\n label: prop.string(),\n 'label-placement': prop.oneOf(['inset', 'outside'] as const, 'inset'),\n loading: prop.bool(false),\n multiple: prop.bool(false),\n name: prop.string(),\n 'no-filter': prop.bool(false),\n options: prop.data<ComboboxOptionInput[]>(),\n placeholder: prop.string('Select...'),\n rounded: prop.string<RoundedSize>(),\n size: prop.string<ComponentSize>(),\n value: prop.string(),\n variant: prop.string<'flat' | 'solid' | 'bordered' | 'outline' | 'ghost'>(),\n },\n setup(props, { bind, el, emit, onCleanup, onElement, watch }) {\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(bind, props, formCtx);\n const query = signal('');\n\n // Element refs needed by the composite option-list factory.\n let inputEl: HTMLInputElement | null = null;\n let fieldEl: HTMLElement | null = null; // set to the ore-input host once it mounts\n let dropdownEl: HTMLElement | null = null;\n let listboxEl: HTMLElement | null = null;\n\n // Ref to the ore-input host; resolved when the template renders.\n const bitInputRef = ref<HTMLElement>();\n\n const abortSignal = lifecycleSignal(onCleanup);\n let _formField: { reportValidity(): void } | null = null;\n const choice = createChoiceField({\n disabled: fCtxProps.disabled,\n error: props.error,\n getFormField: () => _formField,\n helper: props.helper,\n label: props.label,\n labelPlacement: props['label-placement'],\n multiple: props.multiple,\n prefix: 'combobox',\n signal: abortSignal,\n validateOn: formCtx?.validateOn,\n value: props.value,\n });\n\n // filteredOptions signal declared before optionList so the getItems getter\n // captures the live signal reference rather than needing a factory indirection.\n const filteredOptions = signal<ComboboxOptionItem[]>([]);\n\n const optionList = createOptionList<ComboboxOptionItem>({\n getBoundary: () => el,\n getFocusedOptionElement: () => dropdownEl?.querySelector<HTMLElement>('[data-focused]') ?? null,\n getItems: () => filteredOptions.value,\n getOptionId: (index) => `${choice.fieldId}-opt-${index}`,\n getPanel: () => dropdownEl,\n getReference: () => fieldEl,\n getTrigger: () => inputEl,\n isDisabled: () => choice.disabled.value,\n onClose: (reason) => {\n emit('close', { reason });\n\n if (!abortSignal.aborted) restoreQueryFromSelection();\n\n choice.triggerValidation('blur');\n },\n onOpen: (reason) => emit('open', { reason }),\n restoreFocus: false,\n signal: abortSignal,\n });\n\n const { disabled: isDisabled, fieldId: comboId, selectedValues, triggerValidation } = choice;\n\n _formField = useField<string>({ disabled: choice.disabled, toFormValue: (v) => v, value: choice.formValue });\n\n const { focusedIndex, isOpen, scrollFocusedIntoView, updatePosition } = optionList;\n // ── State ────────────────────────────────────────────────────────────────\n const isMultiple = () => Boolean(props.multiple.value);\n const isCreatable = () => Boolean(props.creatable.value);\n const isNoFilter = () => Boolean(props['no-filter'].value);\n\n bind({\n attr: {\n open: () => (isOpen.value ? true : undefined),\n size: fCtxProps.size,\n variant: fCtxProps.variant,\n },\n });\n\n let lastQueryBeforeClear: string | null = null;\n let isRestoringQuery = false;\n\n // Convenience getter for single-select\n const selectedValue = computed(() => selectedValues.value[0] ?? '');\n\n // Expose .value as a JS property accessor on the host element\n Object.defineProperty(el, 'value', {\n configurable: true,\n get: () => (isMultiple() ? selectedValues.value : selectedValue.value),\n set: (val: unknown) => {\n const v = val as string | string[] | null | undefined;\n\n if (Array.isArray(v)) {\n choice.setValues(v.map((entry) => String(entry ?? '')));\n\n return;\n }\n\n if (v == null || v === '') {\n choice.clear();\n\n return;\n }\n\n choice.setValues([String(v)]);\n },\n });\n\n const hasValue = () => selectedValues.value.length > 0;\n\n function focusLiveInput() {\n inputEl?.focus();\n }\n\n // ── Options ──────────────────────────────────────────────────────────────\n const slottedOptions = signal<ComboboxOptionItem[]>([]);\n const createdOptions = signal<ComboboxOptionItem[]>([]);\n const isLoading = () => Boolean(props.loading.value);\n\n function normalizeOption(option: ComboboxOptionInput): ComboboxOptionItem {\n return {\n disabled: Boolean(option.disabled),\n iconEl: option.iconEl ?? null,\n label: option.label ?? option.value,\n value: option.value,\n };\n }\n\n // Merged options: explicit prop value overrides slotted options.\n const allOptions = computed<ComboboxOptionItem[]>(() => {\n const optionsProp = props.options.value;\n const base = Array.isArray(optionsProp) ? optionsProp.map(normalizeOption) : slottedOptions.value;\n\n if (createdOptions.value.length === 0) return base;\n\n return [...base, ...createdOptions.value];\n });\n\n const selectionController = {\n clear: () => {\n choice.clear();\n },\n remove: (key: string) => {\n choice.removeValue(key);\n },\n select: (key: string) => {\n choice.selectValue(key);\n },\n toggle: (key: string) => {\n choice.toggleValue(key);\n },\n };\n\n function readOptions(elements: Element[] = Array.from(el.children)) {\n slottedOptions.value = parseSlottedOptions(elements);\n\n if (!isMultiple()) {\n const match = allOptions.value.find((option) => option.value === selectedValue.value);\n\n query.value = match?.label ?? selectedValue.value;\n }\n }\n\n // Initialize from light DOM immediately; onMounted/observer keep this in sync afterwards.\n readOptions();\n\n watch(() => {\n const nextOptions = filterOptions(allOptions.value, query.value, isNoFilter());\n\n filteredOptions.value = isMultiple()\n ? nextOptions.filter((option) => !selectedValues.value.includes(option.value))\n : nextOptions;\n });\n\n // \"Create\" option shown when creatable + query doesn't match any existing option\n const creatableLabel = computed(() => {\n return getCreatableLabel(query.value, isCreatable(), filteredOptions.value);\n });\n const inputPlaceholder = () =>\n isMultiple() && selectedValues.value.length > 0 ? '' : props.placeholder.value || '';\n\n const selectedValueItems = computed(() => selectedValues.value);\n const selectedLabelItems = computed(() =>\n selectedValues.value.map((value) => allOptions.value.find((option) => option.value === value)?.label ?? value),\n );\n\n function emitChange(originalEvent?: Event) {\n emit('change', { labels: selectedLabelItems.value, originalEvent, values: selectedValueItems.value });\n }\n\n function removeChip(event: Event): void {\n event.stopPropagation();\n\n const value = (event as CustomEvent<{ value?: string }>).detail?.value;\n\n if (value === undefined) return;\n\n selectionController.remove(value);\n emitChange(event);\n triggerValidation('change');\n }\n\n function restoreQueryFromSelection() {\n // Keep input text and selected value in sync whenever the popup closes.\n if (!isMultiple()) {\n const match = allOptions.value.find((option) => option.value === selectedValue.value);\n\n isRestoringQuery = true;\n query.value = match?.label ?? '';\n Promise.resolve().then(() => {\n isRestoringQuery = false;\n });\n\n return;\n }\n\n query.value = '';\n }\n\n watch(() => {\n if (isOpen.value && !isMultiple() && selectedValue.value && focusedIndex.value === -1 && query.value === '') {\n const selectedIndex = filteredOptions.value.findIndex((option) => option.value === selectedValue.value);\n\n if (selectedIndex >= 0) {\n optionList.set(selectedIndex);\n }\n }\n });\n\n // ── Open / Close ─────────────────────────────────────────────────────────\n function openPopup(clearFilter = true, reason: OverlayOpenReason = 'programmatic') {\n if (clearFilter) {\n lastQueryBeforeClear = query.value;\n query.value = '';\n }\n\n // Pre-compute focused index BEFORE opening so the first render has it set\n if (!isMultiple() && selectedValue.value) {\n const freshOptions = filterOptions(allOptions.value, '', isNoFilter());\n const selectedIndex = freshOptions.findIndex((option) => option.value === selectedValue.value);\n\n if (selectedIndex >= 0) {\n optionList.set(selectedIndex);\n }\n }\n\n optionList.open(reason);\n\n if (!isMultiple() && selectedValue.value && focusedIndex.value >= 0) {\n requestAnimationFrame(() => {\n scrollFocusedIntoView();\n });\n }\n }\n\n function closePopup(reason: DialogCloseReason = 'programmatic') {\n optionList.close(reason);\n }\n\n const fieldPress = createInteraction({\n disabled: isDisabled,\n onPress: () => {\n if (!isOpen.value) openPopup(true, 'click');\n\n focusLiveInput();\n },\n });\n\n const enterPress = createInteraction({\n disabled: isDisabled,\n keys: ['Enter'],\n onPress: (originalEvent: Event) => {\n const opts = filteredOptions.value;\n\n if (isOpen.value && focusedIndex.value >= 0 && focusedIndex.value < opts.length) {\n selectOption(opts[focusedIndex.value], originalEvent);\n } else if (isOpen.value && focusedIndex.value === -1 && creatableLabel.value) {\n // Focused on the \"create\" item\n createOption(query.value, originalEvent);\n } else if (!isOpen.value) {\n openPopup(true, 'keyboard');\n }\n },\n });\n\n // ── Selection ────────────────────────────────────────────────────────────\n function selectOption(opt: ComboboxOptionItem, originalEvent?: Event) {\n if (opt.disabled) return;\n\n if (isMultiple()) {\n selectionController.toggle(opt.value);\n query.value = '';\n emitChange(originalEvent);\n triggerValidation('change');\n\n if (props.autoclose.value) {\n closePopup();\n }\n\n // Keep dropdown open in multiple mode (unless autoclose is true)\n focusLiveInput();\n requestAnimationFrame(() => focusLiveInput());\n } else {\n selectionController.select(opt.value);\n query.value = opt.label;\n emitChange(originalEvent);\n triggerValidation('change');\n closePopup();\n focusLiveInput();\n }\n }\n function resolveOptionFromElement(optionEl: HTMLElement): ComboboxOptionItem | null {\n const indexAttr = optionEl.getAttribute('data-option-index');\n const index = indexAttr ? Number(indexAttr) : -1;\n\n if (Number.isInteger(index) && index >= 0 && index < filteredOptions.value.length) {\n return filteredOptions.value[index] ?? null;\n }\n\n const valueAttr = optionEl.getAttribute('data-option-value');\n\n if (valueAttr) {\n const byValue = filteredOptions.value.find((option) => option.value === valueAttr);\n\n if (byValue) return byValue;\n }\n\n const labelText = optionEl.querySelector('span')?.textContent?.trim() ?? optionEl.textContent?.trim() ?? '';\n\n if (!labelText) return null;\n\n return filteredOptions.value.find((option) => option.label === labelText || option.value === labelText) ?? null;\n }\n function clearValue(e: Event) {\n e.stopPropagation();\n selectionController.clear();\n query.value = '';\n emitChange(e);\n triggerValidation('change');\n focusLiveInput();\n }\n function handleInput(e: InputEvent) {\n const target = e.target as HTMLInputElement;\n const newValue = target.value;\n\n // Skip all input processing if we're in the middle of restoring the query\n // This prevents the clearing logic from firing during close/restore\n if (isRestoringQuery) {\n return;\n }\n\n if (newValue === query.value) return;\n\n query.value = newValue;\n\n if (!isMultiple()) {\n const currentItem = selectedValues.value[0];\n const currentLabel = currentItem\n ? (allOptions.value.find((o) => o.value === currentItem)?.label ?? currentItem)\n : '';\n\n // Preserve the current selection while typing. Selection should only\n // change when a new option is committed or when the user explicitly clears.\n const isJustOpening = newValue === '' && lastQueryBeforeClear === currentLabel;\n\n if (isJustOpening) {\n lastQueryBeforeClear = null;\n }\n }\n\n optionList.navigate('first');\n\n if (!isOpen.value) openPopup(false, 'keyboard');\n\n emit('search', { query: target.value });\n }\n function handleFocus() {\n // Intentionally no-op: open only on explicit click or keyboard.\n // Opening on every focus surprises users tabbing through a form.\n }\n\n // ── Keyboard Navigation ──────────────────────────────────────────────────\n function handleKeydown(e: KeyboardEvent) {\n if (isDisabled.value) return;\n\n if (optionList.handleKeydown(e)) return;\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n\n if (!isOpen.value) {\n openPopup(true, 'keyboard');\n optionList.navigate('first');\n } else {\n optionList.navigate('next');\n }\n\n break;\n case 'ArrowUp':\n e.preventDefault();\n\n if (!isOpen.value) {\n openPopup(true, 'keyboard');\n } else {\n optionList.navigate('prev');\n }\n\n break;\n case 'Backspace':\n // In multiple mode, remove the last chip when the input is empty\n if (isMultiple() && !query.value && selectedValues.value.length > 0) {\n choice.removeValue(selectedValues.value[selectedValues.value.length - 1] ?? '');\n emitChange(e);\n triggerValidation('change');\n }\n\n break;\n case 'Enter':\n enterPress.handleKeydown(e);\n\n break;\n case 'Tab':\n closePopup('programmatic');\n break;\n default:\n break;\n }\n }\n\n // ── Create option ────────────────────────────────────────────────────────\n function createOption(rawQuery: string, originalEvent?: Event) {\n const actualLabel = rawQuery.trim();\n\n if (!actualLabel) return;\n\n const value = makeCreatableValue(actualLabel);\n const newOpt: ComboboxOptionItem = { disabled: false, iconEl: null, label: actualLabel, value };\n\n createdOptions.value = [...createdOptions.value, newOpt];\n selectOption(newOpt, originalEvent);\n }\n // ── Lifecycle ────────────────────────────────────────────────────────────\n\n const observeLightDomOptions = (): (() => void) => {\n const observer = new MutationObserver(() => {\n readOptions();\n });\n\n observer.observe(el, {\n attributeFilter: ['disabled', 'label', 'value'],\n attributes: true,\n childList: true,\n subtree: true,\n });\n\n return () => observer.disconnect();\n };\n\n const stopObserving = observeLightDomOptions();\n\n const handleShadowOptionPointerMove = (event: PointerEvent): void => {\n const target = event.target;\n\n if (!(target instanceof Element)) return;\n\n const optionEl = target.closest<HTMLElement>('.option');\n\n if (!optionEl) return;\n\n const option = resolveOptionFromElement(optionEl);\n\n if (!option || option.disabled) return;\n\n const focusedIdx = filteredOptions.value.findIndex((candidate) => candidate.value === option.value);\n\n if (focusedIdx >= 0) {\n optionList.set(focusedIdx);\n }\n };\n const shadowRoot = el.shadowRoot;\n\n if (shadowRoot) {\n shadowRoot.addEventListener('pointermove', handleShadowOptionPointerMove as EventListener);\n }\n\n const createListboxListeners = (listEl: HTMLElement): (() => void) => {\n const handleActivate = (event: Event) => {\n const target = event.target;\n\n if (!(target instanceof Element)) return;\n\n const createRow = target.closest<HTMLElement>('.no-results-create');\n\n if (createRow) {\n event.preventDefault();\n event.stopPropagation();\n createOption(query.value, event);\n\n return;\n }\n\n const optionEl = target.closest<HTMLElement>('.option');\n\n if (!optionEl) return;\n\n event.preventDefault();\n event.stopPropagation();\n\n const option = resolveOptionFromElement(optionEl);\n\n if (!option) return;\n\n selectOption(option, event);\n };\n\n const handlePointerMove = (event: PointerEvent) => {\n const target = event.target;\n\n if (!(target instanceof Element)) return;\n\n const optionEl = target.closest<HTMLElement>('.option');\n\n if (!optionEl) return;\n\n const option = resolveOptionFromElement(optionEl);\n\n if (!option) return;\n\n const focusedIdx = filteredOptions.value.findIndex((candidate) => candidate.value === option.value);\n\n if (focusedIdx >= 0) {\n optionList.set(focusedIdx);\n }\n };\n\n listEl.addEventListener('click', handleActivate);\n listEl.addEventListener('pointermove', handlePointerMove);\n\n return () => {\n listEl.removeEventListener('click', handleActivate);\n listEl.removeEventListener('pointermove', handlePointerMove);\n };\n };\n\n let stopListboxListeners: (() => void) | null = null;\n let listboxListenersTarget: HTMLElement | null = null;\n\n const setListboxElement = (el: HTMLElement | null): void => {\n listboxEl = el;\n\n if (listboxListenersTarget === el) return;\n\n stopListboxListeners?.();\n stopListboxListeners = null;\n listboxListenersTarget = null;\n\n if (!el) return;\n\n stopListboxListeners = createListboxListeners(el);\n listboxListenersTarget = el;\n };\n\n const ensureListboxListeners = (): void => {\n if (!listboxEl) return;\n\n if (listboxListenersTarget === listboxEl && stopListboxListeners) return;\n\n stopListboxListeners?.();\n stopListboxListeners = createListboxListeners(listboxEl);\n listboxListenersTarget = listboxEl;\n };\n\n watch(() => {\n ensureListboxListeners();\n\n if (isOpen.value) {\n if (dropdownEl && 'showPopover' in dropdownEl && !dropdownEl.matches(':popover-open')) dropdownEl.showPopover();\n\n updatePosition();\n } else {\n if (dropdownEl && 'hidePopover' in dropdownEl && dropdownEl.matches(':popover-open')) dropdownEl.hidePopover();\n }\n });\n\n // Once ore-input is in the DOM, grab its inner <input> from its shadow root\n // and attach all combobox-specific ARIA + event handlers imperatively.\n // MUST be registered before the ARIA effects below so inputEl is set first\n // when bitInputRef fires (effects run in registration order).\n onElement(bitInputRef, (bitInputEl) => {\n fieldEl = bitInputEl;\n\n const rawInput = bitInputEl.shadowRoot?.querySelector<HTMLInputElement>('input') ?? null;\n\n if (!rawInput) return;\n\n inputEl = rawInput;\n\n rawInput.setAttribute('role', 'combobox');\n rawInput.setAttribute('autocomplete', 'off');\n rawInput.setAttribute('aria-autocomplete', 'list');\n rawInput.setAttribute('aria-haspopup', 'listbox');\n rawInput.setAttribute('spellcheck', 'false');\n rawInput.setAttribute('aria-controls', `${comboId}-listbox`);\n\n const handleInputClick = (): void => {\n if (!isOpen.value) openPopup(true, 'click');\n\n focusLiveInput();\n };\n\n rawInput.addEventListener('input', handleInput as EventListener);\n rawInput.addEventListener('keydown', handleKeydown as EventListener);\n rawInput.addEventListener('focus', handleFocus);\n rawInput.addEventListener('click', handleInputClick);\n\n return () => {\n inputEl = null;\n fieldEl = null;\n rawInput.removeEventListener('input', handleInput as EventListener);\n rawInput.removeEventListener('keydown', handleKeydown as EventListener);\n rawInput.removeEventListener('focus', handleFocus);\n rawInput.removeEventListener('click', handleInputClick);\n };\n });\n\n // Reactively sync combobox-specific ARIA attrs that ore-input doesn't manage.\n // Uses bitInputRef (a signal) as the gate so the effect re-runs when the\n // inner input mounts — inputEl is a plain variable and would not trigger re-runs.\n watch(() => {\n if (!bitInputRef.value) return;\n\n const el = inputEl;\n\n if (!el) return;\n\n el.setAttribute('aria-expanded', String(isOpen.value));\n\n if (isDisabled.value) {\n el.setAttribute('aria-disabled', 'true');\n } else {\n el.removeAttribute('aria-disabled');\n }\n\n if (props.error.value) {\n el.setAttribute('aria-invalid', 'true');\n el.setAttribute('aria-errormessage', `${comboId}-error`);\n } else {\n el.removeAttribute('aria-invalid');\n el.removeAttribute('aria-errormessage');\n }\n });\n\n // Reactively sync the query signal into the raw input value.\n watch(() => {\n if (!bitInputRef.value) return;\n\n const el = inputEl;\n\n if (!el) return;\n\n if (el.value !== query.value) el.value = query.value;\n });\n\n onCleanup(() => {\n shadowRoot?.removeEventListener('pointermove', handleShadowOptionPointerMove as EventListener);\n stopListboxListeners?.();\n stopListboxListeners = null;\n listboxListenersTarget = null;\n stopObserving();\n });\n\n const inputColor = () => props.color?.value ?? undefined;\n const inputSize = () => fCtxProps.size?.value ?? undefined;\n const inputVariant = () => fCtxProps.variant?.value ?? undefined;\n const inputRounded = () => props.rounded?.value ?? undefined;\n const inputFullwidth = () => (props.fullwidth.value ? true : undefined);\n\n return html`\n <slot></slot>\n <ore-input\n class=\"trigger\"\n ref=${bitInputRef}\n :label=\"${() => props.label.value ?? ''}\"\n :placeholder=\"${inputPlaceholder}\"\n :label-placement=\"${() => props['label-placement'].value ?? 'inset'}\"\n :color=\"${inputColor}\"\n :size=\"${inputSize}\"\n :variant=\"${inputVariant}\"\n :rounded=\"${inputRounded}\"\n :helper=\"${() => props.helper.value ?? ''}\"\n :error=\"${() => props.error.value ?? ''}\"\n ?disabled=\"${isDisabled}\"\n ?required=\"${() => false}\"\n ?fullwidth=\"${inputFullwidth}\"\n :name=\"${() => props.name.value ?? ''}\"\n @click=\"${(e: MouseEvent) => {\n fieldPress.handleClick(e);\n }}\"\n part=\"wrapper\">\n <div slot=\"prefix\" class=\"chips-row\">\n <!-- Keep chip list diffing isolated so input node identity stays stable. -->\n <span class=\"chips-list\">\n ${() =>\n (isMultiple() ? selectedValues.value : []).map(\n (value) => html`\n <ore-chip\n value=${value}\n label=${allOptions.value.find((option) => option.value === value)?.label ?? value}\n mode=\"removable\"\n variant=\"flat\"\n size=\"sm\"\n color=\"${props.color}\"\n @remove=${removeChip}>\n ${allOptions.value.find((option) => option.value === value)?.label ?? value}\n </ore-chip>\n `,\n )}\n </span>\n </div>\n <span slot=\"suffix\" class=\"combobox-suffix\" aria-hidden=\"true\">\n <button\n class=\"clear-btn\"\n part=\"clear-btn\"\n type=\"button\"\n aria-label=\"Clear\"\n tabindex=\"-1\"\n ?hidden=${() => !hasValue()}\n @click=\"${clearValue}\">\n <ore-icon name=\"x\" size=\"12\" stroke-width=\"2.5\" aria-hidden=\"true\"></ore-icon>\n </button>\n <span class=\"combobox-suffix-end\">\n <span class=\"loader\"></span>\n <span class=\"chevron\">\n <ore-icon name=\"chevron-down\" size=\"14\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </span>\n </span>\n </span>\n </ore-input>\n <span\n class=\"sr-only\"\n id=\"${() => `${comboId}-error`}\"\n role=\"alert\"\n aria-live=\"assertive\"\n ?hidden=\"${() => !props.error.value}\"\n >${() => props.error.value ?? ''}</span\n >\n <div\n class=\"dropdown\"\n part=\"dropdown\"\n id=\"${() => `${comboId}-dropdown`}\"\n popover=\"manual\"\n ?data-open=${() => isOpen.value}\n ref=${(el: HTMLElement | null) => {\n dropdownEl = el;\n }}>\n <div\n role=\"listbox\"\n id=\"${() => `${comboId}-listbox`}\"\n :style=\"${() =>\n isOpen.value && filteredOptions.value.length > 0 ? `height:${filteredOptions.value.length * 36}px;` : ''}\"\n aria-label=\"${() => props.label.value || props.placeholder.value || 'Options'}\"\n ref=${(el: HTMLElement | null) => {\n setListboxElement(el);\n }}>\n ${() => {\n if (!isOpen.value) return '';\n\n if (isLoading()) {\n return html`<div class=\"dropdown-loading\">Loading...</div>`;\n }\n\n if (filteredOptions.value.length === 0) {\n if (creatableLabel.value) {\n return html`<button\n type=\"button\"\n class=\"no-results-create\"\n ?data-focused=${() => focusedIndex.value === -1}>\n ${creatableLabel.value}\n </button>`;\n }\n\n return html`<div class=\"no-results\" role=\"presentation\">No results found</div>`;\n }\n\n return filteredOptions.value.map((option, index) => {\n return html`<div\n class=\"option\"\n role=\"option\"\n id=\"${`${comboId}-opt-${index}`}\"\n data-option-index=\"${index}\"\n data-option-value=\"${option.value}\"\n :aria-selected=\"${() =>\n String(\n isMultiple() ? selectedValues.value.includes(option.value) : selectedValue.value === option.value,\n )}\"\n aria-disabled=\"${String(option.disabled)}\"\n style=\"${`position:absolute;top:0;left:0;right:0;transform:translateY(${index * 36}px);`}\"\n ?data-focused=${() => focusedIndex.value === index}\n ?data-selected=${() =>\n isMultiple() ? selectedValues.value.includes(option.value) : selectedValue.value === option.value}\n ?data-disabled=${option.disabled}>\n <span>${option.label}</span>\n <span class=\"option-check\" aria-hidden=\"true\"\n ><ore-icon name=\"check\" size=\"14\" stroke-width=\"2.5\" aria-hidden=\"true\"></ore-icon\n ></span>\n </div>`;\n });\n }}\n </div>\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [reducedMotionMixin, srOnlyMixin, componentStyles],\n}) as unknown as AddEventListeners<OreComboboxEvents>;\n","@layer refine.base {\n :host {\n display: inline-block;\n min-width: var(--select-min-width, 12rem);\n }\n\n :host([fullwidth]) {\n display: block;\n width: 100%;\n }\n\n /* Hide native <option> elements — we render our own UI */\n ::slotted(option),\n ::slotted(optgroup) {\n display: none;\n }\n\n /* ore-input is readonly so pointer defaults to text — override to pointer */\n .trigger {\n cursor: pointer;\n }\n\n .trigger::part(input) {\n cursor: pointer;\n caret-color: transparent;\n user-select: none;\n }\n\n /* Chips slot inside ore-input prefix */\n .chips-row {\n display: flex;\n flex-wrap: wrap;\n gap: var(--size-1);\n align-items: center;\n min-width: 0;\n }\n\n .chips-row[hidden] {\n display: none;\n }\n\n /* Suffix: loader (left) + chevron (right) */\n .trigger-suffix {\n display: flex;\n gap: var(--size-1);\n align-items: center;\n color: var(--color-contrast-500);\n }\n\n .trigger-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n transition: transform var(--transition-fast);\n }\n\n :host([open]) .trigger-icon {\n transform: rotate(180deg);\n }\n\n .loader {\n display: none;\n flex-shrink: 0;\n width: 1em;\n height: 1em;\n border: 2px solid currentcolor;\n border-inline-end-color: transparent;\n border-radius: 50%;\n animation: var(--_motion-animation, spin var(--transition-loader) infinite);\n }\n\n /* Keyframe must live in shadow DOM — @keyframes don't inherit across shadow roots */\n @keyframes spin {\n to {\n transform: rotate(360deg);\n }\n }\n\n :host([loading]) .loader {\n display: inline-block;\n }\n\n /* ========================================\n Dropdown Listbox\n ======================================== */\n\n .dropdown {\n position: fixed;\n inset: 0 auto auto 0;\n z-index: var(--z-dropdown, 8000);\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: var(--size-0-5);\n max-height: 260px;\n padding: var(--size-1);\n margin: 0;\n overflow-y: auto;\n overscroll-behavior: contain;\n text-align: start;\n pointer-events: none;\n background: var(--color-canvas);\n border: var(--border) solid var(--color-contrast-200);\n border-radius: var(--_radius);\n box-shadow: var(--shadow-lg);\n\n /* Hidden by default */\n opacity: 0;\n backdrop-filter: blur(var(--blur-md));\n transform: translateY(var(--overlay-enter-translate-y));\n transition: var(\n --_motion-transition,\n opacity var(--transition-fast),\n transform var(--transition-fast),\n display var(--transition-fast) allow-discrete\n );\n }\n\n .dropdown[data-open] {\n pointer-events: auto;\n opacity: 1;\n transform: translateY(0);\n\n @starting-style {\n opacity: 0;\n transform: translateY(var(--overlay-enter-translate-y));\n }\n }\n\n .options-list {\n display: flex;\n flex-direction: column;\n gap: 0;\n }\n\n /* ========================================\n Option Items\n ======================================== */\n\n .option {\n display: flex;\n gap: var(--size-2);\n align-items: center;\n padding: var(--size-1-5) var(--size-2-5);\n font-size: var(--text-sm);\n line-height: var(--leading-normal);\n cursor: pointer;\n border-radius: var(--rounded-sm);\n transition:\n background var(--transition-fast),\n color var(--transition-fast);\n }\n\n /* Truncate long labels to keep option rows compact and readable. */\n .option > span:first-child {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .option:hover:not([data-disabled]) {\n background: var(--color-contrast-100);\n }\n\n .option[data-focused]:not([data-disabled]) {\n color: var(--_theme-base);\n background: color-mix(in oklch, var(--_theme-base) 12%, var(--color-contrast-100));\n }\n\n .option[data-selected] {\n font-weight: var(--font-medium);\n color: var(--_theme-base);\n background: color-mix(in oklch, var(--_theme-base) 10%, var(--color-contrast-50));\n }\n\n .option[data-selected][data-focused] {\n background: color-mix(in oklch, var(--_theme-base) 20%, var(--color-contrast-100));\n }\n\n .option[data-disabled] {\n color: var(--color-contrast-400);\n cursor: not-allowed;\n opacity: 0.6;\n }\n\n .option-check {\n display: inline-flex;\n flex-shrink: 0;\n margin-inline-start: auto;\n color: var(--_theme-base);\n opacity: 0;\n transition: opacity var(--transition-fast);\n }\n\n .option[data-selected] .option-check {\n opacity: 1;\n }\n\n /* ========================================\n Option Groups\n ======================================== */\n\n .optgroup-label {\n padding: var(--size-1-5) var(--size-2-5) var(--size-1);\n font-size: var(--text-xs);\n font-weight: var(--font-semibold);\n color: var(--color-contrast-500);\n text-transform: uppercase;\n letter-spacing: var(--tracking-wide, 0.05em);\n }\n\n /* ========================================\n Loading / No-Results\n ======================================== */\n\n .dropdown-loading,\n .dropdown-empty {\n padding: var(--size-3) var(--size-2-5);\n font-size: var(--text-sm);\n color: var(--color-contrast-500);\n text-align: center;\n }\n}\n","import { define, useField, html, inject, prop } from '@vielzeug/ore';\nimport { computed, effect, signal, watch } from '@vielzeug/ripple';\n\nimport type { ChoiceChangeDetail, DropdownCloseReason, OverlayOpenDetail, OverlayOpenReason } from '../../headless';\nimport type { SelectableFieldProps } from '../../shared';\nimport type { VisualVariant } from '../../types';\n\nimport { lifecycleSignal, createChoiceField, createOptionList } from '../../headless';\nimport '../../feedback/chip/chip';\nimport '../../content/icon/icon';\nimport '../input/input';\nimport { disablableBundle, loadableBundle, roundableBundle, sizableBundle, themableBundle } from '../../shared';\nimport { reducedMotionMixin } from '../../styles';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport componentStyles from './select.css?inline';\n\n// ── Types ─────────────────────────────────────────────────────────────\n\ntype OptionItem = {\n disabled: boolean;\n group?: string;\n label: string;\n value: string;\n};\n\nexport type OreSelectOptionInput = {\n disabled?: boolean;\n group?: string;\n label?: string;\n value: string;\n};\n\ntype FlatRow =\n | {\n idx: number;\n opt: OptionItem;\n type: 'option';\n }\n | {\n label: string;\n type: 'group';\n };\n\n// ── Styles ─────────────────────────────────────────────────────────────\n\n// ── Component Props ─────────────────────────────────────────────────────────────\n\n/** Select component properties */\n\nexport type OreSelectEvents = {\n change: ChoiceChangeDetail;\n close: { reason: DropdownCloseReason };\n open: OverlayOpenDetail;\n};\n\nexport type OreSelectProps = SelectableFieldProps<Exclude<VisualVariant, 'text' | 'frost'>> & {\n /** Show loading state in dropdown */\n loading?: boolean;\n /** Allow selecting multiple options */\n multiple?: boolean;\n /** JS options array (alternative to slotted <option> elements) */\n options?: OreSelectOptionInput[];\n /** Mark the field as required */\n required?: boolean;\n};\n\n/**\n * A fully custom form-associated select dropdown with keyboard navigation and ARIA support.\n * Reads `<option>` and `<optgroup>` children from the default slot.\n *\n * @element ore-select\n *\n * @attr {string} label - Label text\n * @attr {string} label-placement - 'inset' | 'outside'\n * @attr {string} value - Current selected value(s) (comma-separated for multiple)\n * @attr {string} placeholder - Placeholder when no option selected\n * @attr {string} name - Form field name\n * @attr {boolean} multiple - Enable multi-select\n * @attr {boolean} disabled - Disable the select\n * @attr {boolean} required - Required field\n * @attr {string} helper - Helper text below the select\n * @attr {string} error - Error message\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'outline' | 'ghost'\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n * @attr {boolean} fullwidth - Expand to full width\n *\n * @fires change - Fired when selection changes. detail: { value: string, values: string[], labels: string[], originalEvent?: Event }\n * @fires open - Fired when the dropdown opens. detail: { reason: 'trigger' | 'programmatic' }\n * @fires close - Fired when the dropdown closes. detail: { reason: 'escape' | 'outsideClick' | 'programmatic' | 'trigger' }\n *\n * @slot - `<option>` and `<optgroup>` elements\n *\n * @cssprop --select-bg - Background\n * @cssprop --select-border-color - Border color\n * @cssprop --select-radius - Border radius\n * @cssprop --select-padding - Padding\n * @cssprop --select-font-size - Font size\n * @cssprop --select-placeholder-color - Placeholder text color\n *\n * @part trigger - The `ore-input` trigger element that opens the dropdown.\n * @part dropdown - The dropdown listbox panel container.\n *\n * @example\n * ```html\n * <ore-select label=\"Role\" value=\"admin\">\n * <option value=\"admin\">Administrator</option>\n * <option value=\"editor\">Editor</option>\n * <option value=\"viewer\">Viewer</option>\n * </ore-select>\n *\n * <ore-select label=\"Tags\" multiple color=\"primary\">\n * <optgroup label=\"Frontend\">\n * <option value=\"react\">React</option>\n * <option value=\"vue\">Vue</option>\n * </optgroup>\n * <optgroup label=\"Backend\">\n * <option value=\"node\">Node.js</option>\n * </optgroup>\n * </ore-select>\n * ```\n */\nexport const SELECT_TAG = 'ore-select' as const;\ndefine<OreSelectProps, OreSelectEvents>(SELECT_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n ...loadableBundle,\n ...roundableBundle,\n error: prop.string(),\n fullwidth: prop.bool(false),\n helper: prop.string(),\n label: prop.string(),\n 'label-placement': prop.oneOf(['inset', 'outside'] as const, 'inset'),\n multiple: prop.bool(false),\n name: prop.string(),\n options: prop.json(undefined as OreSelectOptionInput[] | undefined),\n placeholder: prop.string(),\n required: prop.bool(false),\n value: prop.string(),\n variant: prop.string<'flat' | 'solid' | 'bordered' | 'outline' | 'ghost'>(),\n },\n setup(props, { bind, el, emit, onCleanup, onMounted, slots }) {\n const shadowRoot = el.shadowRoot;\n // ────────────────────────────────────────────────────────────────\n // State & Context\n // ────────────────────────────────────────────────────────────────\n\n const slottedOptions = signal<OptionItem[]>([]);\n const isLoading = computed(() => Boolean(props.loading.value));\n\n // Merged options: explicit prop value overrides slotted options\n function normalizeOption(option: OreSelectOptionInput): OptionItem {\n return {\n disabled: Boolean(option.disabled),\n group: option.group,\n label: option.label ?? option.value,\n value: option.value,\n };\n }\n\n const options = computed(() => {\n const explicitOptions = props.options.value;\n\n return Array.isArray(explicitOptions) ? explicitOptions.map(normalizeOption) : slottedOptions.value;\n });\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(bind, props, formCtx);\n\n let triggerEl: HTMLElement | null = null;\n let dropdownEl: HTMLElement | null = null;\n\n const abortSignal = lifecycleSignal(onCleanup);\n let _formField: { reportValidity(): void } | null = null;\n const choice = createChoiceField({\n disabled: fCtxProps.disabled,\n error: props.error,\n getFormField: () => _formField,\n helper: props.helper,\n label: props.label,\n labelPlacement: props['label-placement'],\n multiple: props.multiple,\n prefix: 'select',\n signal: abortSignal,\n validateOn: formCtx?.validateOn,\n value: props.value,\n });\n\n _formField = useField<string>({ disabled: choice.disabled, toFormValue: (v) => v, value: choice.formValue });\n\n const optionList = createOptionList<OptionItem>({\n getBoundary: () => el,\n getFocusedOptionElement: () => dropdownEl?.querySelector<HTMLElement>('[data-focused]') ?? null,\n getItems: () => options.value,\n getPanel: () => dropdownEl,\n getReference: () => triggerEl,\n getTrigger: () => triggerEl,\n isDisabled: () => choice.disabled.value,\n onClose: (reason) => {\n emit('close', { reason });\n choice.triggerValidation('blur');\n },\n onOpen: (reason) => emit('open', { reason }),\n signal: abortSignal,\n });\n\n const { triggerValidation } = choice;\n const selectedValues = choice.selectedValues;\n const isDisabled = choice.disabled;\n\n const { fieldId: selectId } = choice;\n const listboxId = `listbox-${selectId}`;\n const { focusedIndex, isOpen } = optionList;\n\n // Sync host attributes for CSS hooks\n bind({\n attr: {\n 'has-error': () => (props.error.value ? true : undefined),\n open: () => (isOpen.value ? true : undefined),\n size: fCtxProps.size,\n variant: fCtxProps.variant,\n },\n });\n\n // ────────────────────────────────────────────────────────────────\n // Option Reading from Slot\n // ────────────────────────────────────────────────────────────────\n\n function readOptions() {\n const slot = shadowRoot?.querySelector<HTMLSlotElement>('slot');\n\n if (!slot) return;\n\n const assigned = slot.assignedElements({ flatten: true });\n const items: OptionItem[] = [];\n\n for (const el of assigned) {\n if (el.tagName === 'OPTION') {\n const opt = el as HTMLOptionElement;\n\n items.push({ disabled: opt.disabled, label: opt.text || opt.value, value: opt.value });\n } else if (el.tagName === 'OPTGROUP') {\n const group = el as HTMLOptGroupElement;\n const groupLabel = group.label;\n\n for (const child of Array.from(group.querySelectorAll('option'))) {\n const opt = child as HTMLOptionElement;\n\n items.push({ disabled: opt.disabled, group: groupLabel, label: opt.text || opt.value, value: opt.value });\n }\n }\n }\n\n slottedOptions.value = items;\n }\n\n const displayLabel = computed(() => {\n if (selectedValues.value.length === 0) return '';\n\n if (props.multiple.value && selectedValues.value.length > 1) {\n return `${selectedValues.value.length} selected`;\n }\n\n const first = selectedValues.value[0];\n\n return options.value.find((o) => o.value === first)?.label ?? first;\n });\n const selectedChipItems = computed(() => {\n if (!props.multiple.value) return [];\n\n return selectedValues.value.map((value) => ({\n label: options.value.find((o) => o.value === value)?.label ?? value,\n value,\n }));\n });\n const showChips = computed(() => props.multiple.value && selectedValues.value.length > 0);\n const triggerText = computed(() => displayLabel.value || props.placeholder.value || '');\n\n function buildFlatList(opts: OptionItem[]): FlatRow[] {\n const flat: FlatRow[] = [];\n const groups = new Map<string | undefined, OptionItem[]>();\n\n for (const opt of opts) {\n const key = opt.group;\n\n let group = groups.get(key);\n\n if (!group) {\n group = [];\n groups.set(key, group);\n }\n\n group.push(opt);\n }\n\n let globalIdx = 0;\n\n for (const [groupLabel, groupOpts] of groups) {\n if (groupLabel !== undefined) flat.push({ label: groupLabel, type: 'group' });\n\n for (const opt of groupOpts) flat.push({ idx: globalIdx++, opt, type: 'option' });\n }\n\n return flat;\n }\n\n const flatRows = computed(() => buildFlatList(options.value));\n\n function getLabelForValue(value: string): string {\n return options.value.find((option) => option.value === value)?.label ?? value;\n }\n\n function emitChange(originalEvent?: Event): void {\n const values = selectedValues.value;\n const labels = values.map((value) => getLabelForValue(value));\n\n emit('change', { labels, originalEvent, values });\n }\n\n function removeChip(event: Event): void {\n event.stopPropagation();\n\n const value = (event as CustomEvent<{ value?: string }>).detail?.value;\n\n if (value === undefined) return;\n\n choice.removeValue(value);\n emitChange(event);\n triggerValidation('change');\n }\n\n function openPopup(reason: OverlayOpenReason = 'programmatic') {\n optionList.open(reason);\n\n requestAnimationFrame(() => {\n const selectedIndex =\n selectedValues.value.length > 0\n ? options.value.findIndex((option) => option.value === selectedValues.value[0])\n : -1;\n\n if (selectedIndex >= 0) {\n optionList.set(selectedIndex);\n\n return;\n }\n\n optionList.navigate('first');\n });\n }\n\n // Selection\n\n function selectOption(opt: OptionItem, e?: Event) {\n if (opt.disabled) return;\n\n if (props.multiple.value) {\n choice.toggleValue(opt.value);\n } else {\n choice.selectValue(opt.value);\n optionList.close();\n }\n\n emitChange(e);\n triggerValidation('change');\n }\n\n // Keyboard navigation\n\n function handleTriggerKeydown(e: KeyboardEvent) {\n if (isDisabled.value) return;\n\n // Let optionList handle arrow key navigation\n if (optionList.handleKeydown(e)) return;\n\n switch (e.key) {\n case ' ':\n case 'Enter':\n e.preventDefault();\n\n if (isOpen.value) {\n const idx = focusedIndex.value;\n const opts = options.value;\n\n if (idx >= 0 && idx < opts.length) selectOption(opts[idx], e);\n } else {\n openPopup('keyboard');\n }\n\n break;\n case 'Tab':\n optionList.close();\n break;\n }\n }\n\n // ore-input prop helpers\n const inputValue = () => triggerText.value;\n const inputLabel = () => props.label.value ?? '';\n const inputPlaceholder = () => props.placeholder.value ?? '';\n const inputLabelPlacement = () => props['label-placement'].value ?? 'inset';\n const inputColor = () => props.color?.value ?? undefined;\n const inputSize = () => fCtxProps.size?.value ?? undefined;\n const inputVariant = () => fCtxProps.variant?.value ?? undefined;\n const inputRounded = () => props.rounded?.value ?? undefined;\n const inputHelper = () => props.helper.value ?? '';\n const inputError = () => props.error.value ?? '';\n const inputDisabled = () => (isDisabled.value ? true : undefined);\n const inputRequired = () => (props.required.value ? true : undefined);\n const inputFullwidth = () => (props.fullwidth.value ? true : undefined);\n const inputLoading = () => (props.loading.value ? true : undefined);\n const tabIndexAttr = () => (isDisabled.value ? '-1' : '0');\n\n watch(slots.elements(), () => readOptions(), { immediate: true });\n\n const stopPopoverSync = effect(() => {\n if (isOpen.value) {\n if (dropdownEl && 'showPopover' in dropdownEl && !dropdownEl.matches(':popover-open')) dropdownEl.showPopover();\n } else {\n if (dropdownEl && 'hidePopover' in dropdownEl && dropdownEl.matches(':popover-open')) dropdownEl.hidePopover();\n }\n });\n\n onCleanup(() => stopPopoverSync.dispose());\n\n onMounted(() => {\n let onTriggerClick: ((event: MouseEvent) => void) | null = null;\n let onTriggerKeydown: ((event: KeyboardEvent) => void) | null = null;\n\n if (triggerEl) {\n onTriggerClick = (event: MouseEvent) => {\n event.stopPropagation();\n\n if (isDisabled.value) return;\n\n if (isOpen.value) optionList.close('trigger');\n else openPopup('click');\n };\n onTriggerKeydown = (event: KeyboardEvent) => {\n handleTriggerKeydown(event);\n };\n\n triggerEl.addEventListener('click', onTriggerClick);\n triggerEl.addEventListener('keydown', onTriggerKeydown);\n }\n\n return () => {\n if (triggerEl && onTriggerClick) triggerEl.removeEventListener('click', onTriggerClick);\n\n if (triggerEl && onTriggerKeydown) triggerEl.removeEventListener('keydown', onTriggerKeydown);\n };\n });\n\n return html`<slot style=\"display:none\"></slot>\n <ore-input\n class=\"trigger\"\n part=\"trigger\"\n readonly\n tabindex=\"${tabIndexAttr}\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n aria-controls=\"${listboxId}\"\n :aria-disabled=\"${() => (isDisabled.value ? 'true' : null)}\"\n :aria-expanded=\"${() => String(isOpen.value)}\"\n :aria-invalid=\"${() => (props.error.value ? 'true' : null)}\"\n :value=\"${inputValue}\"\n :label=\"${inputLabel}\"\n :placeholder=\"${inputPlaceholder}\"\n :label-placement=\"${inputLabelPlacement}\"\n :color=\"${inputColor}\"\n :size=\"${inputSize}\"\n :variant=\"${inputVariant}\"\n :rounded=\"${inputRounded}\"\n :helper=\"${inputHelper}\"\n :error=\"${inputError}\"\n ?disabled=\"${inputDisabled}\"\n ?required=\"${inputRequired}\"\n ?fullwidth=\"${inputFullwidth}\"\n ?loading=\"${inputLoading}\"\n ref=\"${(el: HTMLElement) => {\n triggerEl = el;\n }}\">\n <div slot=\"prefix\" class=\"chips-row\" ?hidden=\"${() => !showChips.value}\">\n ${() =>\n selectedChipItems.value.map(\n (item) =>\n html`<ore-chip\n value=\"${item.value}\"\n label=\"${item.label}\"\n mode=\"removable\"\n variant=\"flat\"\n size=\"sm\"\n color=\"${props.color}\"\n @remove=\"${removeChip}\">\n ${item.label}\n </ore-chip>`,\n )}\n </div>\n <span slot=\"suffix\" class=\"trigger-suffix\" aria-hidden=\"true\">\n <span class=\"loader\"></span>\n <span class=\"trigger-icon\">\n <ore-icon name=\"chevron-down\" size=\"14\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </span>\n </span>\n </ore-input>\n <div\n class=\"dropdown\"\n part=\"dropdown\"\n popover=\"manual\"\n ?data-open=\"${isOpen}\"\n role=\"listbox\"\n id=\"${listboxId}\"\n aria-label=\"Options\"\n ref=\"${(el: HTMLElement) => {\n dropdownEl = el;\n }}\">\n <div class=\"dropdown-loading\" ?hidden=\"${() => !isLoading.value}\">Loading…</div>\n <div class=\"dropdown-empty\" ?hidden=\"${() => isLoading.value || options.value.length > 0}\">No options</div>\n <div class=\"options-list\" ?hidden=\"${() => isLoading.value || options.value.length === 0}\">\n ${() =>\n flatRows.value.map((row) =>\n row.type === 'group'\n ? html`<div class=\"optgroup-label\" role=\"presentation\">${row.label}</div>`\n : html`<div\n class=\"option\"\n role=\"option\"\n id=\"${`${selectId}-opt-${row.idx}`}\"\n data-option-index=\"${String(row.idx)}\"\n data-option-value=\"${row.opt.value}\"\n aria-selected=\"${() => String(selectedValues.value.includes(row.opt.value))}\"\n aria-disabled=\"${() => String(row.opt.disabled)}\"\n ?data-focused=\"${() => focusedIndex.value === row.idx}\"\n ?data-selected=\"${() => selectedValues.value.includes(row.opt.value)}\"\n ?data-disabled=\"${() => row.opt.disabled}\"\n @click=\"${(e: MouseEvent) => {\n e.stopPropagation();\n selectOption(row.opt, e);\n }}\"\n @pointerenter=\"${() => {\n optionList.set(row.idx);\n }}\">\n <span>${row.opt.label}</span>\n <span class=\"option-check\" aria-hidden=\"true\">\n <ore-icon name=\"check\" size=\"14\" stroke-width=\"2.5\" aria-hidden=\"true\"></ore-icon>\n </span>\n </div>`,\n )}\n </div>\n </div>`;\n },\n shadow: { delegatesFocus: true },\n styles: [reducedMotionMixin, componentStyles],\n});\n","import type { Placement } from '@vielzeug/orbit';\n\nimport { computePosition, flip, offset, shift } from '@vielzeug/orbit';\nimport { type Readable, type Signal, signal, watch } from '@vielzeug/ripple';\n\nimport { lifecycleSignal, createOverlayControl, type DialogCloseReason, type OverlayOpenReason } from '../../headless';\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport type FloatingTriggerType = 'click' | 'focus' | 'hover';\n\nexport type AriaBindFn = (triggerEl: HTMLElement) => () => void;\n\nexport type FloatingTriggerOptions = {\n /** ARIA binding factory: called with the trigger element, returns a cleanup. */\n bindTriggerAria: AriaBindFn;\n /** If true, disable all trigger interactions and close if open. */\n disabled: Readable<boolean>;\n /** Returns the host element (e.g. ore-popover) so slotted content clicks aren't treated as outside clicks. */\n getHost?: () => Element | null;\n /** Returns the panel element, if mounted. */\n getPanel: () => HTMLElement | null;\n /** Gap from reference to floating panel in px. Default: 8. Accepts a signal for runtime reactivity. */\n offset?: Readable<number | undefined> | number;\n /** Cleanup registrar from the component setup ctx. Automatically called on disconnect. */\n onCleanup: (fn: () => void) => void;\n /** Called when the popover closes. */\n onClose?: (reason: DialogCloseReason) => void;\n /** Called when the popover opens. */\n onOpen?: (reason: OverlayOpenReason) => void;\n /** Callback when resolved placement changes (useful for CSS attribute). */\n onPlacementChange?: (placement: Placement) => void;\n /** Controlled open prop. When defined, disables uncontrolled logic. */\n openProp: Readable<boolean | undefined>;\n /** Preferred placement. Default: 'bottom'. */\n placement: Readable<Placement>;\n /** Slot element or a factory to lazily find it. Resolved each time bindEvents runs. */\n slot: HTMLSlotElement | null | (() => HTMLSlotElement | null);\n /** Slot elements signal — used to rebind when slotted elements change. */\n slotElements: Readable<Element[]>;\n /** Which triggers are active. Set to empty array or omit if handling events manually. */\n triggers: Readable<FloatingTriggerType[]>;\n};\n\nexport type FloatingTriggerHandle = {\n /** Closes the panel. No-op if controlled. */\n close: (reason?: DialogCloseReason) => void;\n /**\n * Call inside `onMounted`. Sets up slot + trigger event watchers\n * and returns a cleanup function to pass back to the framework.\n */\n mount: () => () => void;\n /** Opens the panel. No-op if controlled. */\n open: (reason?: OverlayOpenReason) => void;\n /** Toggles the panel. No-op if controlled. */\n toggle: () => void;\n /** Manually trigger a position recalculation. */\n updatePosition: () => void;\n /** Whether the panel is currently visible. */\n visible: Signal<boolean>;\n};\n\n// ── Implementation ─────────────────────────────────────────────────────────────\n\n/**\n * Shared logic for floating-panel triggers (tooltip, popover).\n *\n * Handles:\n * - Slot-based trigger element detection and rebinding\n * - Event binding per trigger type (hover / focus / click)\n * - Floating-element positioning via `@vielzeug/orbit`\n * - Controlled mode via `openProp` watcher\n * - Keyboard escape dismissal\n *\n * ARIA binding is intentionally delegated to the caller via `bindTriggerAria`\n * so that tooltip (`describedby`) and popover (`expanded`/`controls`/…) can diverge.\n */\nexport const useFloatingTrigger = (options: FloatingTriggerOptions): FloatingTriggerHandle => {\n const {\n bindTriggerAria,\n disabled,\n getPanel,\n onClose,\n onOpen,\n onPlacementChange,\n openProp,\n placement,\n slot,\n slotElements,\n triggers,\n } = options;\n\n const resolveSlot = (): HTMLSlotElement | null => (typeof slot === 'function' ? slot() : slot);\n const getOffset = (): number => {\n const o = options.offset;\n\n if (o == null) return 8;\n\n const val = typeof o === 'object' ? (o as Readable<number | undefined>).value : o;\n\n return val ?? 8;\n };\n const abortSignal = lifecycleSignal(options.onCleanup);\n const visible = signal(false);\n const isControlled = () => openProp.value !== undefined;\n let currentTrigger: HTMLElement | null = null;\n let triggerBinding: (() => void) | null = null;\n\n const overlay = createOverlayControl({\n getBoundary: () => document.body,\n getPanel,\n getTrigger: () => currentTrigger,\n isDisabled: () => disabled.value,\n isOpen: () => visible.value,\n onClose,\n onOpen,\n positioner: {\n floating: getPanel,\n reference: () => currentTrigger,\n update: updatePosition,\n },\n restoreFocus: false,\n setOpen: (next) => {\n if (isControlled()) return;\n\n if (next) showFloat();\n else hideFloat();\n },\n signal: abortSignal,\n });\n\n function updatePosition(): void {\n const panel = getPanel();\n\n if (!panel || !currentTrigger) return;\n\n const result = computePosition(currentTrigger, panel, {\n middleware: [offset(getOffset()), flip(), shift({ padding: 8 })],\n placement: placement.value,\n });\n\n panel.style.left = `${result.x}px`;\n panel.style.top = `${result.y}px`;\n\n panel.dataset.placement = result.placement;\n\n onPlacementChange?.(result.placement as Placement);\n }\n\n function showFloat(): void {\n visible.value = true;\n\n const panel = getPanel();\n\n if (panel) {\n panel.dataset.open = '';\n\n if ('showPopover' in panel) {\n try {\n if (!panel.matches(':popover-open')) panel.showPopover();\n } catch {\n // Popover API restricted (e.g. sandboxed iframe); data-open CSS fallback handles visibility.\n }\n }\n }\n\n updatePosition();\n }\n\n function hideFloat(): void {\n visible.value = false;\n\n const panel = getPanel();\n\n if (panel) {\n delete panel.dataset.open;\n\n if ('hidePopover' in panel) {\n try {\n if (panel.matches(':popover-open')) panel.hidePopover();\n } catch {\n // Popover API restricted; data-open removal handles visibility.\n }\n }\n }\n }\n\n function open(reason: OverlayOpenReason = 'programmatic'): void {\n if (!isControlled()) overlay.open(reason);\n }\n\n function close(reason: DialogCloseReason = 'trigger'): void {\n if (!isControlled()) overlay.close(reason, false);\n }\n\n function toggle(): void {\n if (!isControlled()) overlay.toggle();\n }\n\n function handleKeydown(e: KeyboardEvent): void {\n if (e.key === 'Escape') close('escape');\n }\n\n function handleClickOutside(e: PointerEvent | MouseEvent): void {\n if (!visible.value) return;\n\n const path = e.composedPath();\n const panel = getPanel();\n const host = options.getHost?.();\n\n if (\n (currentTrigger && path.includes(currentTrigger)) ||\n (panel && path.includes(panel)) ||\n (host && path.includes(host))\n )\n return;\n\n close('outsideClick');\n }\n\n function handleFocusOut(e: FocusEvent): void {\n const next = e.relatedTarget as Element | null;\n const panel = getPanel();\n\n if (next && panel?.contains(next)) return;\n\n if (next && currentTrigger?.contains(next)) return;\n\n close('trigger');\n }\n\n const bindEvents = (): void => {\n triggerBinding?.();\n triggerBinding = null;\n\n const triggerEl = resolveSlot()?.assignedElements({ flatten: true })[0] as HTMLElement | undefined;\n\n if (!triggerEl) {\n currentTrigger = null;\n\n return;\n }\n\n currentTrigger = triggerEl;\n\n const removeAria = bindTriggerAria(triggerEl);\n const cleanups: Array<() => void> = [];\n\n const add = (\n target: EventTarget,\n event: string,\n listener: EventListener,\n eventOptions?: AddEventListenerOptions,\n ): void => {\n target.addEventListener(event, listener, eventOptions);\n cleanups.push(() => target.removeEventListener(event, listener, eventOptions));\n };\n\n const t = triggers.value;\n\n if (t.includes('click')) {\n add(triggerEl, 'click', toggle as EventListener);\n add(document, 'pointerdown', handleClickOutside as EventListener, { capture: true });\n }\n\n if (t.includes('hover')) {\n add(triggerEl, 'pointerenter', () => open('hover'));\n add(triggerEl, 'pointerleave', () => close('trigger'));\n\n const panelEl = getPanel();\n\n if (panelEl) {\n add(panelEl, 'pointerenter', () => open('hover'));\n add(panelEl, 'pointerleave', () => close('trigger'));\n }\n }\n\n if (t.includes('focus')) {\n add(triggerEl, 'focusin', () => open('focus'));\n add(triggerEl, 'focusout', handleFocusOut as EventListener);\n\n const panelEl = getPanel();\n\n if (panelEl) add(panelEl, 'focusout', handleFocusOut as EventListener);\n }\n\n add(document, 'keydown', handleKeydown as EventListener);\n\n triggerBinding = () => {\n removeAria();\n\n for (const cleanup of cleanups) cleanup();\n\n currentTrigger = null;\n };\n };\n\n const mount = (): (() => void) => {\n watch(slotElements, bindEvents, { immediate: true });\n\n watch(\n openProp,\n (openVal) => {\n if (openVal === undefined || openVal === null) return;\n\n if (openVal) {\n showFloat();\n onOpen?.('programmatic');\n } else if (visible.value) {\n hideFloat();\n onClose?.('programmatic');\n }\n },\n { immediate: true },\n );\n\n watch(disabled, (isNowDisabled) => {\n if (isNowDisabled) close('programmatic');\n });\n\n return () => {\n triggerBinding?.();\n triggerBinding = null;\n\n const panel = getPanel();\n\n if (panel) {\n delete panel.dataset.open;\n\n if ('hidePopover' in panel) {\n try {\n if (panel.matches(':popover-open')) panel.hidePopover();\n } catch {\n // Popover API restricted; data-open removal handles visibility.\n }\n }\n }\n\n overlay.dispose();\n };\n };\n\n return { close, mount, open, toggle, updatePosition, visible };\n};\n","@layer refine.base {\n :host {\n --_panel-bg: var(--popover-bg, var(--color-canvas));\n --_panel-blur: var(--popover-panel-blur, var(--blur-md));\n --_panel-border-color: var(--popover-border-color, var(--color-divider));\n --_panel-shadow: var(--popover-shadow, var(--shadow-xl));\n\n position: relative;\n display: inline-block;\n }\n\n .panel {\n position: fixed;\n\n /* Popover UA resets */\n inset: unset;\n box-sizing: border-box;\n min-width: var(--popover-min-width, 12rem);\n max-width: var(--popover-max-width, 24rem);\n max-height: var(--popover-max-height, min(70vh, 32rem));\n padding: 0;\n margin: 0;\n overflow: auto;\n word-break: auto-phrase;\n overflow-wrap: anywhere;\n background: var(--_panel-bg);\n border: var(--border) solid var(--_panel-border-color);\n border-radius: var(--rounded-lg);\n box-shadow: var(--_panel-shadow);\n\n /* Hidden by default */\n opacity: 0;\n backdrop-filter: blur(var(--_panel-blur));\n transform: scale(var(--overlay-enter-scale-dialog)) translateY(4px);\n transition:\n opacity var(--transition-fast),\n transform 200ms var(--ease-spring),\n display var(--transition-fast) allow-discrete,\n overlay var(--transition-fast) allow-discrete;\n }\n\n .panel[data-open] {\n display: block;\n }\n\n .panel:popover-open,\n .panel[data-open] {\n opacity: 1;\n transform: scale(1) translateY(0);\n\n @starting-style {\n opacity: 0;\n transform: scale(var(--overlay-enter-scale-dialog)) translateY(4px);\n }\n }\n}\n","import { type Placement } from '@vielzeug/orbit';\nimport { createStableId, define, html, prop } from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\n\nimport { type DialogCloseReason, type OverlayOpenReason, parseStringTriggers } from '../../headless';\nimport { disablableBundle } from '../../shared';\nimport { reducedMotionMixin } from '../../styles';\nimport { useFloatingTrigger } from '../shared/use-floating-trigger';\nimport styles from './popover.css?inline';\n\nexport type PopoverTrigger = 'click' | 'focus' | 'hover';\n\nconst PANEL_OFFSET = 8;\nconst VALID_TRIGGERS = new Set<PopoverTrigger>(['click', 'focus', 'hover']);\nconst DEFAULT_POPOVER_TRIGGERS: PopoverTrigger[] = ['click'];\n\nconst normalizeTriggers = (value: unknown): PopoverTrigger[] =>\n parseStringTriggers(String(value ?? ''), VALID_TRIGGERS, DEFAULT_POPOVER_TRIGGERS);\n\nexport type OrePopoverEvents = {\n /** Emitted when the popover closes */\n close: { reason: DialogCloseReason };\n /** Emitted when the popover opens */\n open: { reason: OverlayOpenReason };\n};\n\n/** Popover component properties */\nexport type OrePopoverProps = {\n /** Disable the popover */\n disabled?: boolean;\n /** Accessible label for the panel */\n label?: string;\n /** Gap between trigger and panel in px */\n offset?: number;\n /** Controlled open state */\n open?: boolean;\n /** Preferred placement relative to the trigger */\n placement?: Placement;\n /** Which trigger(s) open/close the popover */\n trigger?: string;\n};\n\n/**\n * A floating panel anchored to a trigger element.\n *\n * @element ore-popover\n * @attr {string} placement - Preferred placement (default: 'bottom')\n * @attr {string} trigger - 'click' | 'hover' | 'focus' (default: 'click')\n * @attr {boolean} open - Controlled open state\n * @attr {number} offset - Gap in px (default: 8)\n * @attr {boolean} disabled - Disables the popover\n * @attr {string} label - aria-label on the panel\n * @fires open - When the panel opens. detail: { reason: string }\n * @fires close - When the panel closes. detail: { reason: string }\n * @slot - The trigger element\n * @slot content - Panel content\n * @part panel - Panel container.\n *\n * @example\n * ```html\n * <ore-popover placement=\"bottom\" trigger=\"click\">\n * <ore-button>Open info</ore-button>\n * <div slot=\"content\">\n * <p>Popover body content goes here.</p>\n * </div>\n * </ore-popover>\n * ```\n */\nexport const POPOVER_TAG = 'ore-popover' as const;\ndefine<OrePopoverProps, OrePopoverEvents>(POPOVER_TAG, {\n props: {\n ...disablableBundle,\n label: prop.string(),\n offset: prop.number(PANEL_OFFSET),\n open: prop.json(undefined as boolean | undefined),\n placement: prop.oneOf(\n [\n 'bottom',\n 'bottom-end',\n 'bottom-start',\n 'left',\n 'left-end',\n 'left-start',\n 'right',\n 'right-end',\n 'right-start',\n 'top',\n 'top-end',\n 'top-start',\n ] as const,\n 'bottom',\n ),\n trigger: prop.string('click'),\n },\n setup(props, { aria, el, emit, onCleanup, onMounted, slots }) {\n const shadowRoot = el.shadowRoot;\n const isDisabled = computed(() => Boolean(props.disabled.value));\n const panelId = createStableId('popover');\n const triggers = computed<PopoverTrigger[]>(() => normalizeTriggers(props.trigger.value));\n let panelEl: HTMLElement | null = null;\n\n const floating = useFloatingTrigger({\n bindTriggerAria: (triggerEl) =>\n aria(triggerEl, {\n controls: () => panelId,\n disabled: () => String(isDisabled.value),\n expanded: () => String(floating.visible.value),\n haspopup: 'dialog',\n }),\n disabled: isDisabled,\n getHost: () => el,\n getPanel: () => panelEl,\n offset: props.offset,\n onCleanup,\n onClose: (reason) => emit('close', { reason }),\n onOpen: (reason) => emit('open', { reason }),\n openProp: props.open as typeof props.open & { value: boolean | undefined },\n placement: computed(() => props.placement.value as Placement),\n slot: () => shadowRoot?.querySelector<HTMLSlotElement>('slot:not([name])') ?? null,\n slotElements: slots.elements(),\n triggers,\n });\n\n onMounted(() => floating.mount());\n\n return html`\n <slot></slot>\n <div\n class=\"panel\"\n part=\"panel\"\n id=\"${panelId}\"\n role=\"dialog\"\n aria-modal=\"false\"\n popover=\"manual\"\n :aria-label=\"${props.label}\"\n :aria-hidden=\"${() => String(!floating.visible.value)}\"\n ref=${(ref: HTMLElement) => {\n panelEl = ref;\n }}>\n <slot name=\"content\"></slot>\n </div>\n `;\n },\n styles: [reducedMotionMixin, styles],\n});\n","import type { DataGridColumn } from '../../headless';\n\nimport { warn } from '../../_dev';\n\n// ── Declarative ore-column element ────────────────────────────────────────────\n\n/**\n * Declarative column definition for `<ore-datagrid>`.\n * Use as a child element instead of setting the `columns` prop imperatively.\n *\n * @element ore-column\n *\n * @attr {string} key - Row property key (required)\n * @attr {string} label - Header display label (required)\n * @attr {boolean} sortable - Makes the column sortable\n * @attr {boolean} resizable - Adds a drag handle to resize the column\n * @attr {string} align - Text alignment: 'left' | 'center' | 'right'\n * @attr {string} width - CSS column width (e.g. '12rem')\n * @attr {string} header-label - Accessible label override for the column header\n *\n * @example\n * ```html\n * <ore-datagrid>\n * <ore-column key=\"name\" label=\"Name\" sortable></ore-column>\n * <ore-column key=\"email\" label=\"Email\" width=\"20rem\"></ore-column>\n * </ore-datagrid>\n * ```\n */\nif (!customElements.get('ore-column'))\n customElements.define(\n 'ore-column',\n class extends HTMLElement {\n connectedCallback(): void {\n if (!this.getAttribute('key')) {\n warn('ore-column: missing required `key` attribute');\n }\n\n if (!this.getAttribute('label')) {\n warn('ore-column: missing required `label` attribute');\n }\n }\n },\n );\n\nexport const COLUMN_TAG = 'ore-column' as const;\n\n/** Attributes observed by the column MutationObserver in ore-datagrid. */\nexport const COLUMN_OBSERVED_ATTRS = [\n 'key',\n 'label',\n 'sortable',\n 'resizable',\n 'align',\n 'width',\n 'header-label',\n] as const;\n\n/** Parse all `<ore-column>` direct children of `host` into DataGridColumn descriptors. */\nexport function parseColumnChildren(host: HTMLElement): DataGridColumn[] {\n return Array.from(host.querySelectorAll(':scope > ore-column')).map((el) => ({\n align: (el.getAttribute('align') as 'left' | 'center' | 'right' | null) ?? undefined,\n headerLabel: el.getAttribute('header-label') ?? undefined,\n key: el.getAttribute('key') ?? '',\n label: el.getAttribute('label') ?? '',\n resizable: el.hasAttribute('resizable'),\n sortable: el.hasAttribute('sortable'),\n width: el.getAttribute('width') ?? undefined,\n }));\n}\n","import { computed, signal, type Readable, watch } from '@vielzeug/ripple';\n\nimport type { DataGridColumn } from '../../headless';\n\n// ── Types ──────────────────────────────────────────────────────────────────────\n\n/**\n * A single filter option definition — the available choices shown in the filter picker\n * for one column. When `filterOptions` is not provided on the grid, options are\n * auto-derived from the current row data.\n */\nexport type FilterOption = {\n key: string;\n label: string;\n operators?: { label: string; value: string }[];\n options: { label?: string; value: string }[];\n};\n\nexport type FilterOperator = 'contains' | 'equals' | 'gt' | 'lt';\n\nexport type FilterRule = {\n operator: FilterOperator;\n values: Set<string>;\n};\n\nexport type DataGridView = {\n /** Unique identifier for this view. */\n id: string;\n /** Display label shown in the tab. */\n label: string;\n};\n\nexport type DataGridControlsOptions = {\n /** Reactive column definitions — used to auto-derive filter options and prune stale state. */\n columns: Readable<DataGridColumn[]>;\n /**\n * Pre-defined filter option definitions per column key.\n * When set, these replace auto-derived options for matching keys.\n */\n filterOptions: Readable<FilterOption[] | undefined>;\n /** Reactive row data — searched and filtered to produce `filteredRows`. */\n rows: Readable<Record<string, unknown>[]>;\n};\n\nexport type DataGridControlsHandle = {\n /** Add a column key to the active filter set (makes its rule appear in the UI). */\n activateFilterKey(key: string): void;\n /** Clear all active filter rules and values. */\n clearAllFilters(): void;\n /**\n * Merged filter option definitions (provided + user-activated auto-derived).\n * A key's presence means its filter rule is visible in the UI.\n */\n readonly filterDefs: Readable<FilterOption[]>;\n /**\n * Rows after applying search and filter. Pass this as the `items` source\n * to the table control so the headless module owns the full data pipeline.\n */\n readonly filteredRows: Readable<Record<string, unknown>[]>;\n /** Unified filter state: column key → filter rule (operator + values). */\n readonly filterValues: Readable<Map<string, FilterRule>>;\n /** Set of column keys hidden by the user. */\n readonly hiddenColumns: Readable<Set<string>>;\n /** Remove a column's filter rule and clear its selected values. */\n removeFilter(key: string): void;\n /** Clear all active filter rules and values. Alias for clearAllFilters, provided for symmetry with resetSearch. */\n resetFilters(): void;\n /** Clear search state (query + active flag). Column visibility is a persistent preference and is never reset. */\n resetSearch(): void;\n /** Whether the inline search input is currently open. */\n readonly searchActive: Readable<boolean>;\n /** Current text search query. */\n readonly searchQuery: Readable<string>;\n /** Set the active filter keys at once, pruning stale values. */\n setActiveFilterKeys(keys: string[]): void;\n /** Apply or update a multi-select filter for a column. Pass [] to clear that column's values. */\n setFilter(key: string, values: string[]): void;\n /** Update the operator for a specific filter rule. */\n setFilterOperator(key: string, operator: FilterOperator): void;\n /** Set the raw search query text directly. */\n setSearchQuery(q: string): void;\n /** Toggle a column's visibility. */\n toggleColumnVisibility(key: string): void;\n /** Toggle search open/closed. Clears the query on close. */\n toggleSearch(): void;\n};\n\n// ── Implementation ─────────────────────────────────────────────────────────────\n\nconst DEFAULT_OPERATORS: { label: string; value: FilterOperator }[] = [\n { label: 'Contains', value: 'contains' },\n { label: 'Equals', value: 'equals' },\n { label: 'Greater than', value: 'gt' },\n { label: 'Less than', value: 'lt' },\n];\n\n/**\n * Headless controls for ore-datagrid: search, filter, column visibility, and derived rows.\n *\n * Design notes:\n * - Filter state uses two signals: activeFilterKeys (Set) drives filterDefs and\n * the filter rule DOM; filterValues (Map) tracks selected values per key.\n * Separating them prevents filterDefs from recomputing on value changes, which\n * would otherwise destroy and recreate the combobox mid-interaction.\n * - colOptions is computed lazily — only for columns with active filter rules,\n * so the common case (no active filters) costs O(0) row iterations.\n * - filteredRows is derived here (not in the component) so the full data pipeline\n * lives in one place and can be unit-tested end-to-end.\n */\nexport const createDataGridControls = (options: DataGridControlsOptions): DataGridControlsHandle => {\n const searchQuery = signal('');\n const searchActive = signal(false);\n const hiddenColumns = signal(new Set<string>());\n\n // Two-signal filter state: activeFilterKeys tracks which rules exist (drives\n // filterDefs / DOM structure); filterValues tracks selected values per key.\n // Separating them prevents filterDefs from recomputing — and the filter rule\n // DOM from being torn down — every time a value is selected.\n const activeFilterKeys = signal(new Set<string>());\n const filterValues = signal(new Map<string, FilterRule>());\n\n // Derive options only for columns that have an active filter rule and are not\n // covered by externally-provided filterOptions. Lazy: O(activeRules × rows).\n const colOptions = computed(() => {\n const externalKeys = new Set((options.filterOptions.value ?? []).map((f) => f.key));\n const activeKeys = [...activeFilterKeys.value].filter((k) => !externalKeys.has(k));\n\n if (!activeKeys.length) return new Map<string, { label: string; value: string }[]>();\n\n const rows = options.rows.value;\n const map = new Map<string, { label: string; value: string }[]>();\n\n for (const key of activeKeys) {\n const seen = new Set<string>();\n const opts: { label: string; value: string }[] = [];\n\n for (const row of rows) {\n const v = row[key];\n const s = v == null ? '' : String(v);\n\n if (!seen.has(s)) {\n seen.add(s);\n opts.push({ label: s || '(empty)', value: s });\n }\n }\n\n map.set(key, opts);\n }\n\n return map;\n });\n\n // Merge provided filter options with auto-derived ones for active keys.\n // Depends only on activeFilterKeys (not filterValues) so adding/removing a\n // value does not tear down the filter rule DOM.\n const filterDefs = computed<FilterOption[]>(() => {\n const provided = options.filterOptions.value ?? [];\n const providedKeys = new Set(provided.map((f) => f.key));\n const derived = [...activeFilterKeys.value]\n .filter((k) => !providedKeys.has(k))\n .map((k) => {\n const col = options.columns.value.find((c) => c.key === k);\n\n return {\n key: k,\n label: col?.label ?? k,\n operators: DEFAULT_OPERATORS,\n options: colOptions.value.get(k) ?? [],\n };\n });\n\n return [...provided.map((f) => ({ ...f, operators: f.operators ?? DEFAULT_OPERATORS })), ...derived];\n });\n\n // Prune stale filter rules when columns are removed.\n watch(\n computed(() => new Set(options.columns.value.map((c) => c.key))),\n (keySet) => {\n const prunedKeys = new Set([...activeFilterKeys.value].filter((k) => keySet.has(k)));\n\n if (prunedKeys.size !== activeFilterKeys.value.size) activeFilterKeys.value = prunedKeys;\n\n const prunedValues = new Map([...filterValues.value].filter(([k]) => keySet.has(k)));\n\n if (prunedValues.size !== filterValues.value.size) filterValues.value = prunedValues;\n },\n { immediate: false },\n );\n\n // Full data pipeline: search then filter. Lives here so the headless module\n // owns the complete input→output contract and can be tested end-to-end.\n const searchedRows = computed(() => {\n const rows = options.rows.value;\n const q = searchQuery.value.trim().toLowerCase();\n\n if (!q) return rows;\n\n return rows.filter((row) => Object.values(row).some((v) => v != null && String(v).toLowerCase().includes(q)));\n });\n\n const filteredRows = computed(() => {\n const rows = searchedRows.value;\n const fv = filterValues.value;\n\n if (!fv.size) return rows;\n\n const currentKeys = new Set(options.columns.value.map((c) => c.key));\n\n return rows.filter((row) => {\n for (const [key, rule] of fv) {\n if (!rule.values.size || !currentKeys.has(key)) continue;\n\n const cell = row[key];\n const cellValue = cell == null ? '' : String(cell);\n\n if (rule.operator === 'equals') {\n if (!rule.values.has(cellValue)) return false;\n } else if (rule.operator === 'contains') {\n if (![...rule.values].some((v) => cellValue.toLowerCase().includes(v.toLowerCase()))) return false;\n } else if (rule.operator === 'gt' || rule.operator === 'lt') {\n const num = parseFloat(cellValue);\n const targets = [...rule.values].map(parseFloat).filter((n) => !isNaN(n));\n\n if (!targets.length) continue;\n\n if (rule.operator === 'gt') {\n if (!targets.some((t) => num > t)) return false;\n } else {\n if (!targets.some((t) => num < t)) return false;\n }\n }\n }\n\n return true;\n });\n });\n\n const setFilter = (key: string, values: string[]): void => {\n const next = new Map(filterValues.value);\n\n if (values.length === 0) {\n next.delete(key);\n } else {\n const existing = next.get(key);\n\n next.set(key, { operator: existing?.operator ?? 'contains', values: new Set(values) });\n }\n\n filterValues.value = next;\n };\n\n const setFilterOperator = (key: string, operator: FilterOperator): void => {\n const next = new Map(filterValues.value);\n const existing = next.get(key);\n\n if (existing) {\n next.set(key, { ...existing, operator });\n\n filterValues.value = next;\n }\n };\n\n const activateFilterKey = (key: string): void => {\n if (activeFilterKeys.value.has(key)) return;\n\n activeFilterKeys.value = new Set([...activeFilterKeys.value, key]);\n };\n\n const removeFilter = (key: string): void => {\n const nextKeys = new Set(activeFilterKeys.value);\n\n nextKeys.delete(key);\n activeFilterKeys.value = nextKeys;\n\n const nextValues = new Map(filterValues.value);\n\n nextValues.delete(key);\n filterValues.value = nextValues;\n };\n\n const clearAllFilters = (): void => {\n activeFilterKeys.value = new Set();\n filterValues.value = new Map();\n };\n\n const setSearchQuery = (q: string): void => {\n searchQuery.value = q;\n };\n\n const setActiveFilterKeys = (keys: string[]): void => {\n const nextKeys = new Set(keys);\n\n activeFilterKeys.value = nextKeys;\n\n // Prune values for keys that are no longer active.\n const nextValues = new Map(filterValues.value);\n let changed = false;\n\n for (const k of nextValues.keys()) {\n if (!nextKeys.has(k)) {\n nextValues.delete(k);\n changed = true;\n }\n }\n\n if (changed) filterValues.value = nextValues;\n };\n\n const toggleColumnVisibility = (key: string): void => {\n const next = new Set(hiddenColumns.value);\n\n if (next.has(key)) {\n next.delete(key);\n } else {\n next.add(key);\n }\n\n hiddenColumns.value = next;\n };\n\n const toggleSearch = (): void => {\n if (searchActive.value) searchQuery.value = '';\n\n searchActive.value = !searchActive.value;\n };\n\n const resetSearch = (): void => {\n searchQuery.value = '';\n searchActive.value = false;\n };\n\n const resetFilters = (): void => {\n activeFilterKeys.value = new Set();\n filterValues.value = new Map();\n };\n\n return {\n activateFilterKey,\n clearAllFilters,\n filterDefs,\n filteredRows,\n filterValues,\n hiddenColumns,\n removeFilter,\n resetFilters,\n resetSearch,\n searchActive,\n searchQuery,\n setActiveFilterKeys,\n setFilter,\n setFilterOperator,\n setSearchQuery,\n toggleColumnVisibility,\n toggleSearch,\n };\n};\n","import { type Readable, signal } from '@vielzeug/ripple';\n\n// ── Types ──────────────────────────────────────────────────────────────────────\n\n/** Position in the 2D grid model (0-based row/col indices). */\nexport type GridCellPos = { col: number; row: number };\n\n/** Handle returned by createGridNav for programmatic control. */\nexport type GridNavHandle = {\n /** Current active cell position. Reactive signal. */\n readonly activeCell: Readable<GridCellPos>;\n /**\n * Move focus to a specific cell by position.\n * Clamps to valid grid bounds; no-ops for invalid positions.\n */\n focusCell(pos: GridCellPos): void;\n};\n\n// ── Selector ───────────────────────────────────────────────────────────────────\n\nconst CELL_SELECTOR = '.dg-td, .dg-th';\n\n/** Build a 2D array of focusable cells from the shadow root. One sub-array per <tr>. */\nfunction getGrid(shadow: ShadowRoot): HTMLElement[][] {\n return Array.from(shadow.querySelectorAll<HTMLElement>('tr'))\n .map((tr) => Array.from(tr.querySelectorAll<HTMLElement>(CELL_SELECTOR)))\n .filter((row) => row.length > 0);\n}\n\n// ── Factory ────────────────────────────────────────────────────────────────────\n\n/**\n * Keyboard navigation for the ARIA grid pattern (roving tabindex).\n *\n * - Arrow keys move focus between cells.\n * - Home/End move to the first/last cell in the row.\n * - Ctrl+Home/Ctrl+End move to the first/last cell in the grid.\n * - Only the active cell has `tabindex=\"0\"`; all others have `\"-1\"`.\n *\n * @param table - The `.dg-table` element to attach the keydown listener to.\n * @param shadow - The shadow root containing the grid cells.\n * @returns A handle with `focusCell` and a reactive `activeCell` signal, plus a cleanup fn.\n */\nexport function createGridNav(table: HTMLElement, shadow: ShadowRoot): { cleanup: () => void; handle: GridNavHandle } {\n const activeCell = signal<GridCellPos>({ col: 0, row: 0 });\n\n const focusCell = (pos: GridCellPos): void => {\n const grid = getGrid(shadow);\n const rowIdx = Math.max(0, Math.min(pos.row, grid.length - 1));\n const row = grid[rowIdx];\n\n if (!row) return;\n\n const colIdx = Math.max(0, Math.min(pos.col, row.length - 1));\n const target = row[colIdx];\n\n if (!target) return;\n\n for (const r of grid) {\n for (const cell of r) cell.setAttribute('tabindex', '-1');\n }\n\n target.setAttribute('tabindex', '0');\n target.focus();\n activeCell.value = { col: colIdx, row: rowIdx };\n };\n\n const handleArrow = (e: KeyboardEvent): void => {\n const active = shadow.activeElement as HTMLElement | null;\n\n if (!active?.matches(CELL_SELECTOR)) return;\n\n const grid = getGrid(shadow);\n const rowIdx = grid.findIndex((row) => row.includes(active));\n\n if (rowIdx === -1) return;\n\n const colIdx = grid[rowIdx].indexOf(active);\n const lastRow = grid.length - 1;\n const lastCol = grid[rowIdx].length - 1;\n\n let nextRow = rowIdx;\n let nextCol = colIdx;\n\n if (e.key === 'ArrowRight') nextCol = colIdx + 1;\n else if (e.key === 'ArrowLeft') nextCol = colIdx - 1;\n else if (e.key === 'ArrowDown') nextRow = rowIdx + 1;\n else if (e.key === 'ArrowUp') nextRow = rowIdx - 1;\n else if (e.key === 'Home') {\n nextCol = 0;\n\n if (e.ctrlKey) nextRow = 0;\n } else if (e.key === 'End') {\n nextCol = lastCol;\n\n if (e.ctrlKey) nextRow = lastRow;\n } else return;\n\n e.preventDefault();\n focusCell({\n col: Math.max(0, Math.min(nextCol, (grid[Math.max(0, Math.min(nextRow, lastRow))]?.length ?? 1) - 1)),\n row: Math.max(0, Math.min(nextRow, lastRow)),\n });\n };\n\n table.addEventListener('keydown', handleArrow);\n\n return {\n cleanup: () => table.removeEventListener('keydown', handleArrow),\n handle: { activeCell, focusCell },\n };\n}\n","@layer refine.base {\n :host {\n /* ── Datagrid-specific token overrides on top of tableBaseMixin ─────── */\n --_row-hover-bg: var(--datagrid-row-hover-bg, color-mix(in oklch, var(--color-contrast-500) 5%, transparent));\n --_row-selected-bg: var(--datagrid-row-selected-bg, color-mix(in oklch, var(--_accent) 10%, transparent));\n --_row-selected-border: var(--datagrid-row-selected-border, var(--_accent));\n }\n\n /* ── Scroll wrapper ───────────────────────────────────────────────────────── */\n\n .dg-scroll {\n max-height: var(--datagrid-max-height, none);\n overflow: auto;\n }\n\n /* ── Table ────────────────────────────────────────────────────────────────── */\n\n .dg-table {\n width: 100%;\n font-size: var(--_font-size);\n table-layout: auto;\n border-collapse: collapse;\n }\n\n /* ── Head ─────────────────────────────────────────────────────────────────── */\n\n .dg-head {\n position: sticky;\n top: 0;\n z-index: 2;\n background: var(--_header-bg);\n box-shadow: inset 0 calc(var(--border) * -1) 0 var(--_border-color);\n }\n\n .dg-th {\n padding: var(--_cell-padding-y) var(--_cell-padding-x);\n font-size: var(--text-xs);\n font-weight: var(--font-semibold);\n color: var(--color-contrast-500);\n text-align: start;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n white-space: nowrap;\n user-select: none;\n border-right: var(--border) solid var(--_border-color);\n\n &[data-align='center'] {\n text-align: center;\n }\n\n &[data-align='right'] {\n text-align: right;\n }\n\n &:has(.dg-sort-btn) {\n padding: 0;\n }\n }\n\n .dg-sort-btn {\n --button-padding: var(--_cell-padding-y) var(--_cell-padding-x);\n --button-font-size: var(--text-xs);\n --button-font-weight: var(--font-semibold);\n --button-color: var(--color-contrast-500);\n --button-justify: flex-start;\n\n height: 100%;\n }\n\n .dg-th[data-align='center'] .dg-sort-btn {\n --button-justify: center;\n }\n\n .dg-th[data-align='right'] .dg-sort-btn {\n --button-justify: flex-end;\n }\n\n :host(:dir(rtl)) .dg-th,\n :dir(rtl) .dg-th {\n border-right: none;\n border-left: var(--border) solid var(--_border-color);\n }\n\n .dg-th:last-child,\n .dg-th.dg-th-check,\n .dg-th.dg-th-expand,\n .dg-th.dg-th-last {\n border-right: none;\n }\n\n :host(:dir(rtl)) .dg-th:last-child,\n :host(:dir(rtl)) .dg-th.dg-th-check,\n :host(:dir(rtl)) .dg-th.dg-th-expand,\n :host(:dir(rtl)) .dg-th.dg-th-last,\n :dir(rtl) .dg-th:last-child,\n :dir(rtl) .dg-th.dg-th-check,\n :dir(rtl) .dg-th.dg-th-expand,\n :dir(rtl) .dg-th.dg-th-last {\n border-left: none;\n }\n\n .dg-th-inner {\n position: relative;\n display: flex;\n gap: var(--size-1);\n align-items: center;\n }\n\n .dg-th[aria-sort]:has(.dg-sort-btn:hover):not(:has(.dg-sort-btn[aria-disabled='true'])) {\n background: color-mix(in oklch, var(--color-contrast-900) 5%, transparent);\n }\n\n .dg-th[aria-sort='ascending'] .dg-sort-icon,\n .dg-th[aria-sort='descending'] .dg-sort-icon {\n color: var(--_accent);\n }\n\n /* Select-all checkbox cell */\n .dg-th-check {\n width: var(--size-5);\n min-width: var(--size-5);\n padding: var(--_cell-padding-y) var(--_cell-padding-x);\n }\n\n .dg-th-check,\n .dg-td-check {\n vertical-align: middle;\n text-align: center;\n }\n\n .dg-td.dg-td-check {\n padding: var(--size-1) 0 0;\n }\n\n /* ore-checkbox used for select-all and row checkboxes — label-less, compact */\n .dg-check {\n display: inline-flex;\n gap: 0;\n align-items: center;\n justify-content: center;\n min-height: 0;\n cursor: pointer;\n }\n\n /* ── Body rows ────────────────────────────────────────────────────────────── */\n\n .dg-body .dg-tr {\n border-block-end: var(--border) solid var(--_border-color);\n transition: background var(--transition-fast);\n }\n\n .dg-body .dg-tr:hover:not([data-disabled], [aria-selected='true']) {\n background: var(--_row-hover-bg);\n }\n\n /* ── Selection ─────────────────────────────────────────────────────────────── */\n\n .dg-body .dg-tr[aria-selected='true'] {\n background: var(--_row-selected-bg);\n }\n\n .dg-body .dg-tr[data-selectable] {\n cursor: pointer;\n outline: none;\n }\n\n .dg-body .dg-tr[data-selectable]:focus-visible {\n box-shadow: inset 0 0 0 2px var(--_row-selected-border);\n }\n\n .dg-body .dg-tr[data-disabled] {\n pointer-events: none;\n opacity: 0.45;\n }\n\n /* Striped rows */\n :host([striped]) .dg-body .dg-tr:nth-child(even) {\n background: var(--_stripe-bg);\n }\n\n :host([striped]) .dg-body .dg-tr:nth-child(even)[aria-selected='true'] {\n background: var(--_row-selected-bg);\n }\n\n /* ── Body cells ────────────────────────────────────────────────────────────── */\n\n .dg-td {\n max-width: var(--datagrid-cell-max-width, 32ch);\n padding: var(--_cell-padding-y) var(--_cell-padding-x);\n overflow: hidden;\n text-overflow: ellipsis;\n vertical-align: middle;\n color: var(--color-contrast-800);\n white-space: nowrap;\n border-right: var(--border) solid var(--_border-color);\n\n &[data-align='center'] {\n text-align: center;\n }\n\n &[data-align='right'] {\n text-align: right;\n }\n }\n\n :host(:dir(rtl)) .dg-td,\n :dir(rtl) .dg-td {\n border-right: none;\n border-left: var(--border) solid var(--_border-color);\n }\n\n .dg-td:last-child,\n .dg-td.dg-td-check,\n .dg-td.dg-td-expand,\n .dg-td.dg-td-last {\n border-right: none;\n }\n\n :host(:dir(rtl)) .dg-td:last-child,\n :host(:dir(rtl)) .dg-td.dg-td-check,\n :host(:dir(rtl)) .dg-td.dg-td-expand,\n :host(:dir(rtl)) .dg-td.dg-td-last,\n :dir(rtl) .dg-td:last-child,\n :dir(rtl) .dg-td.dg-td-check,\n :dir(rtl) .dg-td.dg-td-expand,\n :dir(rtl) .dg-td.dg-td-last {\n border-left: none;\n }\n\n /* ── Empty state ──────────────────────────────────────────────────────────── */\n\n .dg-empty {\n padding: var(--size-12) var(--_cell-padding-x);\n font-size: var(--text-sm);\n color: var(--color-contrast-400);\n text-align: center;\n }\n\n .dg-empty-content {\n display: flex;\n flex-direction: column;\n gap: var(--size-4);\n align-items: center;\n justify-content: center;\n }\n\n .dg-empty-actions {\n margin-top: var(--size-2);\n }\n\n /* ── Controls bar (tabs + action row) ───────────────────────────────────── */\n\n .dg-controls {\n display: flex;\n gap: var(--size-3);\n align-items: center;\n justify-content: space-between;\n height: var(--size-8);\n padding: var(--size-1-5) var(--_cell-padding-x);\n background: var(--_header-bg);\n border-block-end: var(--border) solid var(--_border-color);\n }\n\n /* ── Tab system (left) ───────────────────────────────────────────────────── */\n\n .dg-tabs {\n display: flex;\n flex: 1;\n gap: var(--size-1);\n align-items: center;\n min-width: 0;\n overflow: hidden;\n }\n\n .dg-tab {\n --button-padding: var(--size-0-5) var(--size-2-5);\n --button-font-size: var(--text-xs);\n --button-color: var(--color-contrast-500);\n\n flex: 1;\n min-width: 0;\n }\n\n .dg-tab--active {\n --button-color: var(--color-contrast-900);\n --button-bg: color-mix(in oklch, var(--color-contrast-500) 10%, transparent);\n --button-border-color: var(--_border-color);\n --button-border: var(--border);\n\n font-weight: var(--font-semibold);\n }\n\n /* ── Action bar (right) ──────────────────────────────────────────────────── */\n\n .dg-actions {\n display: flex;\n flex-shrink: 0;\n gap: var(--size-0-5);\n align-items: center;\n }\n\n /* ── Shared icon button — used by action bar, search-expand clear, popover header icons ── */\n\n .dg-action-divider {\n display: inline-block;\n flex-shrink: 0;\n width: var(--border);\n height: var(--size-4);\n margin-inline: var(--size-1);\n background: var(--_border-color);\n\n &[hidden] {\n display: none;\n }\n }\n\n .dg-filter {\n display: block;\n width: 100%;\n }\n\n /* ── Search toggle (rightmost action) ───────────────────────────────────── */\n\n .dg-search {\n display: flex;\n flex-direction: row-reverse;\n gap: var(--size-1);\n align-items: center;\n }\n\n .dg-search-input {\n display: block;\n flex-shrink: 0;\n width: 0;\n overflow: hidden;\n opacity: 0;\n transition:\n width var(--transition-fast),\n opacity var(--transition-fast);\n\n --input-height: var(--size-7);\n }\n\n .dg-search--open .dg-search-input {\n width: 12rem;\n overflow: visible;\n opacity: 1;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .dg-search-input {\n transition: none;\n }\n }\n\n /* ── ore-popover: action popover wrapper ─────────────────────────────────── */\n\n .dg-action-popover {\n display: inline-flex;\n }\n\n /* ── Popover content: shared header row ─────────────────────────────────── */\n\n .dg-pop-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--size-3) var(--size-3) var(--size-2);\n }\n\n .dg-pop-title {\n font-size: var(--text-xs);\n font-weight: var(--font-semibold);\n color: var(--color-contrast-600);\n letter-spacing: 0.02em;\n }\n\n /* ── Sort / Group by popover content ────────────────────────────────────── */\n\n .dg-pop-sort {\n display: flex;\n flex-direction: column;\n padding-block-end: var(--size-2);\n }\n\n .dg-pop-sort-row {\n display: flex;\n gap: var(--size-2);\n align-items: center;\n padding: var(--size-1) var(--size-3);\n }\n\n .dg-pop-select {\n --select-min-width: var(--size-20);\n\n flex: 2;\n }\n\n .dg-pop-dir-select {\n --select-min-width: var(--size-10);\n\n flex: 1;\n }\n\n /* ── Filter popover content ──────────────────────────────────────────────── */\n\n .dg-pop-filter {\n display: flex;\n flex-direction: column;\n }\n\n /* Field picker: select columns to add filter rules. */\n .dg-pop-filter-fields {\n padding: 0 var(--size-3) var(--size-3);\n }\n\n /* ── Filter rules section ────────────────────────────────────────────────── */\n\n .dg-pop-filter-rules {\n padding-block-start: var(--size-1);\n border-block-start: var(--border) solid var(--_border-color);\n\n &[hidden] {\n display: none;\n }\n }\n\n .dg-pop-filter-rule {\n display: flex;\n flex-direction: column;\n gap: var(--size-2);\n padding: var(--size-2) var(--size-3);\n }\n\n .dg-pop-filter-rule-header {\n display: flex;\n gap: var(--size-1-5);\n align-items: center;\n }\n\n .dg-pop-filter-field {\n font-size: var(--text-xs);\n font-weight: var(--font-semibold);\n color: var(--color-contrast-800);\n white-space: nowrap;\n }\n\n .dg-pop-filter-op-select {\n --select-min-width: 0;\n --select-height: var(--size-6);\n --select-font-size: var(--text-2xs);\n --select-padding-x: var(--size-1-5);\n\n flex: 1;\n min-width: 6rem;\n }\n\n .dg-pop-col-item {\n --button-radius: var(--rounded-md);\n\n justify-content: flex-start;\n }\n\n .dg-pop-col-list {\n display: flex;\n flex-wrap: wrap;\n gap: var(--size-1);\n max-width: 25rem;\n padding: var(--size-3);\n }\n\n /* ── Footer / pagination bar ─────────────────────────────────────────────── */\n\n .dg-footer {\n display: flex;\n gap: var(--size-2);\n align-items: center;\n padding: var(--size-2) var(--_cell-padding-x);\n font-size: var(--text-xs);\n color: var(--color-contrast-500);\n background: var(--_header-bg);\n }\n\n .dg-footer-info {\n white-space: nowrap;\n }\n\n .dg-footer-end {\n display: flex;\n gap: var(--size-2);\n align-items: center;\n width: fit-content;\n margin-inline-start: auto;\n }\n\n .dg-page-size-wrap {\n flex-shrink: 0;\n width: 5rem;\n }\n\n .dg-page-size-select {\n --select-min-width: 0;\n --select-height: var(--size-7);\n --select-font-size: var(--text-xs);\n --select-padding-x: var(--size-2);\n }\n\n .dg-pagination {\n display: flex;\n gap: var(--size-1);\n align-items: center;\n }\n\n :host(:dir(rtl)) .dg-page-btn,\n :dir(rtl) .dg-page-btn {\n transform: scaleX(-1);\n }\n\n .dg-page-btn {\n --button-color: var(--color-contrast-600);\n --button-radius: var(--rounded-md);\n\n width: var(--size-7);\n height: var(--size-7);\n }\n\n .dg-page-btn:hover {\n --button-color: var(--color-contrast-900);\n --button-bg: var(--color-contrast-300);\n }\n\n .dg-page-btn:disabled {\n cursor: not-allowed;\n opacity: 0.35;\n }\n\n .dg-page-label {\n padding-inline: var(--size-1);\n white-space: nowrap;\n }\n\n /* ── Column resize handle (F4) ───────────────────────────────────────────── */\n\n .dg-col-resize {\n position: absolute;\n inset-block: calc(var(--_cell-padding-y) * -1);\n inset-inline-end: calc((var(--_cell-padding-x) + var(--border) + 2px) * -1);\n width: var(--size-1);\n cursor: col-resize;\n user-select: none;\n background: transparent;\n border-radius: var(--rounded);\n transition: background var(--transition-fast);\n }\n\n .dg-col-resize:hover,\n .dg-col-resize:active {\n background: var(--_accent, var(--color-contrast-300));\n }\n\n /* ── Cell keyboard focus (ARIA grid roving tabindex) ─────────────────────── */\n\n .dg-td:focus-visible,\n .dg-th:focus-visible {\n outline: 2px solid var(--_row-selected-border);\n outline-offset: -2px;\n }\n\n /* ── Row expansion ────────────────────────────────────────────────────────── */\n\n .dg-tr-expanded .dg-td-expanded {\n padding: var(--_cell-padding-y) var(--_cell-padding-x);\n border: none;\n\n /* Paint background + bottom separator via box-shadow so it is\n direction-agnostic and covers the host outer border on both sides. */\n box-shadow:\n inset 0 0 0 9999px color-mix(in oklch, var(--color-contrast-600) 4%, var(--_bg, transparent)),\n inset 0 calc(var(--border) * -1) 0 var(--_border-color);\n }\n\n .dg-tr-expanded:last-child .dg-td-expanded {\n box-shadow: inset 0 0 0 9999px color-mix(in oklch, var(--color-contrast-900) 4%, var(--_bg, transparent));\n }\n\n .dg-tr:has(+ .dg-tr-expanded) {\n border-block-end: none;\n }\n\n .dg-th-expand,\n .dg-td-expand {\n width: var(--size-8);\n min-width: var(--size-8);\n padding-block: var(--size-1) 0;\n padding-inline: 0 var(--size-2);\n text-align: center;\n white-space: nowrap;\n border-right: none;\n border-left: none;\n }\n\n .dg-expand-btn {\n --button-color: var(--color-contrast-500);\n --button-radius: var(--rounded-sm);\n\n width: var(--size-5);\n height: var(--size-5);\n }\n\n .dg-expand-btn:hover {\n --button-color: var(--color-contrast-900);\n }\n\n .dg-expand-btn:disabled {\n cursor: not-allowed;\n opacity: 0.4;\n }\n\n /* ── Loading overlay ──────────────────────────────────────────────────────── */\n\n .dg-loading-overlay {\n position: absolute;\n inset: 0;\n z-index: 3;\n display: none;\n align-items: center;\n justify-content: center;\n background: color-mix(in oklch, var(--_bg, white) 40%, transparent);\n backdrop-filter: blur(1px);\n }\n\n :host([loading]) .dg-loading-overlay {\n display: flex;\n }\n\n :host([loading]) .dg-scroll table {\n pointer-events: none;\n opacity: 0.5;\n }\n\n .dg-spin {\n animation: dg-spin 1s linear infinite;\n }\n\n @keyframes dg-spin {\n from {\n transform: rotate(0deg);\n }\n\n to {\n transform: rotate(360deg);\n }\n }\n}\n","import { debounce } from '@vielzeug/arsenal';\nimport { define, html, prop } from '@vielzeug/ore';\nimport { raw } from '@vielzeug/ore/directives';\nimport { computed, signal, watch } from '@vielzeug/ripple';\n\nimport { warn } from '../../_dev';\nimport '../../content/icon/icon';\nimport '../../inputs/button/button';\nimport '../../inputs/checkbox/checkbox';\nimport '../../inputs/combobox/combobox';\nimport '../../inputs/select/select';\nimport '../../overlay/popover/popover';\nimport {\n lifecycleSignal,\n createDataGridControl,\n type DataGridColumn,\n type DataGridControl,\n type SelectionMode,\n type SortDirection,\n type SortState,\n} from '../../headless';\nimport { disablableBundle, loadableBundle } from '../../shared';\nimport { tableBaseMixin } from '../../styles';\nimport { COLUMN_OBSERVED_ATTRS, parseColumnChildren } from './datagrid-column';\nimport { createDataGridControls, type FilterOption, type DataGridView, type FilterOperator } from './datagrid-controls';\nimport { type GridNavHandle, createGridNav } from './datagrid-nav';\nimport componentStyles from './datagrid.css?inline';\n\ntype SortMode = 'client' | 'server';\n\nexport { COLUMN_TAG } from './datagrid-column';\nexport type { DataGridView, FilterOption, FilterOperator } from './datagrid-controls';\n\n// ── Pure module-level helpers ─────────────────────────────────────────────────\n\n/**\n * Returns the Lucide icon name for a column's sort state.\n * Pure function — no closure dependency on ctrl.\n */\nexport function sortIconName(state: SortState, key: string): string {\n if (state.key !== key || state.direction === 'none') return 'chevrons-up-down';\n\n return state.direction === 'asc' ? 'chevron-up' : 'chevron-down';\n}\n\n/**\n * Returns the WAI-ARIA `aria-sort` value for a column.\n * Pure function — independently unit-testable.\n */\nexport function ariaSortValue(state: SortState, key: string): 'ascending' | 'descending' | 'none' {\n if (state.key !== key || state.direction === 'none') return 'none';\n\n return state.direction === 'asc' ? 'ascending' : 'descending';\n}\n\n// ── Types ──────────────────────────────────────────────────────────────────────\n\nexport type OreDataGridEvents<T = Record<string, unknown>> = {\n /** Fired when the user cycles the density via the toolbar button. */\n 'density-change': { density: 'compact' | 'cozy' | 'comfortable' };\n /** Fired when the active page changes. */\n 'page-change': { pageIndex: number; pageSize: number };\n /** Fired when a row is expanded or collapsed. */\n 'row-expand': { expanded: boolean; key: string };\n /** Fired when row selection changes. */\n 'selection-change': { keys: string[]; rows: T[] };\n /** Fired when the sort column or direction changes. */\n 'sort-change': { direction: SortDirection; key: string };\n /** Fired when the active view tab changes. detail: { id, label } */\n 'view-change': { id: string; label: string };\n};\n\nexport type OreDataGridProps<T = Record<string, unknown>> = {\n /**\n * The ID of the currently active view. Must match an `id` in `views`.\n * When omitted, no view is active (all data shown).\n * @example `grid.activeView = 'open'`\n */\n activeView?: string;\n /**\n * Column definitions (imperative API). Takes precedence over `<ore-column>` children.\n * Passing `[]` explicitly clears declarative children.\n * Pass `undefined` (or omit) to use `<ore-column>` children instead.\n * @example\n * ```js\n * grid.columns = [\n * { key: 'name', label: 'Name', sortable: true },\n * { key: 'email', label: 'Email' },\n * ];\n * ```\n */\n columns?: DataGridColumn<T>[];\n /** Cell density: `'compact'` | `'cozy'` (default) | `'comfortable'` */\n density?: 'compact' | 'cozy' | 'comfortable';\n /** Disable all interaction. */\n disabled?: boolean;\n /** Text shown when there are no rows. */\n emptyText?: string;\n /**\n * Enable row expansion. When set, each row gets a toggle button.\n * Requires at least one column to have a `renderExpanded` function.\n *\n * @security The `renderExpanded` callback's returned HTML string is inserted via ore's\n * `raw()` directive (participates in `setRawSanitizer()` if one is registered). If data\n * originates from untrusted user input, sanitize it before returning\n * (e.g. with DOMPurify or your CSP-compliant sanitizer).\n */\n expandable?: boolean;\n /**\n * Pre-defined filter option definitions per column key.\n * When provided, these options replace the auto-derived ones in the Filter popover.\n * @example\n * ```js\n * grid.filterOptions = [\n * { key: 'role', label: 'Role', options: [{ value: 'Admin' }, { value: 'Editor' }] },\n * ];\n * ```\n */\n filterOptions?: FilterOption[];\n /** Stretch the grid to fill its container's width. */\n fullwidth?: boolean;\n /**\n * Function that returns a unique string key per row.\n * Defaults to `(row) => String(row['id'])`.\n */\n getRowKey?: (row: T) => string;\n /** Accessible label for the grid. Recommended for screen readers. */\n label?: string;\n /** Show a busy/loading state with reduced opacity. */\n loading?: boolean;\n /** Number of rows per page. Defaults to `10`. Set to `0` to disable pagination. */\n pageSize?: number;\n /**\n * Options for the per-page size selector rendered in the footer.\n * When provided, a `ore-select` is shown next to the pagination controls.\n * @example `grid.pageSizeOptions = [10, 25, 50, 100]`\n */\n pageSizeOptions?: number[];\n /**\n * Row data. Pass as a JS property — not serialisable to an HTML attribute.\n * @example\n * ```js\n * grid.rows = [{ id: '1', name: 'Alice', email: 'alice@example.com' }];\n * ```\n */\n rows?: T[];\n /**\n * Accessible label for the search toggle button. Supports localization.\n * Defaults to `'Search'` (open) and `'Close search'` (close).\n * Pass a tuple `[openLabel, closeLabel]` to override both.\n * @example `grid.searchLabel = ['Suchen', 'Suche schließen']`\n */\n searchLabel?: [open: string, close: string];\n /** Placeholder text for the inline search input in the controls bar. */\n searchPlaceholder?: string;\n /**\n * Pre-selected row keys. Setting this from outside will update the internal selection.\n * @example `grid.selectedKeys = ['1', '3']`\n */\n selectedKeys?: string[];\n /** Row selection mode. */\n selectionMode?: SelectionMode;\n /**\n * Whether sorting is client-side (default) or server-side.\n * When `'server'`, `sort-change` fires but items are not sorted by the control.\n */\n sortMode?: SortMode;\n /**\n * A reactive data source from `@vielzeug/sourcerer` (or any compatible object).\n * When set, the source drives row data, pagination, and search — the `rows` prop is ignored.\n * Client-side sort and filter are bypassed; wire `sort-change` to `source.patch()` externally.\n * @example\n * ```js\n * import { createRemoteSource } from '@vielzeug/sourcerer';\n * const source = createRemoteSource({ fetch: (q, sig) => api.users(q, sig), limit: 20 });\n * grid.source = source;\n * ```\n */\n source?: DataGridSource<T>;\n /** Apply alternating row backgrounds. */\n striped?: boolean;\n /**\n * Named view definitions for the controls bar tab strip.\n * Each view is a label displayed as a tab; switching tabs fires `view-change`.\n * The consumer is responsible for restoring filter/sort state per view.\n * @example\n * ```js\n * grid.views = [\n * { id: 'all', label: 'All' },\n * { id: 'open', label: 'Open' },\n * { id: 'mine', label: 'Mine' },\n * ];\n * grid.activeView = 'all';\n * ```\n */\n views?: DataGridView[];\n};\n\n/**\n * An accessible, keyboard-navigable data grid with sorting, pagination,\n * single/multi row selection, inline search, filter, and named views.\n *\n * @element ore-datagrid\n * @element ore-column - Optional declarative column definition child\n *\n * @attr {boolean} disabled - Disable all interaction\n * @attr {boolean} loading - Show busy/loading state\n * @attr {boolean} striped - Apply alternating row backgrounds\n * @attr {boolean} fullwidth - Stretch the grid to fill its container's width\n * @attr {data} search-label - Tuple [openLabel, closeLabel] for the search toggle button\n * @attr {string} search-placeholder - Placeholder for the inline search input\n * @attr {number} page-size - Rows per page (0 = no pagination, default 10)\n * @attr {string} selection-mode - Row selection: 'none' | 'single' | 'multi'\n * @attr {string} sort-mode - Sorting: 'client' (default) | 'server'\n * @attr {string} density - Cell density: compact | cozy (default) | comfortable\n * @attr {string} empty-text - Text shown when there are no rows\n * @attr {string} label - Accessible label for the grid\n * @attr {string} active-view - ID of the currently active view tab\n *\n * @fires selection-change - Fired when row selection changes. detail: { keys: string[], rows: T[] }\n * @fires sort-change - Fired when sort state changes. detail: { key: string, direction: SortDirection }\n * @fires page-change - Fired when page changes. detail: { pageIndex: number, pageSize: number }\n * @fires row-expand - Fired when a row is expanded or collapsed. detail: { expanded: boolean; key: string }\n * @fires view-change - Fired when the active view tab changes. detail: { id: string, label: string }\n *\n * @cssprop --datagrid-bg - Grid background color\n * @cssprop --datagrid-border-color - Grid and cell border color\n * @cssprop --datagrid-radius - Grid border radius\n * @cssprop --datagrid-shadow - Grid box shadow\n * @cssprop --datagrid-header-bg - Column header background\n * @cssprop --datagrid-row-hover-bg - Row hover background\n * @cssprop --datagrid-row-selected-bg - Selected row background\n * @cssprop --datagrid-stripe-bg - Even-row stripe background\n * @cssprop --datagrid-cell-padding-x - Cell horizontal padding\n * @cssprop --datagrid-cell-padding-y - Cell vertical padding\n * @cssprop --datagrid-cell-max-width - Maximum cell content width before truncating\n * @cssprop --datagrid-max-height - Max scrollable height of the table area\n * @cssprop --datagrid-font-size - Base font size for cells\n *\n * @part controls - The controls bar (tabs + action row)\n * @part table - The `<table>` element\n * @part thead - The `<thead>` element\n * @part tbody - The `<tbody>` element\n * @part row - A body `<tr>` element\n * @part cell - A body `<td>` element\n * @part footer - The pagination footer bar\n *\n * @example\n * ```html\n * <ore-datagrid id=\"grid\" label=\"Users\" selection-mode=\"multi\"></ore-datagrid>\n * <script>\n * const grid = document.getElementById('grid');\n * grid.columns = [\n * { key: 'name', label: 'Name', sortable: true },\n * { key: 'role', label: 'Role' },\n * ];\n * grid.rows = [\n * { id: '1', name: 'Alice', role: 'Admin' },\n * { id: '2', name: 'Bob', role: 'Viewer' },\n * ];\n * grid.views = [{ id: 'all', label: 'All' }, { id: 'open', label: 'Open' }];\n * grid.activeView = 'all';\n * </script>\n * ```\n */\n/**\n * Minimal structural interface for a reactive data source accepted by `ore-datagrid`.\n *\n * Any `@vielzeug/sourcerer` source (`LocalSource<T>`, `RemoteSource<T>`, `PageNavigator<T>`)\n * satisfies this interface automatically — no direct sourcerer import is required in refine.\n *\n * When `source` is set on the grid:\n * - `rows` prop is ignored; `source.current` drives the displayed items.\n * - Pagination is driven by `source.meta` (pageCount, pageNumber, totalItems).\n * - Prev/next buttons call `source.prev()` / `source.next()`.\n * - The search input calls `source.search(query)` when available.\n * - `source.meta.isLoading` contributes to the grid's `aria-busy` state.\n * - Client-side sort and filter are bypassed; wire `sort-change` to `source.patch()` externally.\n *\n * @example\n * ```ts\n * import { createRemoteSource } from '@vielzeug/sourcerer';\n *\n * const source = createRemoteSource({\n * fetch: (q, signal) =>\n * fetch(`/api/users?page=${q.page}&limit=${q.limit}&search=${q.search ?? ''}`, { signal })\n * .then(r => r.json()),\n * limit: 20,\n * });\n *\n * const grid = document.querySelector('ore-datagrid');\n * grid.source = source;\n * ```\n */\nexport type DataGridSource<T = Record<string, unknown>> = {\n /** Current page of items. Updated reactively after each fetch or patch. */\n readonly current: readonly T[];\n /** Navigate to a specific 1-indexed page number. */\n goTo?(page: number): Promise<void>;\n /** Pagination and loading metadata. */\n readonly meta: {\n readonly error: { message: string } | null;\n readonly isLoading: boolean;\n readonly pageCount: number;\n readonly pageNumber: number;\n readonly pageSize: number;\n readonly totalItems: number;\n };\n /** Navigate to the next page. No-op when on the last page. */\n next?(): Promise<void>;\n /** Navigate to the previous page. No-op when on the first page. */\n prev?(): Promise<void>;\n /** Debounced text search. No-op when not implemented by the source. */\n search?(query: string, opts?: { immediate?: boolean }): Promise<void>;\n /** Subscribe to source updates. Returns an unsubscribe function. */\n subscribe(listener: () => void): () => void;\n};\n\nexport const DATAGRID_TAG = 'ore-datagrid' as const;\n\ndefine<OreDataGridProps, OreDataGridEvents>(DATAGRID_TAG, {\n props: {\n activeView: prop.string(),\n density: prop.string<'compact' | 'cozy' | 'comfortable'>(),\n ...disablableBundle,\n ...loadableBundle,\n columns: prop.data<DataGridColumn[]>(),\n emptyText: prop.string('No data'),\n expandable: prop.bool(false),\n filterOptions: prop.data<FilterOption[]>(),\n fullwidth: prop.bool(false),\n getRowKey: prop.data<(row: Record<string, unknown>) => string>(),\n label: prop.string(),\n pageSize: prop.number(10),\n pageSizeOptions: prop.data<number[]>(),\n rows: prop.data<Record<string, unknown>[]>(),\n searchLabel: prop.data<[string, string]>(),\n searchPlaceholder: prop.string('Search…'),\n selectedKeys: prop.data<string[]>(),\n selectionMode: prop.string<SelectionMode>('none'),\n sortMode: prop.string<SortMode>('client'),\n source: prop.data<DataGridSource>(),\n striped: prop.bool(false),\n views: prop.data<DataGridView[]>(),\n },\n\n setup(props, { el, emit, onCleanup, onMounted, slots }) {\n const isDisabled = computed(() => props.disabled.value === true);\n const selectionMode = computed(() => props.selectionMode.value ?? 'none');\n\n // ── Row expansion (hoisted — needed by checkOffset + effectiveColCount) ──\n const expandedKeys = signal(new Set<string>());\n\n // resolvedColumns is declared further below; this callback is lazy and only\n // evaluates when .value is first read (after setup completes), so the\n // forward closure reference is safe at runtime.\n const hasExpander = computed(\n () =>\n props.expandable.value === true && resolvedColumns.value.some((c) => typeof c.renderExpanded === 'function'),\n );\n\n const checkOffset = computed(() => (selectionMode.value === 'multi' ? 1 : 0));\n\n // ── Page size ────────────────────────────────────────────────────────\n // Signal driven by the `page-size` prop. Stays in sync with prop changes\n // so consumers can set grid.pageSize = n reactively after mount.\n // The per-page size selector also writes to this signal directly.\n const pageSize = signal<number>(props.pageSize.value ?? 10);\n\n watch(props.pageSize, (n) => {\n if (n != null) pageSize.value = n;\n });\n\n // ── Declarative ore-column children ─────────────────────────────────────\n // A writable signal holding columns parsed from <ore-column> children.\n // Updated on mount and whenever children change. The JS `columns` prop\n // takes precedence when explicitly set (non-empty).\n const declarativeColumns = signal<DataGridColumn[]>([]);\n\n onMounted(() => {\n declarativeColumns.value = parseColumnChildren(el);\n\n const columnObserver = new MutationObserver(() => {\n declarativeColumns.value = parseColumnChildren(el);\n });\n\n columnObserver.observe(el, {\n attributeFilter: COLUMN_OBSERVED_ATTRS as unknown as string[],\n attributes: true,\n childList: true,\n subtree: true,\n });\n\n return () => columnObserver.disconnect();\n });\n\n // Resolved columns: prop wins when explicitly set (even to []); undefined = not set → use declarative children.\n const resolvedColumns = computed<DataGridColumn[]>(() => {\n const propCols = props.columns.value;\n\n return propCols !== undefined ? propCols : declarativeColumns.value;\n });\n\n // ── Key resolution ─────────────────────────────────────────────────────────\n // Reads getRowKey prop dynamically so changes after mount are reflected.\n\n const resolveKey = (item: Record<string, unknown>): string => {\n const fn = props.getRowKey.value;\n\n if (fn) return fn(item);\n\n const id = item['id'];\n\n if (id == null) {\n warn('ore-datagrid: row missing `id` — keys will collide. Provide `getRowKey` or add a unique `id` field.');\n\n return `__missing_${Math.random().toString(36).slice(2)}`;\n }\n\n return String(id);\n };\n\n // ── Controls (search, filter, column visibility) ──────────────────────────\n // Extracted into a dedicated headless module so this scope stays focused\n // on table rendering machinery.\n\n const controls = createDataGridControls({\n columns: resolvedColumns,\n filterOptions: props.filterOptions,\n rows: computed(() => props.rows.value ?? []),\n });\n\n const debouncedSearch = debounce((q: unknown) => {\n // `debounce`'s generic constraint requires the parameter type to accept `unknown`;\n // the only call site below always passes the search input's string value.\n const query = q as string;\n const src = props.source.value;\n\n if (src?.search) void src.search(query);\n else controls.setSearchQuery(query);\n }, 250);\n\n // ── Reactive source bridge ────────────────────────────────────────────────\n // When `source` is provided it drives rows, pagination, and search.\n // The `rows` prop and client-side filter pipeline are bypassed.\n\n type SourceMetaState = {\n error: { message: string } | null;\n isLoading: boolean;\n pageCount: number;\n pageNumber: number;\n pageSize: number;\n totalItems: number;\n };\n\n const hasSource = computed(() => props.source.value != null);\n const sourceItems = signal<Record<string, unknown>[]>([]);\n const sourceMeta = signal<SourceMetaState>({\n error: null,\n isLoading: false,\n pageCount: 1,\n pageNumber: 1,\n pageSize: pageSize.value,\n totalItems: 0,\n });\n\n let _sourceUnsub: (() => void) | null = null;\n\n onCleanup(() => {\n _sourceUnsub?.();\n _sourceUnsub = null;\n });\n\n watch(\n props.source,\n (src) => {\n _sourceUnsub?.();\n _sourceUnsub = null;\n\n if (!src) {\n sourceItems.value = [];\n sourceMeta.value = {\n error: null,\n isLoading: false,\n pageCount: 1,\n pageNumber: 1,\n pageSize: pageSize.value,\n totalItems: 0,\n };\n\n return;\n }\n\n const update = (): void => {\n sourceItems.value = src.current as Record<string, unknown>[];\n sourceMeta.value = src.meta as SourceMetaState;\n };\n\n update();\n _sourceUnsub = src.subscribe(update);\n },\n { immediate: true },\n );\n\n // Items fed to ctrl: source.current when source is active, filtered rows otherwise.\n const itemsForCtrl = computed<Record<string, unknown>[]>(() =>\n hasSource.value ? sourceItems.value : controls.filteredRows.value,\n );\n\n // ── Headless control ──────────────────────────────────────────────────────\n\n const ctrl: DataGridControl = createDataGridControl({\n columns: () => resolvedColumns.value,\n getRowKey: resolveKey,\n items: itemsForCtrl,\n onSelectionChange: (keys: Set<string>) => {\n emit('selection-change', { keys: [...keys], rows: ctrl.selectedRows.value as Record<string, unknown>[] });\n },\n onSortChange: (sort) => {\n emit('sort-change', sort);\n },\n pageSize: () => (hasSource.value ? 0 : pageSize.value),\n selectionMode: () => selectionMode.value,\n signal: lifecycleSignal(onCleanup),\n });\n\n // ── Sync external selected-keys prop into ctrl ────────────────────────────\n\n watch(\n props.selectedKeys,\n (keys) => {\n if (Array.isArray(keys)) ctrl.setSelection(new Set(keys));\n },\n { immediate: true },\n );\n\n // ── Column resize (F4) ───────────────────────────────────────────────────\n // Stores user-dragged widths as { key → px } so they survive re-renders.\n // Only columns with `resizable: true` get a drag handle.\n\n const colWidths = signal<Record<string, number>>({});\n\n const createColResizeHandler =\n (key: string, th: HTMLElement): ((e: PointerEvent) => void) =>\n (e: PointerEvent): void => {\n e.preventDefault();\n\n const startX = e.clientX;\n const startW = th.getBoundingClientRect().width;\n // AbortController ensures listeners are removed even if the component\n // is destroyed mid-drag (e.g. during SPA navigation).\n const ac = new AbortController();\n const { signal: sig } = ac;\n\n window.addEventListener(\n 'pointermove',\n (mv: PointerEvent) => {\n colWidths.value = { ...colWidths.value, [key]: Math.max(40, startW + mv.clientX - startX) };\n },\n { signal: sig },\n );\n\n window.addEventListener('pointerup', () => ac.abort(), { signal: sig });\n };\n\n // ── Visible columns (respects hide/show from column menu) ────────────────\n\n const visibleColumns = computed<DataGridColumn[]>(() =>\n resolvedColumns.value.filter((c) => !controls.hiddenColumns.value.has(c.key)),\n );\n\n // ── Cell value helper ────────────────────────────────────────────────────\n\n const getCellValue = (col: DataGridColumn, item: Record<string, unknown>): string => {\n if (col.cell) return col.cell(item);\n\n const v = item[col.key];\n\n return v == null ? '' : String(v);\n };\n\n // B4: reactive page reset — any change to the filtered result set resets to page 0.\n // Removes the need to call ctrl.goToPage(0) manually in every event handler.\n watch(controls.filteredRows, () => ctrl.goToPage(0), { immediate: false });\n\n // ── Pagination handlers ───────────────────────────────────────────────────\n\n function handlePage(direction: 'next' | 'prev'): void {\n const src = props.source.value;\n\n if (src) {\n if (direction === 'prev') void src.prev?.();\n else void src.next?.();\n\n return;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n direction === 'prev' ? ctrl.prevPage() : ctrl.nextPage();\n emit('page-change', { pageIndex: ctrl.pageIndex.value, pageSize: pageSize.value });\n }\n\n // ── Select-all helpers ────────────────────────────────\n\n const isSomeSelected = computed(() => {\n const page = ctrl.currentPageItems.value;\n\n if (!page.length || ctrl.isAllSelected()) return false;\n\n return page.some((item) => ctrl.selectedKeys.value.has(resolveKey(item as Record<string, unknown>)));\n });\n\n // ── Column count (used in keyboard nav + empty colspan) ───────────────────\n\n const effectiveColCount = computed(\n () => visibleColumns.value.length + (selectionMode.value === 'multi' ? 1 : 0) + (hasExpander.value ? 1 : 0),\n );\n\n // ── Pagination info text ──────────────────────────────────────────────────\n\n const paginationEnabled = computed(() => {\n if (hasSource.value) return sourceMeta.value.pageCount > 1;\n\n return pageSize.value > 0;\n });\n\n const paginationInfo = computed(() => {\n if (hasSource.value) {\n const { pageNumber, pageSize: pSize, totalItems } = sourceMeta.value;\n const safePSize = Math.max(1, pSize);\n\n if (!paginationEnabled.value) return `${totalItems} row${totalItems !== 1 ? 's' : ''}`;\n\n if (totalItems === 0) return '0 to 0 of 0';\n\n const start = (pageNumber - 1) * safePSize + 1;\n const end = Math.min(start + safePSize - 1, totalItems);\n\n return `${start} to ${end} of ${totalItems}`;\n }\n\n const total = ctrl.totalItems.value;\n\n if (!paginationEnabled.value) return `${total} row${total !== 1 ? 's' : ''}`;\n\n if (total === 0) return '0 to 0 of 0';\n\n const start = ctrl.pageIndex.value * pageSize.value + 1;\n const end = Math.min(start + pageSize.value - 1, total);\n\n return `${start} to ${end} of ${total}`;\n });\n\n // ── Source-aware loading and pagination helpers ───────────────────────────\n\n const isLoading = computed(() => props.loading.value === true || (hasSource.value && sourceMeta.value.isLoading));\n\n const effectiveHasPrev = computed(() =>\n hasSource.value ? sourceMeta.value.pageNumber > 1 : ctrl.hasPrevPage.value,\n );\n\n const effectiveHasNext = computed(() =>\n hasSource.value ? sourceMeta.value.pageNumber < sourceMeta.value.pageCount : ctrl.hasNextPage.value,\n );\n\n const effectivePageLabel = computed(() => {\n if (hasSource.value) {\n return sourceMeta.value.totalItems === 0\n ? '0 / 0'\n : `${sourceMeta.value.pageNumber} / ${sourceMeta.value.pageCount}`;\n }\n\n return `${ctrl.pageIndex.value + 1} / ${ctrl.pageCount.value}`;\n });\n\n // ── Density toggle (E5) ──────────────────────────────────────────────────\n // Local signal so the toolbar button can cycle density without requiring\n // the consumer to wire up an external prop. Stays in sync with the `density`\n // prop: prop changes win; button clicks write back to the host attribute so\n // the CSS layer picks them up immediately.\n\n type Density = 'compact' | 'cozy' | 'comfortable';\n\n const DENSITY_CYCLE: Density[] = ['compact', 'cozy', 'comfortable'];\n const DENSITY_ICONS: Record<Density, string> = {\n comfortable: 'rows-2',\n compact: 'rows-4',\n cozy: 'rows-3',\n };\n const DENSITY_LABELS: Record<Density, string> = {\n comfortable: 'Density: Comfortable',\n compact: 'Density: Compact',\n cozy: 'Density: Cozy',\n };\n\n const densitySignal = signal<Density>(props.density.value ?? 'cozy');\n\n watch(props.density, (d) => {\n if (d) densitySignal.value = d;\n });\n\n const cycleDensity = (): void => {\n const idx = DENSITY_CYCLE.indexOf(densitySignal.value);\n const next = DENSITY_CYCLE[(idx + 1) % DENSITY_CYCLE.length]!;\n\n densitySignal.value = next;\n el.setAttribute('density', next);\n emit('density-change', { density: next });\n };\n\n // ── Filter badge hover state ────────────────────────────────────────────\n // Drives the dot↔count toggle on the filter toolbar badge: dot at rest,\n // count on hover/focus so the number is revealed on interaction only.\n const filterBadgeActive = signal(false);\n\n // ── Row expansion (toggle handler) ───────────────────────────────────────\n\n const toggleExpand = (key: string): void => {\n const next = new Set(expandedKeys.value);\n const expanded = !next.has(key);\n\n // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n expanded ? next.add(key) : next.delete(key);\n expandedKeys.value = next;\n emit('row-expand', { expanded, key });\n };\n\n // ── Keyboard cell navigation (roving tabindex — extracted to datagrid-nav.ts) ──\n // navHandle is initialised with a real sentinel signal so the first render\n // produces correct tabindex values (row=0, col=0 → '0') before onMounted.\n // onMounted replaces it with the live handle from createGridNav.\n\n let navHandle: GridNavHandle = {\n activeCell: signal({ col: 0, row: 0 }),\n focusCell: () => {},\n };\n\n onMounted(() => {\n const shadow = el.shadowRoot!;\n const table = shadow.querySelector<HTMLElement>('.dg-table');\n\n if (!table) return;\n\n const { cleanup, handle } = createGridNav(table, shadow);\n\n navHandle = handle;\n\n return cleanup;\n });\n\n // Expose programmatic focusCell API on the host element (F6)\n (el as HTMLElement & { focusCell: (pos: { col: number; row: number }) => void }).focusCell = (pos) =>\n navHandle.focusCell(pos);\n\n // ── Render helpers ────────────────────────────────────────────────────────\n // Each helper renders one self-contained region, closing only over the\n // signals it actually needs. This keeps the root template readable.\n\n const renderViewTabs = (): unknown => {\n const views = props.views.value ?? [];\n const activeId = props.activeView.value;\n\n return html`<div\n class=\"dg-tabs\"\n role=\"tablist\"\n aria-label=\"Views\"\n aria-controls=\"dg-tabpanel\"\n @keydown=\"${(e: KeyboardEvent) => {\n if (!['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(e.key)) return;\n\n const tabs = Array.from((e.currentTarget as HTMLElement).querySelectorAll('.dg-tab'));\n const activeIdx = tabs.findIndex((t) => t.classList.contains('dg-tab--active'));\n\n let nextIdx = activeIdx;\n\n if (e.key === 'ArrowLeft') nextIdx = Math.max(0, activeIdx - 1);\n else if (e.key === 'ArrowRight') nextIdx = Math.min(tabs.length - 1, activeIdx + 1);\n else if (e.key === 'Home') nextIdx = 0;\n else if (e.key === 'End') nextIdx = tabs.length - 1;\n\n if (nextIdx !== activeIdx) {\n e.preventDefault();\n\n const nextTab = tabs[nextIdx] as HTMLElement;\n\n nextTab.focus();\n nextTab.click();\n }\n }}\">\n ${views.map(\n (view) =>\n html`<ore-button\n class=\"${() => `dg-tab${activeId === view.id ? ' dg-tab--active' : ''}`}\"\n role=\"tab\"\n variant=\"ghost\"\n rounded=\"full\"\n size=\"sm\"\n :tabindex=\"${() => (activeId === view.id ? '0' : '-1')}\"\n :aria-selected=\"${() => String(activeId === view.id)}\"\n aria-controls=\"dg-tabpanel\"\n @click=\"${() => {\n emit('view-change', { id: view.id, label: view.label });\n }}\">\n ${view.label}\n </ore-button>`,\n )}\n </div>`;\n };\n\n const renderSortPopover = (): unknown =>\n html`<ore-popover class=\"dg-action-popover\" placement=\"bottom-end\" label=\"Sort\" style=\"--popover-min-width:18rem\">\n <ore-button variant=\"ghost\" size=\"sm\" icon-only label=\"Sort\">\n <ore-icon name=\"arrow-up-down\" size=\"15\" stroke-width=\"1.75\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n <div slot=\"content\" class=\"dg-pop-sort\">\n <div class=\"dg-pop-header\">\n <span class=\"dg-pop-title\">Sort by</span>\n <ore-button\n class=\"dg-icon-btn\"\n variant=\"ghost\"\n size=\"sm\"\n icon-only\n label=\"Clear sort\"\n :disabled=\"${() => ctrl.sortState.value.direction === 'none' || undefined}\"\n @click=\"${() => ctrl.sortTo('', 'none')}\">\n <ore-icon name=\"trash-2\" size=\"14\" stroke-width=\"1.75\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n </div>\n <div class=\"dg-pop-sort-row\">\n <ore-select\n class=\"dg-pop-select\"\n variant=\"flat\"\n size=\"sm\"\n rounded=\"lg\"\n placeholder=\"Property\"\n fullwidth\n :value=\"${() => ctrl.sortState.value.key}\"\n :options=\"${() => resolvedColumns.value.map((c) => ({ label: c.label, value: c.key }))}\"\n @change=\"${(e: CustomEvent<{ values: string[] }>) => {\n const key = e.detail.values[0] ?? '';\n const dir = ctrl.sortState.value.direction === 'none' ? 'asc' : ctrl.sortState.value.direction;\n\n ctrl.sortTo(key, dir);\n }}\"></ore-select>\n <ore-select\n class=\"dg-pop-dir-select\"\n variant=\"flat\"\n size=\"sm\"\n rounded=\"lg\"\n fullwidth\n :disabled=\"${() => !ctrl.sortState.value.key || undefined}\"\n :value=\"${() => (ctrl.sortState.value.direction === 'none' ? 'asc' : ctrl.sortState.value.direction)}\"\n :options=\"${() => [\n { label: 'A → Z', value: 'asc' },\n { label: 'Z → A', value: 'desc' },\n ]}\"\n @change=\"${(e: CustomEvent<{ values: string[] }>) => {\n if (ctrl.sortState.value.key) {\n ctrl.sortTo(ctrl.sortState.value.key, (e.detail.values[0] ?? 'asc') as 'asc' | 'desc');\n }\n }}\"></ore-select>\n </div>\n </div>\n </ore-popover>`;\n\n const renderFilterPopover = (): unknown =>\n html`<ore-popover\n class=\"dg-action-popover\"\n placement=\"bottom-end\"\n label=\"Filter\"\n style=\"--popover-min-width:16rem;--popover-max-height:min(90vh,48rem)\">\n ${() =>\n controls.filterDefs.value.length\n ? html`<ore-badge\n anchor=\"top-end\"\n color=\"primary\"\n size=\"xs\"\n :count=\"${() => (filterBadgeActive.value ? controls.filterDefs.value.length : undefined)}\"\n :dot=\"${() => !filterBadgeActive.value || undefined}\"\n :label=\"${() =>\n `${controls.filterDefs.value.length} active filter${controls.filterDefs.value.length > 1 ? 's' : ''}`}\"\n aria-hidden=\"true\"\n @mouseenter=\"${() => (filterBadgeActive.value = true)}\"\n @mouseleave=\"${() => (filterBadgeActive.value = false)}\"\n @focusin=\"${() => (filterBadgeActive.value = true)}\"\n @focusout=\"${() => (filterBadgeActive.value = false)}\">\n <ore-button slot=\"target\" variant=\"ghost\" size=\"sm\" icon-only label=\"Filter\">\n <ore-icon name=\"filter\" size=\"15\" stroke-width=\"1.75\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n </ore-badge>`\n : html`<ore-button class=\"dg-icon-btn\" variant=\"ghost\" size=\"sm\" icon-only label=\"Filter\">\n <ore-icon name=\"filter\" size=\"15\" stroke-width=\"1.75\" aria-hidden=\"true\"></ore-icon>\n </ore-button>`}\n <div slot=\"content\" class=\"dg-pop-filter\">\n <div class=\"dg-pop-header\">\n <span class=\"dg-pop-title\">Filter by</span>\n ${() =>\n controls.filterDefs.value.length\n ? html`<ore-button\n class=\"dg-icon-btn\"\n variant=\"ghost\"\n size=\"sm\"\n icon-only\n label=\"Clear all filters\"\n @click=\"${() => controls.clearAllFilters()}\">\n <ore-icon name=\"trash-2\" size=\"14\" stroke-width=\"1.75\" aria-hidden=\"true\"></ore-icon>\n </ore-button>`\n : html``}\n </div>\n\n <!-- Always-visible field picker: select columns to add filter rules -->\n <div class=\"dg-pop-filter-fields\">\n <ore-combobox\n placeholder=\"Add filter…\"\n multiple\n fullwidth\n autoclose\n :options=\"${() =>\n resolvedColumns.value.map((col) => ({\n label: col.label,\n value: col.key,\n }))}\"\n :value=\"${() => controls.filterDefs.value.map((f) => f.key)}\"\n @change=\"${(e: CustomEvent<{ values: string[] }>) => {\n controls.setActiveFilterKeys(e.detail.values);\n }}\">\n </ore-combobox>\n </div>\n\n <!-- Active filter rules (appear below the field picker as rules are added) -->\n <div class=\"dg-pop-filter-rules\" ?hidden=\"${() => !controls.filterDefs.value.length}\">\n ${() =>\n controls.filterDefs.value.map(\n (f) => html`\n <div class=\"dg-pop-filter-rule\">\n <div class=\"dg-pop-filter-rule-header\">\n <span class=\"dg-pop-filter-field\">${f.label}</span>\n <ore-select\n class=\"dg-pop-filter-op-select\"\n variant=\"ghost\"\n size=\"sm\"\n fullwidth\n :value=\"${() => controls.filterValues.value.get(f.key)?.operator ?? 'contains'}\"\n :options=\"${() => f.operators ?? []}\"\n @change=\"${(e: CustomEvent<{ values: string[] }>) => {\n controls.setFilterOperator(f.key, e.detail.values[0] as FilterOperator);\n }}\"></ore-select>\n <ore-button\n class=\"dg-icon-btn\"\n variant=\"ghost\"\n size=\"sm\"\n icon-only\n label=\"Remove filter\"\n @click=\"${() => controls.removeFilter(f.key)}\">\n <ore-icon name=\"trash-2\" size=\"13\" stroke-width=\"1.75\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n </div>\n <ore-combobox\n class=\"dg-filter\"\n :placeholder=\"${() => f.label}\"\n :options=\"${() => f.options}\"\n :value=\"${() => [...(controls.filterValues.value.get(f.key)?.values ?? [])]}\"\n :disabled=\"${() => isDisabled.value || undefined}\"\n multiple\n fullwidth\n autoclose\n @change=\"${(e: CustomEvent<{ values: string[] }>) => {\n controls.setFilter(f.key, e.detail.values);\n }}\"></ore-combobox>\n </div>\n `,\n )}\n </div>\n </div>\n </ore-popover>`;\n\n const renderColumnMenu = (): unknown =>\n html`<ore-popover\n class=\"dg-action-popover\"\n placement=\"bottom-end\"\n label=\"Column options\"\n style=\"--popover-min-width:18rem\">\n <ore-button class=\"dg-icon-btn\" variant=\"ghost\" size=\"sm\" icon-only label=\"Column options\">\n <ore-icon name=\"columns-2\" size=\"15\" stroke-width=\"1.75\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n <div slot=\"content\" class=\"dg-pop-col-list\" role=\"menu\" aria-label=\"Column visibility\">\n ${() =>\n resolvedColumns.value.map(\n (col) =>\n html`<ore-button\n class=\"dg-pop-col-item\"\n role=\"menuitemcheckbox\"\n variant=\"ghost\"\n size=\"sm\"\n :aria-checked=\"${() => String(!controls.hiddenColumns.value.has(col.key))}\"\n @click=\"${() => controls.toggleColumnVisibility(col.key)}\">\n <ore-icon\n slot=\"prefix\"\n :name=\"${() => (controls.hiddenColumns.value.has(col.key) ? 'eye-off' : 'eye')}\"\n size=\"13\"\n stroke-width=\"2\"\n aria-hidden=\"true\"></ore-icon>\n ${col.label}\n </ore-button>`,\n )}\n </div>\n </ore-popover>`;\n\n // ── Template ──────────────────────────────────────────────────────────────\n\n return html`\n <!-- ── Controls Bar ────────────────────────────────────────────────── -->\n <div class=\"dg-controls\" part=\"controls\">\n <!-- Left: view tabs -->\n ${() => renderViewTabs()}\n\n <!-- Right: Action bar -->\n <div class=\"dg-actions\">\n ${() => renderSortPopover()} ${() => renderFilterPopover()} ${() => renderColumnMenu()}\n\n <!-- Density toggle -->\n <ore-button\n class=\"dg-icon-btn\"\n variant=\"ghost\"\n size=\"sm\"\n icon-only\n :label=\"${() => DENSITY_LABELS[densitySignal.value]}\"\n @click=\"${cycleDensity}\">\n <ore-icon\n :name=\"${() => DENSITY_ICONS[densitySignal.value]}\"\n size=\"15\"\n stroke-width=\"1.75\"\n aria-hidden=\"true\"></ore-icon>\n </ore-button>\n\n <span class=\"dg-action-divider\" aria-hidden=\"true\" ?hidden=\"${() => !slots.has('actions').value}\"></span>\n\n <slot name=\"actions\"></slot>\n\n <!-- Search toggle: rightmost, expands in-place -->\n <div class=\"${() => `dg-search${controls.searchActive.value ? ' dg-search--open' : ''}`}\">\n ${() =>\n controls.searchActive.value\n ? html`<ore-input\n class=\"dg-search-input\"\n type=\"search\"\n variant=\"flat\"\n size=\"sm\"\n rounded=\"full\"\n :placeholder=\"${() => props.searchPlaceholder.value ?? 'Search…'}\"\n :disabled=\"${() => isDisabled.value || undefined}\"\n ref=\"${(inputEl: HTMLElement | null) => {\n if (inputEl) requestAnimationFrame(() => (inputEl as HTMLElement).focus());\n }}\"\n @input=\"${(e: CustomEvent<{ value: string }>) => {\n debouncedSearch(e.detail.value);\n }}\"\n @keydown=\"${(e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n const src = props.source.value;\n\n if (src?.search) void src.search('');\n\n controls.toggleSearch();\n }\n }}\">\n <ore-icon slot=\"prefix\" name=\"search\" size=\"13\" stroke-width=\"1.75\" aria-hidden=\"true\"></ore-icon>\n </ore-input>`\n : html``}\n <ore-button\n variant=\"ghost\"\n size=\"sm\"\n icon-only\n :label=\"${() => {\n const [open, close] = props.searchLabel.value ?? ['Search', 'Close search'];\n\n return controls.searchActive.value ? close : open;\n }}\"\n @click=\"${() => {\n const src = props.source.value;\n\n if (src?.search && controls.searchActive.value) void src.search('');\n\n controls.toggleSearch();\n }}\">\n <ore-icon\n :name=\"${() => (controls.searchActive.value ? 'x' : 'search')}\"\n size=\"15\"\n stroke-width=\"1.75\"\n aria-hidden=\"true\"></ore-icon>\n </ore-button>\n </div>\n </div>\n </div>\n\n <div id=\"dg-tabpanel\" class=\"dg-scroll\" role=\"tabpanel\" aria-label=\"Data\">\n <div class=\"dg-loading-overlay\">\n <ore-icon name=\"loader-2\" size=\"24\" class=\"dg-spin\" aria-hidden=\"true\"></ore-icon>\n </div>\n <table\n class=\"dg-table\"\n part=\"table\"\n role=\"grid\"\n :aria-label=\"${() => props.label.value ?? undefined}\"\n :aria-busy=\"${() => (isLoading.value ? 'true' : null)}\"\n :aria-disabled=\"${() => (isDisabled.value ? 'true' : null)}\">\n <!-- Head -->\n <thead class=\"dg-head\" part=\"thead\">\n <tr role=\"row\">\n ${() =>\n selectionMode.value === 'multi'\n ? html`<th\n class=\"dg-th dg-th-check\"\n role=\"columnheader\"\n scope=\"col\"\n :tabindex=\"${() =>\n navHandle.activeCell.value.row === 0 &&\n navHandle.activeCell.value.col === 0 &&\n checkOffset.value >= 1\n ? '0'\n : '-1'}\">\n <ore-checkbox\n class=\"dg-check\"\n :checked=\"${() => ctrl.isAllSelected()}\"\n :indeterminate=\"${isSomeSelected}\"\n ?disabled=\"${isDisabled}\"\n aria-label=\"Select all rows on this page\"\n @change=\"${() => {\n if (!isDisabled.value) ctrl.selectAll();\n }}\"></ore-checkbox>\n </th>`\n : html``}\n ${() =>\n visibleColumns.value.map((col: DataGridColumn, colIdx: number) => {\n const isLast = colIdx === visibleColumns.value.length - 1;\n\n return html`<th\n class=\"${`dg-th${isLast && hasExpander.value ? ' dg-th-last' : ''}`}\"\n role=\"columnheader\"\n scope=\"col\"\n :tabindex=\"${() => {\n const ac = navHandle.activeCell.value;\n\n return ac.row === 0 && ac.col === colIdx + checkOffset.value ? '0' : '-1';\n }}\"\n data-align=\"${col.align ?? 'left'}\"\n :aria-sort=\"${() => (col.sortable ? ariaSortValue(ctrl.sortState.value, col.key) : undefined)}\"\n :aria-label=\"${col.sortable ? undefined : (col.headerLabel ?? col.label)}\"\n :style=\"${() => {\n const dragged = colWidths.value[col.key];\n\n return dragged ? `width:${dragged}px` : col.width ? `width:${col.width}` : '';\n }}\">\n <div class=\"dg-th-inner\">\n ${() =>\n col.sortable\n ? html`<ore-button\n class=\"dg-sort-btn\"\n variant=\"text\"\n size=\"sm\"\n fullwidth\n :label=\"${col.headerLabel ?? col.label}\"\n :disabled=\"${() => isDisabled.value || undefined}\"\n @click=\"${() => {\n if (!isDisabled.value) ctrl.sortBy(col.key);\n }}\">\n ${col.label}\n <ore-icon\n slot=\"suffix\"\n class=\"dg-sort-icon\"\n :name=\"${() => sortIconName(ctrl.sortState.value, col.key)}\"\n size=\"14\"\n stroke-width=\"2\"></ore-icon>\n </ore-button>`\n : col.label}\n ${\n col.resizable\n ? html`<span\n class=\"dg-col-resize\"\n aria-hidden=\"true\"\n ref=\"${(handleEl: HTMLElement | null) => {\n if (!handleEl) return;\n\n const th = handleEl.closest('th') as HTMLElement | null;\n\n if (th) handleEl.addEventListener('pointerdown', createColResizeHandler(col.key, th));\n }}\"></span>`\n : html``\n }\n </div>\n </th>`;\n })}\n ${() =>\n hasExpander.value\n ? html`<th\n class=\"dg-th dg-th-expand\"\n role=\"columnheader\"\n scope=\"col\"\n aria-label=\"Row details\"\n tabindex=\"-1\"></th>`\n : html``}\n </tr>\n </thead>\n\n <!-- Body -->\n <tbody class=\"dg-body\" part=\"tbody\">\n ${() =>\n ctrl.currentPageItems.value.length === 0\n ? html`<tr role=\"row\">\n <td class=\"dg-empty\" role=\"gridcell\" :colspan=\"${() => String(effectiveColCount.value)}\">\n <div class=\"dg-empty-content\">\n ${() => props.emptyText.value ?? 'No data'}\n ${() =>\n controls.searchQuery.value || controls.filterValues.value.size\n ? html`<div class=\"dg-empty-actions\">\n <ore-button\n variant=\"text\"\n size=\"sm\"\n @click=\"${() => {\n controls.resetSearch();\n controls.resetFilters();\n }}\">\n Clear all filters & search\n </ore-button>\n </div>`\n : html``}\n </div>\n </td>\n </tr>`\n : ctrl.currentPageItems.value.map((item: Record<string, unknown>, itemIdx: number) => {\n const key = resolveKey(item);\n const isSelectable = selectionMode.value !== 'none' && !isDisabled.value;\n const rowIdx = itemIdx + 1;\n\n return html`<tr\n class=\"dg-tr\"\n part=\"row\"\n role=\"row\"\n :aria-selected=\"${() =>\n selectionMode.value !== 'none' ? String(ctrl.selectedKeys.value.has(key)) : null}\"\n :aria-expanded=\"${() => (hasExpander.value ? String(expandedKeys.value.has(key)) : null)}\"\n ?data-selectable=\"${isSelectable}\"\n ?data-disabled=\"${isDisabled}\"\n @click=\"${() => {\n if (isSelectable && selectionMode.value === 'single') ctrl.toggleRow(key);\n }}\"\n @keydown=\"${(e: KeyboardEvent) => {\n if (\n (e.key === 'Enter' || e.key === ' ') &&\n isSelectable &&\n selectionMode.value === 'single'\n ) {\n e.preventDefault();\n ctrl.toggleRow(key);\n }\n }}\">\n ${() =>\n selectionMode.value === 'multi'\n ? html`<td\n class=\"dg-td dg-td-check\"\n role=\"gridcell\"\n :tabindex=\"${() => {\n const ac = navHandle.activeCell.value;\n\n return ac.row === rowIdx && ac.col === 0 ? '0' : '-1';\n }}\"\n @keydown=\"${(e: KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n\n if (!isDisabled.value) ctrl.toggleRow(key);\n }\n }}\">\n <ore-checkbox\n class=\"dg-check\"\n :checked=\"${() => ctrl.selectedKeys.value.has(key)}\"\n ?disabled=\"${isDisabled}\"\n aria-label=\"Select row\"\n tabindex=\"-1\"\n @click=\"${(e: MouseEvent) => e.stopPropagation()}\"\n @change=\"${() => {\n if (!isDisabled.value) ctrl.toggleRow(key);\n }}\"></ore-checkbox>\n </td>`\n : html``}\n ${visibleColumns.value.map((col: DataGridColumn, colIdx: number) => {\n const value = getCellValue(col, item as Record<string, unknown>);\n\n const isLastCol = colIdx === visibleColumns.value.length - 1;\n\n return html`<td\n class=\"${`dg-td${isLastCol && hasExpander.value ? ' dg-td-last' : ''}`}\"\n part=\"cell\"\n role=\"gridcell\"\n data-align=\"${col.align ?? 'left'}\"\n :tabindex=\"${() => {\n const ac = navHandle.activeCell.value;\n\n return ac.row === rowIdx && ac.col === colIdx + checkOffset.value ? '0' : '-1';\n }}\"\n :title=\"${value}\">\n ${value}\n </td>`;\n })}\n ${() =>\n hasExpander.value\n ? html`<td\n class=\"dg-td dg-td-expand\"\n role=\"gridcell\"\n :tabindex=\"${() => {\n const ac = navHandle.activeCell.value;\n\n return ac.row === rowIdx && ac.col === effectiveColCount.value - 1 ? '0' : '-1';\n }}\"\n @keydown=\"${(e: KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n\n if (!isDisabled.value) toggleExpand(key);\n }\n }}\">\n <ore-button\n class=\"dg-expand-btn\"\n variant=\"ghost\"\n size=\"sm\"\n icon-only\n tabindex=\"-1\"\n :label=\"${() => (expandedKeys.value.has(key) ? 'Collapse row' : 'Expand row')}\"\n :aria-expanded=\"${() => String(expandedKeys.value.has(key))}\"\n :disabled=\"${() => isDisabled.value || undefined}\"\n @click=\"${(e: MouseEvent) => {\n e.stopPropagation();\n\n if (!isDisabled.value) toggleExpand(key);\n }}\">\n <ore-icon\n :name=\"${() => (expandedKeys.value.has(key) ? 'chevron-up' : 'chevron-down')}\"\n size=\"14\"\n stroke-width=\"2\"\n aria-hidden=\"true\"></ore-icon>\n </ore-button>\n </td>`\n : html``}\n </tr>\n ${() =>\n hasExpander.value && expandedKeys.value.has(key)\n ? html`<tr class=\"dg-tr-expanded\" role=\"row\">\n <td\n class=\"dg-td-expanded\"\n role=\"gridcell\"\n :colspan=\"${() => String(effectiveColCount.value)}\">\n ${\n // Routed through raw() (not a bare innerHTML= write) so it\n // participates in the app's registered setRawSanitizer() and\n // the dev-mode unsanitized-HTML warning — see the @security\n // note above: consumers are still responsible for sanitizing\n // any row-derived content their renderExpanded returns.\n raw(() => {\n const renderer = resolvedColumns.value.find(\n (c) => typeof c.renderExpanded === 'function',\n );\n\n return renderer?.renderExpanded?.(item) ?? '';\n })\n }\n </td>\n </tr>`\n : html``} `;\n })}\n </tbody>\n </table>\n </div>\n\n <!-- Footer / Pagination -->\n ${() =>\n paginationEnabled.value\n ? html`<div class=\"dg-footer\" part=\"footer\" role=\"navigation\" aria-label=\"Pagination\">\n ${() =>\n !(props.pageSizeOptions.value ?? []).length\n ? html`<span class=\"dg-footer-info\" dir=\"ltr\" aria-live=\"polite\" aria-atomic=\"true\"\n >${paginationInfo}</span\n >`\n : html``}\n <div class=\"dg-footer-end\">\n ${() => {\n const opts = props.pageSizeOptions.value ?? [];\n\n return opts.length\n ? html`<div class=\"dg-page-size-wrap\">\n <ore-select\n class=\"dg-page-size-select\"\n fullwidth\n aria-label=\"Rows per page\"\n :value=\"${() => String(pageSize.value)}\"\n :options=\"${() => opts.map((n) => ({ label: String(n), value: String(n) }))}\"\n :disabled=\"${() => isDisabled.value || undefined}\"\n @change=\"${(e: CustomEvent<{ values: string[] }>) => {\n const n = parseInt(e.detail.values[0], 10);\n\n if (!isNaN(n)) {\n pageSize.value = n;\n ctrl.goToPage(0);\n emit('page-change', { pageIndex: 0, pageSize: n });\n }\n }}\"></ore-select>\n </div>`\n : html``;\n }}\n <div class=\"dg-pagination\" role=\"group\" aria-label=\"Page navigation\">\n <ore-button\n class=\"dg-page-btn\"\n variant=\"ghost\"\n size=\"sm\"\n icon-only\n label=\"Previous page\"\n :disabled=\"${() => !effectiveHasPrev.value || isDisabled.value}\"\n @click=\"${() => handlePage('prev')}\">\n <ore-icon name=\"chevron-left\" size=\"14\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n <span\n class=\"dg-page-label\"\n dir=\"ltr\"\n aria-current=\"page\"\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\">\n ${() => effectivePageLabel.value}\n </span>\n <ore-button\n class=\"dg-page-btn\"\n variant=\"ghost\"\n size=\"sm\"\n icon-only\n label=\"Next page\"\n :disabled=\"${() => !effectiveHasNext.value || isDisabled.value}\"\n @click=\"${() => handlePage('next')}\">\n <ore-icon name=\"chevron-right\" size=\"14\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n </div>\n </div>\n </div>`\n : html``}\n `;\n },\n\n shadow: { delegatesFocus: true },\n styles: [tableBaseMixin('datagrid'), componentStyles],\n});\n","@layer refine.base {\n :host {\n --_day-selected-bg: var(--calendar-day-selected-bg, var(--_theme-focus));\n --_day-today-color: var(--calendar-day-today-color, var(--_theme-focus));\n --_day-outside-opacity: var(--calendar-day-outside-opacity, 0.35);\n --_bg: var(--calendar-bg, var(--color-canvas));\n --_border-color: var(--calendar-border-color, var(--color-contrast-200));\n --_radius: var(--calendar-radius, var(--rounded-xl));\n\n display: inline-block;\n }\n\n :host([fullwidth]) {\n display: block;\n }\n\n :host([color='secondary']) {\n --_day-selected-bg: var(--calendar-day-selected-bg, var(--_theme-base));\n --_day-today-color: var(--calendar-day-today-color, var(--_theme-base));\n }\n\n /* ── Root panel ──────────────────────────────────────────────────────────── */\n\n .calendar {\n display: flex;\n flex-direction: column;\n gap: var(--size-2);\n min-width: 18rem;\n padding: var(--size-3);\n background: var(--_bg);\n border: var(--border) solid var(--_border-color);\n border-radius: var(--_radius);\n box-shadow: var(--calendar-shadow, var(--shadow-md));\n }\n\n :host([fullwidth]) .calendar {\n min-width: 0;\n }\n\n /* ── Header ──────────────────────────────────────────────────────────────── */\n\n .cal-header {\n display: flex;\n gap: var(--size-1);\n align-items: center;\n justify-content: space-between;\n padding-block-end: var(--size-2);\n border-block-end: var(--border) solid var(--_border-color);\n }\n\n .nav-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--size-8);\n height: var(--size-8);\n padding: 0;\n color: var(--color-contrast-600);\n cursor: pointer;\n outline: none;\n background: transparent;\n border: none;\n border-radius: var(--rounded-md);\n transition:\n background var(--transition-fast),\n color var(--transition-fast);\n }\n\n .nav-btn:hover:not(:disabled) {\n color: var(--color-contrast-900);\n background: var(--color-contrast-300);\n }\n\n .nav-btn:focus-visible {\n box-shadow: 0 0 0 2px var(--_day-selected-bg);\n }\n\n .nav-btn:disabled {\n cursor: not-allowed;\n opacity: 0.4;\n }\n\n .cal-label-btn {\n flex: 1;\n padding: var(--size-1) var(--size-2);\n font-size: var(--text-sm);\n font-weight: var(--font-semibold);\n color: var(--color-contrast-900);\n text-align: center;\n cursor: pointer;\n outline: none;\n background: transparent;\n border: none;\n border-radius: var(--rounded-md);\n transition: background var(--transition-fast);\n }\n\n .cal-label-btn:hover:not(:disabled) {\n background: var(--color-contrast-300);\n }\n\n .cal-label-btn:focus-visible {\n box-shadow: 0 0 0 2px var(--_day-selected-bg);\n }\n\n .cal-label-btn:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n }\n\n .cal-label-month,\n .cal-label-year {\n display: inline-block;\n }\n\n .cal-label-sep {\n display: inline-block;\n padding-inline: var(--size-1);\n font-weight: var(--font-normal);\n color: var(--color-contrast-400);\n }\n\n /* ── Grid base ───────────────────────────────────────────────────────────── */\n\n [hidden] {\n display: none !important;\n }\n\n .cal-grid {\n display: flex;\n flex-direction: column;\n gap: var(--size-0-5);\n }\n\n .cal-grid-days {\n display: grid;\n grid-template-columns: repeat(7, minmax(0, 1fr));\n gap: var(--size-0-5);\n\n /* Reserve max height (6 week rows + 1 header) so the panel never shrinks\n on 5-week months or when switching to month/year view. */\n min-height: calc(7 * var(--size-10) + 6 * var(--size-0-5));\n }\n\n /* role=\"row\" wrappers exist for ARIA grid structure only — `display: contents`\n removes them from layout so their children still participate directly in the\n parent's CSS grid tracks. */\n .cal-grid [role='row'] {\n display: contents;\n }\n\n .cal-cell {\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: var(--text-sm);\n cursor: pointer;\n outline: none;\n border-radius: var(--rounded-md);\n transition:\n background var(--transition-fast),\n color var(--transition-fast);\n }\n\n /* ── Column headers ──────────────────────────────────────────────────────── */\n\n .cal-cell-head {\n height: var(--size-8);\n font-size: var(--text-xs);\n font-weight: var(--font-medium);\n color: var(--color-contrast-500);\n cursor: default;\n }\n\n /* ── Day cells ───────────────────────────────────────────────────────────── */\n\n .cal-cell-day {\n flex-direction: column;\n gap: var(--size-0-5);\n min-width: 0;\n height: var(--size-10);\n overflow: hidden;\n color: var(--color-contrast-800);\n }\n\n .cal-cell-day:hover:not([data-disabled]) {\n color: var(--color-contrast-900);\n background: color-mix(in oklch, var(--_day-selected-bg) 15%, transparent);\n }\n\n .cal-cell-day:focus-visible {\n box-shadow: 0 0 0 2px var(--_day-selected-bg);\n }\n\n .cal-cell-day[data-today] {\n font-weight: var(--font-semibold);\n color: var(--_day-today-color);\n }\n\n .cal-cell-day[data-selected] {\n font-weight: var(--font-semibold);\n color: var(--color-white, #fff);\n background: var(--_day-selected-bg);\n }\n\n .cal-cell-day[data-outside] {\n opacity: var(--_day-outside-opacity);\n }\n\n .cal-cell-day[data-disabled] {\n pointer-events: none;\n cursor: not-allowed;\n opacity: 0.3;\n }\n\n /* ── Event dots (normal mode) ────────────────────────────────────────────── */\n\n .cal-dots {\n display: flex;\n gap: 2px;\n align-items: center;\n justify-content: center;\n margin-block-start: var(--size-0-5);\n }\n\n .cal-dot {\n --badge-bg: var(--_day-selected-bg);\n --badge-border-color: var(--_day-selected-bg);\n }\n\n .cal-dot-overflow {\n font-size: 8px;\n font-weight: var(--font-semibold);\n line-height: 1;\n color: var(--color-contrast-500);\n }\n\n /* ── Month / year grids ──────────────────────────────────────────────────── */\n\n .cal-grid-months,\n .cal-grid-years {\n /* 4-column grid — same width as cal-grid-days, natural height. */\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n gap: var(--size-1);\n }\n\n .cal-cell-month,\n .cal-cell-year {\n height: var(--size-10);\n font-size: var(--text-sm);\n color: var(--color-contrast-800);\n cursor: pointer;\n border-radius: var(--rounded-md);\n }\n\n .cal-cell-month:hover:not([data-disabled]),\n .cal-cell-year:hover:not([data-disabled]) {\n background: color-mix(in oklch, var(--_day-selected-bg) 15%, transparent);\n }\n\n .cal-cell-month:focus-visible,\n .cal-cell-year:focus-visible {\n box-shadow: 0 0 0 2px var(--_day-selected-bg);\n }\n\n .cal-cell-month[data-selected],\n .cal-cell-year[data-selected] {\n font-weight: var(--font-semibold);\n color: var(--color-white, #fff);\n background: var(--_day-selected-bg);\n }\n\n .cal-cell-month[data-disabled],\n .cal-cell-year[data-disabled] {\n pointer-events: none;\n cursor: not-allowed;\n opacity: 0.3;\n }\n\n /* ── Expanded variant ────────────────────────────────────────────────────── */\n\n :host([expanded]) {\n display: block;\n width: 100%;\n }\n\n :host([expanded]) .calendar {\n width: 100%;\n min-width: 0;\n padding: 0;\n overflow: hidden;\n }\n\n :host([expanded]) .cal-header {\n padding: var(--size-3) var(--size-4);\n }\n\n :host([expanded]) .cal-label-btn {\n font-size: var(--text-base);\n }\n\n :host([expanded]) .cal-grid {\n gap: 0;\n }\n\n :host([expanded]) .cal-grid-days {\n gap: 0;\n border-block-start: var(--border) solid var(--_border-color);\n }\n\n :host([expanded]) .cal-cell {\n border-radius: 0;\n }\n\n :host([expanded]) .cal-cell-head {\n height: var(--size-9);\n font-size: var(--text-xs);\n font-weight: var(--font-semibold);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n border-block-end: var(--border) solid var(--_border-color);\n }\n\n :host([expanded]) .cal-cell-day {\n position: relative;\n flex-direction: column;\n gap: 0;\n align-items: flex-start;\n justify-content: flex-start;\n height: auto;\n min-height: var(--calendar-expanded-cell-height, var(--size-28));\n aspect-ratio: auto;\n padding: var(--size-2);\n font-size: var(--text-sm);\n vertical-align: top;\n border-block-end: var(--border) solid var(--_border-color);\n border-inline-end: var(--border) solid var(--_border-color);\n }\n\n /* Remove right border on last column */\n :host([expanded]) .cal-cell-day:nth-child(7n) {\n border-inline-end: none;\n }\n\n :host([expanded]) .cal-cell-day:hover:not([data-disabled]) {\n background: color-mix(in oklch, var(--_day-selected-bg) 6%, transparent);\n }\n\n /* Selected day — circle around the number only */\n :host([expanded]) .cal-cell-day[data-selected] {\n color: inherit;\n background: transparent;\n }\n\n :host([expanded]) .cal-cell-day[data-selected]::before {\n position: absolute;\n top: var(--size-1-5);\n left: var(--size-1-5);\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--size-7);\n height: var(--size-7);\n font-size: var(--text-sm);\n font-weight: var(--font-semibold);\n color: var(--color-white, #fff);\n content: attr(data-day);\n background: var(--_day-selected-bg);\n border-radius: var(--rounded-full);\n }\n\n /* Today — circle in accent colour */\n :host([expanded]) .cal-cell-day[data-today] {\n font-weight: inherit;\n color: inherit;\n }\n\n :host([expanded]) .cal-cell-day[data-today]::before {\n position: absolute;\n top: var(--size-1-5);\n left: var(--size-1-5);\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--size-7);\n height: var(--size-7);\n font-size: var(--text-sm);\n font-weight: var(--font-semibold);\n color: var(--color-white, #fff);\n content: attr(data-day);\n background: var(--_day-today-color);\n border-radius: var(--rounded-full);\n }\n\n /* When both today AND selected — selected wins */\n :host([expanded]) .cal-cell-day[data-today][data-selected]::before {\n background: var(--_day-selected-bg);\n }\n\n /* ── Expanded event pills ────────────────────────────────────────────────── */\n\n /* Push events below the day-number circle row */\n :host([expanded]) .cal-events {\n display: flex;\n flex-direction: column;\n gap: 2px;\n width: 100%;\n margin-block-start: var(--size-4);\n overflow: hidden;\n }\n\n :host([expanded]) .cal-event-pill {\n max-width: 100%;\n\n --badge-max-width: 100%;\n }\n\n :host([expanded]) .cal-event-pill-overflow {\n padding-inline: var(--size-1);\n font-size: 10px;\n font-weight: var(--font-semibold);\n color: var(--color-contrast-500);\n }\n\n /* Dots are hidden in expanded mode — pills take over */\n :host([expanded]) .cal-dots {\n display: none;\n }\n\n :host([expanded]) .cal-cell-day[data-outside] {\n background: color-mix(in oklch, var(--color-contrast-900) 2%, transparent);\n }\n\n /* Expanded month / year grids */\n :host([expanded]) .cal-grid-months,\n :host([expanded]) .cal-grid-years {\n gap: var(--size-2);\n min-height: 0;\n padding: var(--size-4);\n }\n\n :host([expanded]) .cal-cell-month,\n :host([expanded]) .cal-cell-year {\n min-height: var(--size-16);\n font-size: var(--text-base);\n border: var(--border) solid var(--_border-color);\n border-radius: var(--rounded-lg);\n }\n\n :host([expanded]) .cal-cell-month[data-selected],\n :host([expanded]) .cal-cell-year[data-selected] {\n border-color: transparent;\n }\n\n /* ── Disabled host ───────────────────────────────────────────────────────── */\n\n :host(.is-disabled) .calendar {\n pointer-events: none;\n opacity: 0.6;\n }\n\n /* ── Reduced motion ──────────────────────────────────────────────────────── */\n\n @media (prefers-reduced-motion: reduce) {\n .nav-btn,\n .cal-label-btn,\n .cal-cell {\n transition: none;\n }\n }\n}\n","import { define, useField, html, prop } from '@vielzeug/ore';\nimport { styleMap } from '@vielzeug/ore/directives';\nimport { computed, signal } from '@vielzeug/ripple';\nimport { Temporal, format } from '@vielzeug/tempo';\n\nimport type { ComponentSize, RoundedSize, ThemeColor } from '../../shared';\n\nimport '../../content/icon/icon';\nimport '../../feedback/badge/badge';\nimport { createDatePickerControl, parseIso, toIsoString, type DatePickerView } from '../../headless';\nimport { disablableBundle, roundableBundle, sizableBundle, themableBundle } from '../../shared';\nimport { colorThemeMixin, reducedMotionMixin } from '../../styles';\nimport componentStyles from './calendar.css?inline';\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport type OreCalendarEvents = {\n change: { isoValue: string | null };\n};\n\n/**\n * A calendar event entry.\n * Dates must be ISO 8601 strings (yyyy-MM-dd).\n *\n * The `color` field accepts any valid CSS color value (e.g. `'#e11d48'`,\n * `'var(--color-primary)'`). An invalid value silently falls back to the\n * component's theme color. Only pass values you control.\n */\nexport type CalendarEvent = {\n /**\n * Any CSS color value for the event dot / pill.\n * Defaults to the component's theme color when omitted.\n * Rendered via `styleMap()`, which strips `;`/`{`/`}` so the value can't break out of\n * its custom-property declaration — it is not a full CSS-color syntax validator, so an\n * invalid (but injection-safe) value may still render as no color.\n */\n color?: string;\n /** ISO date the event falls on (yyyy-MM-dd) */\n date: string;\n /** Unique identifier */\n id: string;\n /** Short label shown in the calendar cell */\n label: string;\n};\n\nexport type OreCalendarProps = {\n /** Theme color */\n color?: ThemeColor;\n /** Disable all date selection */\n disabled?: boolean;\n /**\n * Array of calendar events to display on day cells.\n * In normal mode each event renders as a small colored dot (max 3 dots, then \"+N\").\n * In expanded mode each event renders as a full-width colored pill with its label.\n * Pass as a JS property or as a JSON-encoded attribute.\n * @example\n * ```js\n * calendar.events = [\n * { id: '1', date: '2025-06-15', label: 'Team standup', color: 'var(--color-primary)' },\n * { id: '2', date: '2025-06-20', label: 'Release', color: '#e11d48' },\n * ];\n * ```\n */\n events?: CalendarEvent[];\n /**\n * Expanded layout — large cells with top-aligned day numbers suitable\n * for a full-page calendar app view.\n */\n expanded?: boolean;\n /** Expand to container width */\n fullwidth?: boolean;\n /** Locale for day/month names (default: browser locale) */\n locale?: string;\n /** Latest selectable date in ISO 8601 format (yyyy-MM-dd) */\n max?: string;\n /** Earliest selectable date in ISO 8601 format (yyyy-MM-dd) */\n min?: string;\n /** Form field name (when used inside a form) */\n name?: string;\n /** Mark field as required */\n required?: boolean;\n /** Border radius override */\n rounded?: RoundedSize;\n /** Component size */\n size?: ComponentSize;\n /**\n * Selected date in ISO 8601 format (yyyy-MM-dd).\n * @example '2025-06-15'\n */\n value?: string;\n /**\n * Day-of-week indices to disable (0 = Sunday … 6 = Saturday).\n * Pass as a JSON array attribute or a JS property.\n * @example\n * ```html\n * <ore-calendar weekend-days=\"[0,6]\"></ore-calendar>\n * ```\n */\n 'weekend-days'?: number[];\n};\n\n/**\n * An accessible, keyboard-navigable inline calendar component.\n * Supports day/month/year drill-down views, min/max bounds, disabled weekend\n * days, and optional form association.\n *\n * @element ore-calendar\n *\n * @attr {string} value - Selected date in ISO 8601 format (yyyy-MM-dd)\n * @attr {string} min - Minimum selectable date (yyyy-MM-dd)\n * @attr {string} max - Maximum selectable date (yyyy-MM-dd)\n * @attr {boolean} disabled - Disable all interaction\n * @attr {boolean} required - Required field (form association)\n * @attr {string} name - Form field name\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n * @attr {string} locale - BCP 47 locale string\n * @attr {string} weekend-days - JSON array of day indices to disable (0=Sun…6=Sat)\n * @attr {boolean} fullwidth - Expand to full container width\n * @attr {boolean} expanded - Large-cell calendar-app layout with top-aligned day numbers\n *\n * @fires change - Fired when a date is selected. detail: { isoValue: string | null }\n *\n * @cssprop --calendar-bg - Calendar background\n * @cssprop --calendar-border-color - Calendar border color\n * @cssprop --calendar-radius - Calendar border radius\n * @cssprop --calendar-shadow - Calendar drop shadow\n * @cssprop --calendar-day-selected-bg - Background of selected day cell\n * @cssprop --calendar-day-today-color - Colour of today's date number\n * @cssprop --calendar-day-outside-opacity - Opacity of days outside visible month\n *\n * @part calendar - The root calendar panel\n * @part header - Calendar header (nav + label)\n * @part grid - Day grid\n * @part day - Individual day cell\n *\n * @example\n * ```html\n * <!-- Single date with bounds -->\n * <ore-calendar value=\"2025-06-15\" min=\"2025-01-01\" max=\"2025-12-31\" color=\"primary\"></ore-calendar>\n *\n * <!-- Expanded calendar-app layout -->\n * <ore-calendar expanded fullwidth color=\"primary\"></ore-calendar>\n * ```\n */\nexport const CALENDAR_TAG = 'ore-calendar' as const;\n\n/** Maximum event dots/pills shown per cell before \"+N\" overflow */\nconst MAX_EVENTS = 3;\n\n// ── Component ────────────────────────────────────────────────────────────────\n\ndefine<OreCalendarProps, OreCalendarEvents>(CALENDAR_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n ...roundableBundle,\n events: prop.json([] as CalendarEvent[]),\n expanded: prop.bool(false),\n fullwidth: prop.bool(false),\n locale: prop.string(),\n max: prop.string(),\n min: prop.string(),\n name: prop.string(),\n required: prop.bool(false),\n value: prop.string(),\n 'weekend-days': prop.json([] as number[]),\n },\n\n setup(props, { bind, emit }) {\n // ── Derived flags ────────────────────────────────────────────────────────\n\n const isDisabled = computed(() => props.disabled.value === true);\n const isExpanded = computed(() => props.expanded.value === true);\n\n // ── Selected date: local-override pattern ─────────────────────────────────\n // `localSelection` holds a user-initiated pick (or undefined = no override).\n // `selectedDate` derives from it, falling back to the value prop reactively.\n // This eliminates setInterval polling — external prop changes propagate\n // through the computed graph automatically.\n\n const localSelection = signal<Temporal.PlainDate | null | undefined>(undefined);\n\n const selectedDate = computed(() =>\n localSelection.value !== undefined ? localSelection.value : parseIso(props.value.value),\n );\n\n // ── Date-picker control ──────────────────────────────────────────────────\n\n const ctrl = createDatePickerControl({\n get locale() {\n return props.locale.value ?? (typeof navigator !== 'undefined' ? navigator.language : 'en');\n },\n get max() {\n return parseIso(props.max.value);\n },\n get min() {\n return parseIso(props.min.value);\n },\n onChange(date) {\n localSelection.value = date;\n currentView.value = 'day';\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n emit('change', { isoValue: toIsoString(date) });\n },\n get value() {\n return selectedDate.value;\n },\n get weekendDays() {\n return props['weekend-days'].value ?? [];\n },\n });\n\n // ── Reactive display state ────────────────────────────────────────────────\n // Three separate primitive signals — the proven pattern. Mutating any one\n // of them invalidates only the computeds that read it.\n\n const currentView = signal<DatePickerView>('day');\n const displayYear = signal(ctrl.displayYear());\n const displayMonth = signal(ctrl.displayMonth()); // 1-indexed (Temporal)\n\n // ── Form value ───────────────────────────────────────────────────────────\n\n useField<string>({\n disabled: isDisabled,\n toFormValue: (v) => v || null,\n value: computed(() => toIsoString(selectedDate.value) ?? ''),\n });\n\n // ── Events lookup ─────────────────────────────────────────────────────────\n\n const eventsByDate = computed(() => {\n const map = new Map<string, CalendarEvent[]>();\n\n for (const evt of props.events.value ?? []) {\n const list = map.get(evt.date) ?? [];\n\n list.push(evt);\n map.set(evt.date, list);\n }\n\n return map;\n });\n\n // ── Derived cells ─────────────────────────────────────────────────────────\n // Each reads a display signal so they re-run when navigation changes.\n\n const dayCells = computed(() => {\n void displayYear.value;\n void displayMonth.value;\n void selectedDate.value; // re-run when selection changes to refresh isSelected flags\n\n return ctrl.dayCells();\n });\n const monthCells = computed(() => {\n void displayYear.value;\n\n return ctrl.monthCells();\n });\n const yearCells = computed(() => {\n void displayYear.value;\n\n return ctrl.yearCells();\n });\n const weekdayLabels = computed(() => ctrl.weekdayLabels());\n\n const displayMonth_ = computed(() => {\n const d = Temporal.PlainDate.from({ day: 1, month: displayMonth.value, year: displayYear.value });\n const loc = props.locale.value ?? (typeof navigator !== 'undefined' ? navigator.language : 'en');\n\n return format(d, { intl: { month: 'long' }, locale: loc, tz: 'UTC' });\n });\n\n const displayYear_ = computed(() => String(displayYear.value));\n const displayLabel = computed(() => `${displayMonth_.value} ${displayYear_.value}`);\n\n // ── Navigation ───────────────────────────────────────────────────────────\n\n function handlePrev(): void {\n if (currentView.value === 'day') ctrl.prevMonth();\n else ctrl.prevYear();\n\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n }\n\n function handleNext(): void {\n if (currentView.value === 'day') ctrl.nextMonth();\n else ctrl.nextYear();\n\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n }\n\n function handleHeaderClick(): void {\n const views: DatePickerView[] = ['day', 'month', 'year'];\n const next = views[(views.indexOf(currentView.value) + 1) % views.length];\n\n ctrl.setView(next);\n currentView.value = next;\n }\n\n // ── Selection handlers — all disabled guards live here ────────────────────\n\n function handleSelectMonth(month: number): void {\n if (isDisabled.value) return;\n\n ctrl.goTo(ctrl.displayYear(), month);\n ctrl.setView('day');\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n currentView.value = 'day';\n }\n\n function handleSelectYear(year: number): void {\n if (isDisabled.value) return;\n\n ctrl.goTo(year, ctrl.displayMonth());\n ctrl.setView('month');\n displayYear.value = ctrl.displayYear();\n currentView.value = 'month';\n }\n\n function handleSelectDay(isoStr: string): void {\n if (isDisabled.value) return;\n\n const date = parseIso(isoStr);\n\n if (!date) return;\n\n ctrl.select(date); // ctrl.select() internally rejects disabled/out-of-range dates\n }\n\n // ── Day-cell keyboard navigation (full ARIA grid pattern) ─────────────────\n\n function handleDayKeydown(e: KeyboardEvent): void {\n const cell = e.currentTarget as HTMLElement;\n const grid = cell.closest('.cal-grid-days');\n\n if (!grid) return;\n\n const allCells = Array.from(grid.querySelectorAll<HTMLElement>('.cal-cell-day'));\n const idx = allCells.indexOf(cell);\n\n if (idx === -1) return;\n\n let target: HTMLElement | undefined;\n\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleSelectDay(cell.dataset.iso ?? '');\n\n return;\n } else if (e.key === 'ArrowRight') {\n target = allCells[idx + 1];\n } else if (e.key === 'ArrowLeft') {\n target = allCells[idx - 1];\n } else if (e.key === 'ArrowDown') {\n target = allCells[idx + 7];\n } else if (e.key === 'ArrowUp') {\n target = allCells[idx - 7];\n } else if (e.key === 'Home') {\n target = allCells[Math.floor(idx / 7) * 7]; // first cell in same row\n } else if (e.key === 'End') {\n target = allCells[Math.floor(idx / 7) * 7 + 6]; // last cell in same row\n } else {\n return;\n }\n\n e.preventDefault();\n target?.focus();\n }\n\n // ── Month/year-cell keyboard navigation (fixed 4-column grid) ─────────────\n\n function handleGridKeydown(e: KeyboardEvent, cellSelector: string, columns: number, onSelect: () => void): void {\n const cell = e.currentTarget as HTMLElement;\n const grid = cell.closest('.cal-grid');\n\n if (!grid) return;\n\n const allCells = Array.from(grid.querySelectorAll<HTMLElement>(cellSelector));\n const idx = allCells.indexOf(cell);\n\n if (idx === -1) return;\n\n let target: HTMLElement | undefined;\n\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onSelect();\n\n return;\n } else if (e.key === 'ArrowRight') {\n target = allCells[idx + 1];\n } else if (e.key === 'ArrowLeft') {\n target = allCells[idx - 1];\n } else if (e.key === 'ArrowDown') {\n target = allCells[idx + columns];\n } else if (e.key === 'ArrowUp') {\n target = allCells[idx - columns];\n } else if (e.key === 'Home') {\n target = allCells[Math.floor(idx / columns) * columns];\n } else if (e.key === 'End') {\n target = allCells[Math.min(Math.floor(idx / columns) * columns + columns - 1, allCells.length - 1)];\n } else {\n return;\n }\n\n e.preventDefault();\n target?.focus();\n }\n\n // ── Host bindings ────────────────────────────────────────────────────────\n\n bind({\n attr: {\n 'aria-disabled': () => (isDisabled.value ? 'true' : null),\n 'aria-label': () => displayLabel.value,\n role: 'group',\n },\n class: {\n 'is-disabled': isDisabled,\n },\n });\n\n // ── Template ─────────────────────────────────────────────────────────────\n\n return html`\n <div class=\"calendar\" part=\"calendar\" role=\"presentation\">\n <!-- Header -->\n <div class=\"cal-header\" part=\"header\">\n <button class=\"nav-btn\" type=\"button\" aria-label=\"Previous\" ?disabled=\"${isDisabled}\" @click=\"${handlePrev}\">\n <ore-icon name=\"chevron-left\" size=\"16\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </button>\n\n <button\n class=\"cal-label-btn\"\n type=\"button\"\n :aria-label=\"${() =>\n `Switch to ${currentView.value === 'day' ? 'month' : currentView.value === 'month' ? 'year' : 'day'} view`}\"\n ?disabled=\"${isDisabled}\"\n @click=\"${handleHeaderClick}\">\n <span class=\"cal-label-month\">${displayMonth_}</span><span class=\"cal-label-sep\" aria-hidden=\"true\">/</span\n ><span class=\"cal-label-year\">${displayYear_}</span>\n </button>\n\n <button class=\"nav-btn\" type=\"button\" aria-label=\"Next\" ?disabled=\"${isDisabled}\" @click=\"${handleNext}\">\n <ore-icon name=\"chevron-right\" size=\"16\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </button>\n </div>\n\n <!-- Day view -->\n <div\n class=\"cal-grid cal-grid-days\"\n role=\"grid\"\n part=\"grid\"\n :aria-label=\"${() => displayLabel.value}\"\n ?hidden=\"${() => currentView.value !== 'day'}\">\n <div role=\"row\" class=\"cal-grid-row\">\n ${() =>\n weekdayLabels.value.map(\n (lbl) => html`<div class=\"cal-cell cal-cell-head\" role=\"columnheader\" aria-label=\"${lbl}\">${lbl}</div>`,\n )}\n </div>\n ${() => {\n const cells = dayCells.value;\n const rows: (typeof cells)[number][][] = [];\n\n for (let i = 0; i < cells.length; i += 7) rows.push(cells.slice(i, i + 7));\n\n return rows.map(\n (row) =>\n html`<div role=\"row\" class=\"cal-grid-row\">\n ${row.map(\n (cell) =>\n html`<div\n class=\"cal-cell cal-cell-day\"\n role=\"gridcell\"\n part=\"day\"\n :aria-selected=\"${() => String(cell.isSelected)}\"\n :aria-disabled=\"${() => String(cell.isDisabled || isDisabled.value)}\"\n :aria-current=\"${() => (cell.isToday ? 'date' : null)}\"\n ?data-selected=\"${() => cell.isSelected}\"\n ?data-today=\"${() => cell.isToday}\"\n ?data-outside=\"${() => cell.isOutsideMonth}\"\n ?data-disabled=\"${() => cell.isDisabled || isDisabled.value}\"\n data-iso=\"${cell.iso}\"\n data-day=\"${String(cell.day)}\"\n tabindex=\"${() => (cell.isDisabled || isDisabled.value ? '-1' : '0')}\"\n @click=\"${() => handleSelectDay(cell.iso)}\"\n @keydown=\"${handleDayKeydown}\">\n ${String(cell.day)}\n ${() => {\n const evts = eventsByDate.value.get(cell.iso) ?? [];\n\n if (!evts.length) return html``;\n\n const shown = evts.slice(0, MAX_EVENTS);\n const overflow = evts.length - MAX_EVENTS;\n\n if (isExpanded.value) {\n return html`<div\n class=\"cal-events\"\n aria-label=\"${() => `${evts.length} event${evts.length > 1 ? 's' : ''}`}\">\n ${shown.map(\n (evt) =>\n html`<ore-badge\n class=\"cal-event-pill\"\n size=\"xs\"\n rounded=\"sm\"\n aria-label=\"${evt.label}\"\n :style=\"${styleMap({\n '--badge-bg': evt.color,\n '--badge-border-color': evt.color,\n })}\">\n ${evt.label}\n </ore-badge>`,\n )}\n ${\n overflow > 0\n ? html`<span class=\"cal-event-pill-overflow\" aria-hidden=\"true\"\n >+${overflow} more</span\n >`\n : html``\n }\n </div>`;\n }\n\n return html`<div\n class=\"cal-dots\"\n aria-label=\"${() => `${evts.length} event${evts.length > 1 ? 's' : ''}`}\">\n ${shown.map(\n (evt) =>\n html`<ore-badge\n class=\"cal-dot\"\n dot\n size=\"xs\"\n aria-hidden=\"true\"\n :style=\"${styleMap({\n '--badge-bg': evt.color,\n '--badge-border-color': evt.color,\n })}\"></ore-badge>`,\n )}\n ${\n overflow > 0\n ? html`<span class=\"cal-dot-overflow\" aria-hidden=\"true\">+${overflow}</span>`\n : html``\n }\n </div>`;\n }}\n </div>`,\n )}\n </div>`,\n );\n }}\n </div>\n\n <!-- Month view -->\n <div\n class=\"cal-grid cal-grid-months\"\n role=\"grid\"\n :aria-label=\"${() => displayYear_.value}\"\n ?hidden=\"${() => currentView.value !== 'month'}\">\n ${() => {\n const cells = monthCells.value;\n const rows: (typeof cells)[number][][] = [];\n\n for (let i = 0; i < cells.length; i += 4) rows.push(cells.slice(i, i + 4));\n\n return rows.map(\n (row) =>\n html`<div role=\"row\">\n ${row.map(\n (cell) =>\n html`<div\n class=\"cal-cell cal-cell-month\"\n role=\"gridcell\"\n :aria-selected=\"${() => String(cell.isSelected)}\"\n :aria-disabled=\"${() => String(cell.isDisabled || isDisabled.value)}\"\n ?data-selected=\"${() => cell.isSelected}\"\n ?data-disabled=\"${() => cell.isDisabled || isDisabled.value}\"\n tabindex=\"${() => (cell.isDisabled || isDisabled.value ? '-1' : '0')}\"\n @click=\"${() => handleSelectMonth(cell.month)}\"\n @keydown=\"${(e: KeyboardEvent) =>\n handleGridKeydown(e, '.cal-cell-month', 4, () => handleSelectMonth(cell.month))}\">\n ${cell.shortLabel}\n </div>`,\n )}\n </div>`,\n );\n }}\n </div>\n\n <!-- Year view -->\n <div\n class=\"cal-grid cal-grid-years\"\n role=\"grid\"\n aria-label=\"Select year\"\n ?hidden=\"${() => currentView.value !== 'year'}\">\n ${() => {\n const cells = yearCells.value;\n const rows: (typeof cells)[number][][] = [];\n\n for (let i = 0; i < cells.length; i += 4) rows.push(cells.slice(i, i + 4));\n\n return rows.map(\n (row) =>\n html`<div role=\"row\">\n ${row.map(\n (cell) =>\n html`<div\n class=\"cal-cell cal-cell-year\"\n role=\"gridcell\"\n :aria-selected=\"${() => String(cell.isSelected)}\"\n :aria-disabled=\"${() => String(cell.isDisabled || isDisabled.value)}\"\n ?data-selected=\"${() => cell.isSelected}\"\n ?data-disabled=\"${() => cell.isDisabled || isDisabled.value}\"\n tabindex=\"${() => (cell.isDisabled || isDisabled.value ? '-1' : '0')}\"\n @click=\"${() => handleSelectYear(cell.year)}\"\n @keydown=\"${(e: KeyboardEvent) =>\n handleGridKeydown(e, '.cal-cell-year', 4, () => handleSelectYear(cell.year))}\">\n ${String(cell.year)}\n </div>`,\n )}\n </div>`,\n );\n }}\n </div>\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [colorThemeMixin, reducedMotionMixin, componentStyles],\n});\n","@layer refine.base {\n :host {\n --_day-selected-bg: var(--date-picker-day-selected-bg, var(--_theme-focus));\n --_day-today-color: var(--date-picker-day-today-color, var(--_theme-focus));\n --_day-outside-opacity: var(--date-picker-day-outside-opacity, 0.35);\n\n position: relative;\n display: inline-block;\n }\n\n :host([fullwidth]) {\n display: block;\n }\n\n :host([color='secondary']) {\n --_day-selected-bg: var(--date-picker-day-selected-bg, var(--_theme-base));\n --_day-today-color: var(--date-picker-day-today-color, var(--_theme-base));\n }\n\n /* Make the trigger look like a button — ore-input is readonly so pointer changes to text by default */\n .trigger {\n cursor: pointer;\n }\n\n .trigger::part(input) {\n cursor: pointer;\n caret-color: transparent;\n user-select: none;\n }\n\n /* ── Calendar popup ──────────────────────────────────────────────────────── */\n\n .calendar {\n position: absolute;\n top: calc(100% + var(--size-1));\n left: 0;\n z-index: var(--z-dropdown, 200);\n display: flex;\n flex-direction: column;\n gap: var(--size-2);\n min-width: 18rem;\n padding: var(--size-3);\n pointer-events: none;\n background: var(--_bg);\n border: var(--border) solid var(--_border-color);\n border-radius: var(--_radius);\n box-shadow: var(--date-picker-shadow, var(--shadow-lg));\n\n /* Hidden by default */\n opacity: 0;\n backdrop-filter: blur(var(--blur-sm));\n transform: translateY(var(--overlay-enter-translate-y));\n transition: var(\n --_motion-transition,\n opacity var(--transition-fast),\n transform var(--transition-fast),\n display var(--transition-fast) allow-discrete\n );\n }\n\n .calendar[data-open] {\n pointer-events: auto;\n opacity: 1;\n transform: translateY(0);\n\n @starting-style {\n opacity: 0;\n transform: translateY(var(--overlay-enter-translate-y));\n }\n }\n\n /* ── Calendar header ─────────────────────────────────────────────────────── */\n\n .cal-header {\n display: flex;\n gap: var(--size-1);\n align-items: center;\n justify-content: space-between;\n padding-block-end: var(--size-2);\n border-block-end: var(--border) solid var(--_border-color);\n }\n\n .nav-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--size-8);\n height: var(--size-8);\n padding: 0;\n color: var(--color-contrast-600);\n cursor: pointer;\n outline: none;\n background: transparent;\n border: none;\n border-radius: var(--rounded-md);\n transition:\n background var(--transition-fast),\n color var(--transition-fast);\n }\n\n .nav-btn:hover {\n color: var(--color-contrast-900);\n background: var(--color-contrast-300);\n }\n\n .nav-btn:focus-visible {\n box-shadow: 0 0 0 2px var(--_day-selected-bg);\n }\n\n .cal-label-btn {\n flex: 1;\n padding: var(--size-1) var(--size-2);\n font-size: var(--text-sm);\n font-weight: var(--font-semibold);\n color: var(--color-contrast-900);\n text-align: center;\n cursor: pointer;\n outline: none;\n background: transparent;\n border: none;\n border-radius: var(--rounded-md);\n transition: background var(--transition-fast);\n }\n\n .cal-label-btn:hover {\n background: var(--color-contrast-300);\n }\n\n .cal-label-btn:focus-visible {\n box-shadow: 0 0 0 2px var(--_day-selected-bg);\n }\n\n .cal-label-month,\n .cal-label-year {\n display: inline-block;\n }\n\n .cal-label-sep {\n display: inline-block;\n padding-inline: var(--size-1);\n font-weight: var(--font-normal);\n color: var(--color-contrast-400);\n }\n\n /* ── Day grid ────────────────────────────────────────────────────────────── */\n\n /* Prevent display:flex from overriding the [hidden] attribute */\n [hidden] {\n display: none !important;\n }\n\n .cal-grid {\n display: flex;\n flex-direction: column;\n gap: var(--size-0-5);\n }\n\n .cal-grid-days {\n display: grid;\n grid-template-columns: repeat(7, 1fr);\n gap: var(--size-0-5);\n min-height: calc(7 * var(--size-10) + 6 * var(--size-0-5));\n }\n\n /* role=\"row\" wrappers exist for ARIA grid structure only — `display: contents`\n removes them from layout so their children still participate directly in the\n parent's CSS grid tracks. */\n .cal-grid [role='row'] {\n display: contents;\n }\n\n .cal-cell {\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: var(--text-sm);\n cursor: pointer;\n outline: none;\n border-radius: var(--rounded-md);\n transition:\n background var(--transition-fast),\n color var(--transition-fast);\n }\n\n .cal-cell-head {\n height: var(--size-8);\n font-size: var(--text-xs);\n font-weight: var(--font-medium);\n color: var(--color-contrast-500);\n cursor: default;\n }\n\n .cal-cell-day {\n height: var(--size-8);\n color: var(--color-contrast-800);\n }\n\n .cal-cell-day:hover:not([data-disabled]) {\n color: var(--color-contrast-900);\n background: color-mix(in oklch, var(--_day-selected-bg) 15%, transparent);\n }\n\n .cal-cell-day:focus-visible {\n box-shadow: 0 0 0 2px var(--_day-selected-bg);\n }\n\n .cal-cell-day[data-today] {\n font-weight: var(--font-semibold);\n color: var(--_day-today-color);\n }\n\n .cal-cell-day[data-selected] {\n font-weight: var(--font-semibold);\n color: var(--color-white, #fff);\n background: var(--_day-selected-bg);\n }\n\n .cal-cell-day[data-outside] {\n opacity: var(--_day-outside-opacity);\n }\n\n .cal-cell-day[data-disabled] {\n pointer-events: none;\n cursor: not-allowed;\n opacity: 0.3;\n }\n\n /* ── Month / Year grids ──────────────────────────────────────────────────── */\n\n .cal-grid-months,\n .cal-grid-years {\n /* 4-column grid — same width as cal-grid-days, natural height. */\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n gap: var(--size-1);\n }\n\n .cal-cell-month,\n .cal-cell-year {\n height: var(--size-10);\n font-size: var(--text-sm);\n color: var(--color-contrast-800);\n cursor: pointer;\n border-radius: var(--rounded-md);\n }\n\n .cal-cell-month:hover:not([data-disabled]),\n .cal-cell-year:hover:not([data-disabled]) {\n background: color-mix(in oklch, var(--_day-selected-bg) 15%, transparent);\n }\n\n .cal-cell-month:focus-visible,\n .cal-cell-year:focus-visible {\n box-shadow: 0 0 0 2px var(--_day-selected-bg);\n }\n\n .cal-cell-month[data-selected],\n .cal-cell-year[data-selected] {\n font-weight: var(--font-semibold);\n color: var(--color-white, #fff);\n background: var(--_day-selected-bg);\n }\n\n .cal-cell-month[data-disabled],\n .cal-cell-year[data-disabled] {\n pointer-events: none;\n cursor: not-allowed;\n opacity: 0.3;\n }\n\n /* ── Reduced motion ──────────────────────────────────────────────────────── */\n\n @media (prefers-reduced-motion: reduce) {\n .field,\n .nav-btn,\n .cal-label-btn,\n .cal-cell {\n transition: none;\n }\n }\n}\n","import { define, useField, html, inject, prop } from '@vielzeug/ore';\nimport { computed, signal } from '@vielzeug/ripple';\nimport { Temporal, format } from '@vielzeug/tempo';\n\nimport type { ComponentSize, RoundedSize, ThemeColor, VisualVariant } from '../../shared';\n\nimport { createDatePickerControl, formatDisplayDate, parseIso, toIsoString, type DatePickerView } from '../../headless';\nimport '../../content/icon/icon';\nimport '../input/input';\nimport { disablableBundle, roundableBundle, sizableBundle, themableBundle } from '../../shared';\nimport { colorThemeMixin, reducedMotionMixin } from '../../styles';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport componentStyles from './date-picker.css?inline';\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport type OreDatePickerEvents = {\n change: { isoValue: string | null };\n};\n\nexport type OreDatePickerProps = {\n /** Theme color */\n color?: ThemeColor;\n /** Disable the picker */\n disabled?: boolean;\n /** Validation error message */\n error?: string;\n /** Expand to container width */\n fullwidth?: boolean;\n /** Helper text below the field */\n helper?: string;\n /** Visible label */\n label?: string;\n /** Label placement */\n 'label-placement'?: 'inset' | 'outside';\n /** Locale for day/month names (default: browser locale) */\n locale?: string;\n /** Latest selectable date in ISO 8601 format (yyyy-MM-dd) */\n max?: string;\n /** Earliest selectable date in ISO 8601 format (yyyy-MM-dd) */\n min?: string;\n /** Form field name */\n name?: string;\n /** Placeholder shown in the text trigger */\n placeholder?: string;\n /** Mark field as required */\n required?: boolean;\n /** Border radius */\n rounded?: RoundedSize;\n /** Component size */\n size?: ComponentSize;\n /**\n * Selected date in ISO 8601 format (yyyy-MM-dd).\n * @example '2025-06-15'\n */\n value?: string;\n /** Visual variant */\n variant?: Exclude<VisualVariant, 'text' | 'frost'>;\n /**\n * Day-of-week indices to disable (0 = Sunday … 6 = Saturday).\n * Pass as a JSON array attribute or a JS property.\n * @example\n * ```html\n * <ore-date-picker weekend-days=\"[0,6]\"></ore-date-picker>\n * ```\n */\n 'weekend-days'?: number[];\n};\n\n/**\n * An accessible, keyboard-navigable date picker with an inline calendar popup.\n * Supports min/max bounds, disabled weekend days, and form association.\n *\n * @element ore-date-picker\n *\n * @attr {string} value - Selected date in ISO 8601 format (yyyy-MM-dd)\n * @attr {string} min - Minimum selectable date (yyyy-MM-dd)\n * @attr {string} max - Maximum selectable date (yyyy-MM-dd)\n * @attr {string} label - Label text\n * @attr {string} label-placement - 'inset' | 'outside'\n * @attr {string} placeholder - Trigger placeholder\n * @attr {boolean} disabled - Disable the picker\n * @attr {boolean} required - Required field\n * @attr {string} name - Form field name\n * @attr {string} error - Error message\n * @attr {string} helper - Helper text\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'outline' | 'ghost'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n * @attr {string} locale - BCP 47 locale string\n * @attr {string} weekend-days - Comma-separated day indices to disable\n *\n * @fires change - Fired when a date is selected. detail: { isoValue: string | null }\n *\n * @slot label - Custom label for the trigger field\n * @slot prefix - Content before the trigger text (e.g. icon)\n * @slot helper - Custom helper text\n * @slot error - Custom error content\n *\n * @cssprop --date-picker-bg - Calendar background\n * @cssprop --date-picker-border-color - Calendar border color\n * @cssprop --date-picker-radius - Calendar border radius\n * @cssprop --date-picker-day-selected-bg - Background of selected day\n * @cssprop --date-picker-day-today-color - Color of today's date number\n * @cssprop --date-picker-day-outside-opacity - Opacity of days outside visible month\n *\n * @part field - The trigger button/field\n * @part calendar - The floating calendar panel\n * @part header - Calendar header (nav + label)\n * @part grid - Day grid\n * @part day - Individual day cell\n *\n * @example\n * ```html\n * <!-- Single date with constraints -->\n * <ore-date-picker label=\"Appointment date\" name=\"date\" min=\"2025-01-01\" max=\"2025-12-31\" color=\"primary\"></ore-date-picker>\n *\n *\n * <!-- Outside label, bordered variant -->\n * <ore-date-picker label=\"Start date\" label-placement=\"outside\" variant=\"bordered\"></ore-date-picker>\n * ```\n */\nexport const DATE_PICKER_TAG = 'ore-date-picker' as const;\n\ndefine<OreDatePickerProps, OreDatePickerEvents>(DATE_PICKER_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n ...roundableBundle,\n error: prop.string(),\n fullwidth: prop.bool(false),\n helper: prop.string(),\n label: prop.string(),\n 'label-placement': prop.oneOf(['inset', 'outside'] as const, 'inset'),\n locale: prop.string(),\n max: prop.string(),\n min: prop.string(),\n name: prop.string(),\n placeholder: prop.string(),\n required: prop.bool(false),\n value: prop.string(),\n variant: prop.string<'flat' | 'solid' | 'bordered' | 'outline' | 'ghost'>(),\n 'weekend-days': prop.json([] as number[]),\n },\n\n setup(props, { bind, el, emit, onMounted }) {\n // ── Signals ─────────────────────────────────────────────────────────────\n\n const isOpen = signal(false);\n\n // ── Selected date: local-override pattern ──────────────────────────────\n // localSelection holds a user-initiated pick (or undefined = no override).\n // selectedDate falls back to the value prop reactively — no setInterval needed.\n\n const localSelection = signal<Temporal.PlainDate | null | undefined>(undefined);\n\n const selectedDate = computed(() =>\n localSelection.value !== undefined ? localSelection.value : parseIso(props.value.value),\n );\n\n // ── Form context ────────────────────────────────────────────────────────\n\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(bind, props, formCtx);\n\n const isDisabled = fCtxProps.disabled;\n const locale = computed(() => props.locale.value || (typeof navigator !== 'undefined' ? navigator.language : 'en'));\n\n // ── Date-picker control ─────────────────────────────────────────────────\n\n const ctrl = createDatePickerControl({\n get locale() {\n return locale.value;\n },\n get max() {\n return parseIso(props.max.value);\n },\n get min() {\n return parseIso(props.min.value);\n },\n onChange(date) {\n localSelection.value = date;\n isOpen.value = false;\n ctrl.setView('day');\n currentView.value = 'day';\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n emit('change', { isoValue: toIsoString(date) });\n },\n get value() {\n return selectedDate.value;\n },\n get weekendDays() {\n return props['weekend-days'].value ?? [];\n },\n });\n\n // ── Reactive display state ────────────────────────────────────────────\n // Three separate primitive signals — the proven pattern.\n\n const currentView = signal<DatePickerView>('day');\n const displayYear = signal(ctrl.displayYear());\n const displayMonth = signal(ctrl.displayMonth()); // 1-indexed (Temporal)\n\n // ── Form value (host is formAssociated) ──────────────────────────────────\n\n useField<string>({\n disabled: isDisabled,\n toFormValue: (v) => v || null,\n value: computed(() => toIsoString(selectedDate.value) ?? ''),\n });\n\n const dialogId = `date-picker-${Math.random().toString(36).slice(2, 9)}-calendar`;\n\n // ── Derived display values ───────────────────────────────────────────────\n\n const triggerText = computed(() => {\n if (selectedDate.value) return formatDisplayDate(selectedDate.value, locale.value);\n\n return props.placeholder.value || '';\n });\n\n const displayMonth_ = computed(() => {\n const d = Temporal.PlainDate.from({ day: 1, month: displayMonth.value, year: displayYear.value });\n\n return format(d, { intl: { month: 'long' }, locale: locale.value, tz: 'UTC' });\n });\n\n const displayYear_ = computed(() => String(displayYear.value));\n const displayLabel = computed(() => `${displayMonth_.value} ${displayYear_.value}`);\n\n const dayCells = computed(() => {\n void displayYear.value;\n void displayMonth.value;\n void selectedDate.value; // re-run when selection changes to refresh isSelected flags\n\n return ctrl.dayCells();\n });\n const monthCells = computed(() => {\n void displayYear.value;\n\n return ctrl.monthCells();\n });\n const yearCells = computed(() => {\n void displayYear.value;\n\n return ctrl.yearCells();\n });\n const weekdayLabels = computed(() => ctrl.weekdayLabels());\n const tabIndex = () => (isDisabled.value ? '-1' : '0');\n\n // ── Navigation handlers ──────────────────────────────────────────────────\n // In year/month views navigate by year; in day view navigate by month.\n\n function handlePrev(): void {\n if (currentView.value === 'day') ctrl.prevMonth();\n else ctrl.prevYear();\n\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n }\n\n function handleNext(): void {\n if (currentView.value === 'day') ctrl.nextMonth();\n else ctrl.nextYear();\n\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n }\n\n function handleHeaderClick(): void {\n const views: DatePickerView[] = ['day', 'month', 'year'];\n const next = views[(views.indexOf(currentView.value) + 1) % views.length];\n\n ctrl.setView(next);\n currentView.value = next;\n }\n\n function handleSelectMonth(month: number): void {\n ctrl.goTo(ctrl.displayYear(), month);\n ctrl.setView('day');\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n currentView.value = 'day';\n }\n\n function handleSelectYear(year: number): void {\n ctrl.goTo(year, ctrl.displayMonth());\n ctrl.setView('month');\n displayYear.value = ctrl.displayYear();\n currentView.value = 'month';\n }\n\n function handleSelectDay(isoStr: string): void {\n const date = parseIso(isoStr);\n\n if (!date) return;\n\n ctrl.select(date);\n }\n\n function handleDayKeydown(e: KeyboardEvent): void {\n const cell = e.currentTarget as HTMLElement;\n const grid = cell.closest('.cal-grid-days');\n\n if (!grid) return;\n\n const allCells = Array.from(grid.querySelectorAll<HTMLElement>('.cal-cell-day'));\n const idx = allCells.indexOf(cell);\n\n if (idx === -1) return;\n\n let target: HTMLElement | undefined;\n\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleSelectDay(cell.dataset.iso ?? '');\n\n return;\n } else if (e.key === 'ArrowRight') {\n target = allCells[idx + 1];\n } else if (e.key === 'ArrowLeft') {\n target = allCells[idx - 1];\n } else if (e.key === 'ArrowDown') {\n target = allCells[idx + 7];\n } else if (e.key === 'ArrowUp') {\n target = allCells[idx - 7];\n } else if (e.key === 'Home') {\n target = allCells[Math.floor(idx / 7) * 7];\n } else if (e.key === 'End') {\n target = allCells[Math.floor(idx / 7) * 7 + 6];\n } else {\n return;\n }\n\n e.preventDefault();\n target?.focus();\n }\n\n // ── Month/year-cell keyboard navigation (fixed 4-column grid) ─────────────\n\n function handleGridKeydown(e: KeyboardEvent, cellSelector: string, columns: number, onSelect: () => void): void {\n const cell = e.currentTarget as HTMLElement;\n const grid = cell.closest('.cal-grid');\n\n if (!grid) return;\n\n const allCells = Array.from(grid.querySelectorAll<HTMLElement>(cellSelector));\n const idx = allCells.indexOf(cell);\n\n if (idx === -1) return;\n\n let target: HTMLElement | undefined;\n\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onSelect();\n\n return;\n } else if (e.key === 'ArrowRight') {\n target = allCells[idx + 1];\n } else if (e.key === 'ArrowLeft') {\n target = allCells[idx - 1];\n } else if (e.key === 'ArrowDown') {\n target = allCells[idx + columns];\n } else if (e.key === 'ArrowUp') {\n target = allCells[idx - columns];\n } else if (e.key === 'Home') {\n target = allCells[Math.floor(idx / columns) * columns];\n } else if (e.key === 'End') {\n target = allCells[Math.min(Math.floor(idx / columns) * columns + columns - 1, allCells.length - 1)];\n } else {\n return;\n }\n\n e.preventDefault();\n target?.focus();\n }\n\n // ── Open / close ─────────────────────────────────────────────────────────\n\n function openPicker(): void {\n if (isDisabled.value) return;\n\n isOpen.value = true;\n ctrl.setView('day');\n currentView.value = 'day';\n\n const sel = selectedDate.value;\n\n if (sel) {\n ctrl.goTo(sel.year, sel.month);\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n }\n }\n\n function closePicker(): void {\n isOpen.value = false;\n ctrl.setView('day');\n currentView.value = 'day';\n }\n\n function handleTriggerClick(): void {\n if (isOpen.value) closePicker();\n else openPicker();\n }\n\n // ── Keyboard handlers ────────────────────────────────────────────────────\n\n function handleTriggerKeydown(e: KeyboardEvent): void {\n if (isDisabled.value) return;\n\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleTriggerClick();\n } else if (e.key === 'Escape' && isOpen.value) {\n e.preventDefault();\n closePicker();\n }\n }\n\n function handleCalendarKeydown(e: KeyboardEvent): void {\n if (e.key === 'Escape') {\n e.preventDefault();\n closePicker();\n }\n }\n\n function handleOutsideClick(e: PointerEvent | MouseEvent): void {\n if (!isOpen.value) return;\n\n const path = e.composedPath();\n\n if (!path.includes(el)) closePicker();\n }\n\n // ── Lifecycle ────────────────────────────────────────────────────────────\n\n onMounted(() => {\n document.addEventListener('pointerdown', handleOutsideClick, { capture: true });\n\n return () => {\n document.removeEventListener('pointerdown', handleOutsideClick, { capture: true });\n };\n });\n\n // ── Host bindings ────────────────────────────────────────────────────────\n\n bind({\n attr: {\n open: () => (isOpen.value ? true : undefined),\n },\n });\n\n // ── Template ─────────────────────────────────────────────────────────────\n\n const inputValue = () => triggerText.value;\n const inputLabel = () => props.label.value ?? '';\n const inputPlaceholder = () => props.placeholder.value ?? '';\n const inputLabelPlacement = () => props['label-placement'].value ?? 'inset';\n const inputColor = () => props.color?.value ?? undefined;\n const inputSize = () => fCtxProps.size?.value ?? undefined;\n const inputVariant = () => fCtxProps.variant?.value ?? undefined;\n const inputRounded = () => props.rounded?.value ?? undefined;\n const inputHelper = () => props.helper.value ?? '';\n const inputError = () => props.error.value ?? '';\n const inputDisabled = () => (isDisabled.value ? true : undefined);\n const inputRequired = () => (props.required.value ? true : undefined);\n const inputFullwidth = () => (props.fullwidth.value ? true : undefined);\n\n return html`\n <!-- Trigger: ore-input in readonly display mode -->\n <ore-input\n class=\"trigger\"\n readonly\n tabindex=\"${tabIndex}\"\n role=\"combobox\"\n aria-haspopup=\"dialog\"\n aria-controls=\"${dialogId}\"\n :aria-expanded=\"${() => String(isOpen.value)}\"\n :aria-disabled=\"${() => (isDisabled.value ? 'true' : null)}\"\n :value=\"${inputValue}\"\n :label=\"${inputLabel}\"\n :placeholder=\"${inputPlaceholder}\"\n :label-placement=\"${inputLabelPlacement}\"\n :color=\"${inputColor}\"\n :size=\"${inputSize}\"\n :variant=\"${inputVariant}\"\n :rounded=\"${inputRounded}\"\n :helper=\"${inputHelper}\"\n :error=\"${inputError}\"\n ?disabled=\"${inputDisabled}\"\n ?required=\"${inputRequired}\"\n ?fullwidth=\"${inputFullwidth}\"\n @click=\"${handleTriggerClick}\"\n @keydown=\"${handleTriggerKeydown}\">\n <ore-icon slot=\"suffix\" name=\"calendar\" size=\"16\" stroke-width=\"1.75\" aria-hidden=\"true\"></ore-icon>\n </ore-input>\n\n <!-- Calendar popup -->\n <div\n class=\"calendar\"\n id=\"${dialogId}\"\n role=\"dialog\"\n aria-modal=\"true\"\n :aria-label=\"${() => `Choose date — ${displayLabel.value}`}\"\n ?data-open=\"${isOpen}\"\n @keydown=\"${handleCalendarKeydown}\">\n <!-- Calendar header -->\n <div class=\"cal-header\" part=\"header\">\n <button class=\"nav-btn\" type=\"button\" aria-label=\"Previous\" @click=\"${handlePrev}\">\n <ore-icon name=\"chevron-left\" size=\"16\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </button>\n <button\n class=\"cal-label-btn\"\n type=\"button\"\n :aria-label=\"${() =>\n `Switch to ${currentView.value === 'day' ? 'month' : currentView.value === 'month' ? 'year' : 'day'} view`}\"\n @click=\"${handleHeaderClick}\">\n <span class=\"cal-label-month\">${displayMonth_}</span><span class=\"cal-label-sep\" aria-hidden=\"true\">/</span\n ><span class=\"cal-label-year\">${displayYear_}</span>\n </button>\n <button class=\"nav-btn\" type=\"button\" aria-label=\"Next\" @click=\"${handleNext}\">\n <ore-icon name=\"chevron-right\" size=\"16\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </button>\n </div>\n\n <!-- Day view: flat 7-column CSS grid, weekday headers + day cells -->\n <div\n class=\"cal-grid cal-grid-days\"\n role=\"grid\"\n part=\"grid\"\n :aria-label=\"${() => displayLabel.value}\"\n ?hidden=\"${() => currentView.value !== 'day'}\">\n <div role=\"row\" class=\"cal-grid-row\">\n ${() =>\n weekdayLabels.value.map(\n (lbl) => html`<div class=\"cal-cell cal-cell-head\" role=\"columnheader\" aria-label=\"${lbl}\">${lbl}</div>`,\n )}\n </div>\n ${() => {\n const cells = dayCells.value;\n const rows: (typeof cells)[number][][] = [];\n\n for (let i = 0; i < cells.length; i += 7) rows.push(cells.slice(i, i + 7));\n\n return rows.map(\n (row) =>\n html`<div role=\"row\" class=\"cal-grid-row\">\n ${row.map(\n (cell) =>\n html`<div\n class=\"cal-cell cal-cell-day\"\n role=\"gridcell\"\n part=\"day\"\n :aria-selected=\"${() => String(cell.isSelected)}\"\n :aria-disabled=\"${() => String(cell.isDisabled)}\"\n :aria-current=\"${() => (cell.isToday ? 'date' : null)}\"\n ?data-selected=\"${() => cell.isSelected}\"\n ?data-today=\"${() => cell.isToday}\"\n ?data-outside=\"${() => cell.isOutsideMonth}\"\n ?data-disabled=\"${() => cell.isDisabled}\"\n data-iso=\"${cell.iso}\"\n tabindex=\"${() => (cell.isDisabled ? '-1' : '0')}\"\n @click=\"${() => handleSelectDay(cell.iso)}\"\n @keydown=\"${handleDayKeydown}\">\n ${String(cell.day)}\n </div>`,\n )}\n </div>`,\n );\n }}\n </div>\n\n <!-- Month view -->\n <div\n class=\"cal-grid cal-grid-months\"\n role=\"grid\"\n :aria-label=\"${() => displayYear_.value}\"\n ?hidden=\"${() => currentView.value !== 'month'}\">\n ${() => {\n const cells = monthCells.value;\n const rows: (typeof cells)[number][][] = [];\n\n for (let i = 0; i < cells.length; i += 4) rows.push(cells.slice(i, i + 4));\n\n return rows.map(\n (row) =>\n html`<div role=\"row\">\n ${row.map(\n (cell) =>\n html`<div\n class=\"cal-cell cal-cell-month\"\n role=\"gridcell\"\n :aria-selected=\"${() => String(cell.isSelected)}\"\n :aria-disabled=\"${() => String(cell.isDisabled)}\"\n ?data-selected=\"${() => cell.isSelected}\"\n ?data-disabled=\"${() => cell.isDisabled}\"\n tabindex=\"${() => (cell.isDisabled ? '-1' : '0')}\"\n @click=\"${() => {\n if (!cell.isDisabled) handleSelectMonth(cell.month);\n }}\"\n @keydown=\"${(e: KeyboardEvent) =>\n handleGridKeydown(e, '.cal-cell-month', 4, () => {\n if (!cell.isDisabled) handleSelectMonth(cell.month);\n })}\">\n ${cell.shortLabel}\n </div>`,\n )}\n </div>`,\n );\n }}\n </div>\n\n <!-- Year view -->\n <div\n class=\"cal-grid cal-grid-years\"\n role=\"grid\"\n aria-label=\"Select year\"\n ?hidden=\"${() => currentView.value !== 'year'}\">\n ${() => {\n const cells = yearCells.value;\n const rows: (typeof cells)[number][][] = [];\n\n for (let i = 0; i < cells.length; i += 4) rows.push(cells.slice(i, i + 4));\n\n return rows.map(\n (row) =>\n html`<div role=\"row\">\n ${row.map(\n (cell) =>\n html`<div\n class=\"cal-cell cal-cell-year\"\n role=\"gridcell\"\n :aria-selected=\"${() => String(cell.isSelected)}\"\n :aria-disabled=\"${() => String(cell.isDisabled)}\"\n ?data-selected=\"${() => cell.isSelected}\"\n ?data-disabled=\"${() => cell.isDisabled}\"\n tabindex=\"${() => (cell.isDisabled ? '-1' : '0')}\"\n @click=\"${() => {\n if (!cell.isDisabled) handleSelectYear(cell.year);\n }}\"\n @keydown=\"${(e: KeyboardEvent) =>\n handleGridKeydown(e, '.cal-cell-year', 4, () => {\n if (!cell.isDisabled) handleSelectYear(cell.year);\n })}\">\n ${String(cell.year)}\n </div>`,\n )}\n </div>`,\n );\n }}\n </div>\n </div>\n `;\n },\n\n shadow: { delegatesFocus: true },\n styles: [colorThemeMixin, reducedMotionMixin, componentStyles],\n});\n","@layer refine.base {\n :host {\n --_font-size: var(--file-input-font-size, var(--text-sm));\n --_radius: var(--file-input-radius, var(--rounded-lg));\n --_bg: var(--file-input-bg, var(--color-contrast-100));\n --_border-color: var(--file-input-border-color, var(--color-contrast-300));\n --_min-height: var(--file-input-min-height, var(--size-36));\n\n display: inline-flex;\n flex-direction: column;\n align-items: stretch;\n }\n\n .file-input-wrapper {\n display: flex;\n flex-direction: column;\n gap: var(--size-1-5);\n width: 100%;\n }\n\n /* ========================================\n Label\n ======================================== */\n\n .label-outside {\n font-size: var(--text-sm);\n font-weight: var(--font-medium);\n line-height: var(--leading-none);\n color: var(--color-contrast-500);\n cursor: default;\n user-select: none;\n transition: color var(--transition-fast);\n }\n\n /* ========================================\n Dropzone\n ======================================== */\n\n .dropzone {\n position: relative;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: var(--size-2);\n align-items: center;\n justify-content: center;\n min-height: var(--_min-height);\n padding: var(--size-6) var(--size-4);\n text-align: center;\n cursor: pointer;\n outline: none;\n background: var(--_bg);\n border: var(--border-2) dashed var(--_border-color);\n border-radius: var(--_radius);\n transition:\n background var(--transition-fast),\n border-color var(--transition-fast),\n box-shadow var(--transition-fast);\n }\n\n .dropzone-content {\n display: flex;\n flex-direction: column;\n gap: var(--size-2);\n align-items: center;\n pointer-events: none;\n }\n\n .dropzone-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--color-contrast-400);\n transition:\n color var(--transition-fast),\n transform var(--transition-fast);\n }\n\n .dropzone-title {\n font-size: var(--_font-size);\n font-weight: var(--font-medium);\n line-height: var(--leading-snug);\n color: var(--color-contrast-700);\n }\n\n .dropzone-title u {\n color: var(--_theme-focus, var(--color-primary));\n text-decoration: underline;\n text-decoration-color: transparent;\n text-underline-offset: 2px;\n transition: text-decoration-color var(--transition-fast);\n }\n\n .dropzone-hint {\n font-size: var(--text-xs);\n line-height: var(--leading-tight);\n color: var(--color-contrast-400);\n }\n\n /* ========================================\n Helper Text\n ======================================== */\n\n .helper-text[hidden] {\n display: none;\n }\n\n .helper-text {\n padding-inline: 2px;\n font-size: var(--text-xs);\n line-height: var(--leading-tight);\n color: var(--color-contrast-500);\n }\n\n /* ========================================\n File List\n ======================================== */\n\n .file-list {\n display: flex;\n flex-direction: column;\n gap: var(--size-1);\n padding: 0;\n margin: 0;\n list-style: none;\n }\n\n .file-item {\n box-sizing: border-box;\n display: flex;\n gap: var(--size-3);\n align-items: center;\n padding: var(--size-2) var(--size-3);\n background: var(--color-contrast-50);\n border: var(--border) solid var(--color-contrast-200);\n border-radius: var(--_radius);\n transition: background var(--transition-fast);\n }\n\n .file-item:hover {\n background: var(--color-contrast-100);\n }\n\n .file-icon {\n flex-shrink: 0;\n color: var(--_theme-focus, var(--color-primary));\n }\n\n .file-meta {\n display: flex;\n flex: 1;\n flex-direction: column;\n gap: var(--size-0-5);\n min-width: 0;\n }\n\n .file-name {\n overflow: hidden;\n text-overflow: ellipsis;\n font-size: var(--text-sm);\n font-weight: var(--font-medium);\n color: var(--color-contrast-700);\n white-space: nowrap;\n }\n\n .file-size {\n font-size: var(--text-xs);\n color: var(--color-contrast-400);\n }\n\n .file-remove {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n padding: var(--size-1);\n color: var(--color-contrast-400);\n cursor: pointer;\n background: transparent;\n border: none;\n border-radius: var(--rounded-sm);\n transition:\n color var(--transition-fast),\n background var(--transition-fast);\n }\n\n .file-remove:hover {\n color: var(--color-error);\n background: var(--color-error-backdrop, color-mix(in oklch, var(--color-error) 12%, transparent));\n }\n\n /* ========================================\n Hover & Focus\n ======================================== */\n\n :host(:not([disabled])) .dropzone:hover {\n border-color: var(--color-contrast-400);\n }\n\n :host(:not([disabled])) .dropzone:hover .dropzone-title u {\n text-decoration-color: var(--_theme-focus, var(--color-primary));\n }\n\n :host(:not([disabled])) .dropzone:focus-visible {\n border-color: var(--_theme-focus, var(--color-primary));\n box-shadow: var(--_theme-shadow, var(--color-primary-focus-shadow));\n }\n\n :host(:not([disabled])) .dropzone:hover .dropzone-icon,\n :host(:not([disabled])) .dropzone:focus-visible .dropzone-icon {\n color: var(--_theme-focus, var(--color-primary));\n transform: translateY(-1px);\n }\n\n /* ========================================\n Drag-Over State\n ======================================== */\n\n :host([drag-over]) .dropzone {\n background: color-mix(in oklch, var(--_theme-base, var(--color-primary)) 8%, var(--color-canvas));\n border-color: var(--_theme-focus, var(--color-primary));\n box-shadow: var(--_theme-shadow, var(--color-primary-focus-shadow));\n }\n\n :host([drag-over]) .dropzone .dropzone-icon {\n color: var(--_theme-focus, var(--color-primary));\n transform: translateY(-2px) scale(1.05);\n }\n\n /* ========================================\n Error State\n ======================================== */\n\n :host([invalid]) .dropzone {\n border-color: var(--color-error);\n }\n\n :host([invalid]) .label-outside {\n color: var(--color-error);\n }\n\n /* ========================================\n Error Text\n ======================================== */\n\n .helper-text-error {\n color: var(--color-error);\n }\n}\n\n@layer refine.variants {\n /* Solid (Default) */\n :host(:not([variant])),\n :host([variant='solid']) {\n --_bg: var(--file-input-bg, var(--color-contrast-50));\n --_border-color: var(--file-input-border-color, var(--color-contrast-300));\n }\n\n /* Flat */\n :host([variant='flat']) {\n --_bg: var(--file-input-bg, var(--color-contrast-100));\n --_border-color: var(--file-input-border-color, var(--_theme-border));\n }\n\n :host([variant='flat']) .dropzone:hover {\n background: var(--file-input-hover-bg, color-mix(in oklch, var(--_theme-base) 6%, var(--color-contrast-100)));\n border-color: var(\n --file-input-hover-border-color,\n color-mix(in oklch, var(--_theme-base) 35%, var(--color-contrast-300))\n );\n }\n\n :host([variant='flat']) .dropzone:focus-visible,\n :host([variant='flat'][drag-over]) .dropzone {\n background: var(--file-input-focus-bg, color-mix(in oklch, var(--_theme-base) 8%, var(--color-canvas)));\n border-color: var(--file-input-focus-border-color, color-mix(in oklch, var(--_theme-focus) 60%, transparent));\n box-shadow: var(--_theme-shadow);\n }\n\n /* Bordered */\n :host([variant='bordered']) {\n --_bg: var(--file-input-bg, var(--_theme-backdrop));\n --_border-color: var(--file-input-border-color, color-mix(in oklch, var(--_theme-focus) 70%, transparent));\n }\n\n :host([variant='bordered']) .dropzone:hover {\n border-color: var(--file-input-hover-border-color, var(--_theme-focus));\n }\n\n /* Outline */\n :host([variant='outline']) {\n --_bg: var(--file-input-bg, transparent);\n }\n\n /* Ghost */\n :host([variant='ghost']) {\n --_bg: var(--file-input-bg, transparent);\n --_border-color: var(--file-input-border-color, var(--color-contrast-200));\n }\n\n :host([variant='ghost']) .dropzone:hover {\n background: var(--file-input-hover-bg, var(--color-contrast-100));\n }\n}\n\n@layer refine.utilities {\n :host([fullwidth]) {\n width: 100%;\n }\n}\n","import { createDropZone, matchesAccept } from '@vielzeug/dnd';\nimport { createStableId, define, useField, html, inject, prop, ref } from '@vielzeug/ore';\nimport { computed, signal, watch } from '@vielzeug/ripple';\n\nimport { createInteraction } from '../../headless';\nimport { FILE_INPUT_SIZE_PRESET } from '../../shared';\nimport { fieldMixins, forcedColorsFocusMixin, sizeVariantMixin } from '../../styles';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport componentStyles from './file-input.css?inline';\n\nconst formatBytes = (bytes: number) => {\n if (bytes === 0) return '0 B';\n\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n\n return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];\n};\n\nconst isFileSizeAllowed = (file: File, maxSize?: number) => !maxSize || file.size <= maxSize;\n\n/** File input component properties */\nexport type OreFileInputProps = {\n /** Accepted file types (comma-separated, e.g. '.jpg, .png, image/*') */\n accept?: string;\n /** Theme color tint */\n color?: string;\n /** Disabled state */\n disabled?: boolean;\n /** Error message text */\n error?: string;\n /** Helper text displayed below the input */\n helper?: string;\n /** Input label text */\n label?: string;\n /** Max number of files allowed (only used if multiple is true) */\n 'max-files'?: number;\n /** Max size of a single file in bytes */\n 'max-size'?: number;\n /** Allow multiple files selection */\n multiple?: boolean;\n /** Form field name */\n name?: string;\n /**\n * JS-only callback fired with the inner `<input type=\"file\">` element when it\n * mounts, and with `null` when it unmounts. Intended for composed components\n * that need imperative access to the raw element.\n * Set as a JS property: `bitFileInput.ref = (el) => { ... }`.\n */\n ref?: ((el: HTMLInputElement | null) => void) | null;\n /** Required field */\n required?: boolean;\n /** Field size preset */\n size?: string;\n};\n\n/** Events emitted by the file-input component */\nexport type OreFileInputEvents = {\n /** Emitted when files are added or removed */\n change: { files: File[]; originalEvent?: Event; value: File[] };\n /** Emitted when a specific file is removed */\n remove: { file: File; files: File[]; originalEvent?: Event; value: File[] };\n};\n\n/**\n * A file upload field with drag-and-drop support and built-in validation messaging.\n *\n * @element ore-file-input\n *\n * @attr {string} accept - Comma-separated file extensions or MIME types\n * @attr {boolean} multiple - Enable multiple files selection\n * @attr {number} max-files - Max number of files allowed\n * @attr {number} max-size - Max size of each file in bytes\n * @attr {boolean} disabled - Disable interaction\n * @attr {string} error - Show an error state/message\n * @attr {string} helper - Provide helper context below the dropzone\n *\n * @fires change - detail: { files: File[], value: File[] }\n * @fires remove - detail: { file: File, files: File[] }\n *\n * @cssprop --file-input-bg - Dropzone background color\n * @cssprop --file-input-border-color - Dropzone border color\n * @cssprop --file-input-font-size - Font size\n * @cssprop --file-input-radius - Dropzone border radius\n * @cssprop --file-input-min-height - Minimum dropzone height\n * @cssprop --file-input-hover-bg - Dropzone background on hover (flat/ghost variants)\n * @cssprop --file-input-hover-border-color - Dropzone border on hover (flat/bordered variants)\n * @cssprop --file-input-focus-bg - Dropzone background when focused/drag-over (flat variant)\n * @cssprop --file-input-focus-border-color - Dropzone border when focused/drag-over (flat variant)\n * @part wrapper - Root wrapper around the file input field\n * @part label - Visible label rendered above the dropzone\n * @part dropzone - Interactive drag-and-drop target\n * @part input - Native file input element\n * @part helper - Helper text shown beneath the dropzone\n * @part error - Error message shown beneath the field\n * @example\n * ```html\n * <ore-file-input label=\"Upload files\" accept=\"image/*\" multiple />\n * <ore-file-input label=\"Resume\" accept=\".pdf,.doc,.docx\" max-size=\"5242880\" />\n * <ore-file-input variant=\"bordered\" color=\"primary\" />\n * ```\n */\nexport const FILE_INPUT_TAG = 'ore-file-input' as const;\ndefine<OreFileInputProps, OreFileInputEvents>(FILE_INPUT_TAG, {\n formAssociated: true,\n props: {\n accept: prop.string(),\n color: prop.string(),\n disabled: prop.bool(false),\n error: prop.string(),\n helper: prop.string(),\n label: prop.string(),\n 'max-files': prop.number(0),\n 'max-size': prop.number(0),\n multiple: prop.bool(false),\n name: prop.string(),\n ref: prop.json(undefined as ((el: HTMLInputElement | null) => void) | null | undefined),\n required: prop.bool(false),\n size: prop.string(),\n },\n setup(props, { bind, emit, onCleanup, onElement, onEvent, onMounted }) {\n // ============================================\n // State\n // ============================================\n\n const files = signal<File[]>([]);\n const isDragging = signal(false);\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(bind, props, formCtx);\n const isDisabled = fCtxProps.disabled;\n const maxFilesLimit = computed(() => props['max-files'].value ?? 0);\n const maxSizeLimit = computed(() => props['max-size'].value ?? 0);\n\n // ============================================\n // Form Integration\n // ============================================\n\n useField({\n disabled: isDisabled,\n toFormValue: (fi: File[]) => {\n if (fi.length === 0) return null;\n\n const name = props.name.value || 'file';\n const fd = new FormData();\n\n for (const file of fi) fd.append(name, file);\n\n return fd;\n },\n value: files,\n });\n\n // Sync host attributes for CSS selectors\n const isInvalid = computed(() => Boolean(props.error.value));\n\n bind({\n attr: {\n 'drag-over': () => (isDragging.value ? true : undefined),\n invalid: () => (isInvalid.value ? true : undefined),\n size: fCtxProps.size,\n },\n });\n\n // ============================================\n // IDs\n // ============================================\n const fileInputId = createStableId('file-input');\n const labelId = `label-${fileInputId}`;\n const helperId = `helper-${fileInputId}`;\n const errorId = `error-${fileInputId}`;\n\n // ============================================\n // Refs\n // ============================================\n const dropzoneRef = ref<HTMLDivElement>();\n const inputRef = ref<HTMLInputElement>();\n const hintText = computed(() => {\n const parts: string[] = [];\n\n if (props.accept.value) {\n parts.push(\n props.accept.value\n .split(',')\n .map((s: string) => s.trim())\n .join(', '),\n );\n }\n\n const maxSize = maxSizeLimit.value;\n\n if (maxSize > 0) parts.push(`max ${formatBytes(maxSize)}`);\n\n const maxFiles = maxFilesLimit.value;\n\n if (maxFiles > 0) parts.push(`up to ${maxFiles} file${maxFiles !== 1 ? 's' : ''}`);\n\n return parts.join(' · ');\n });\n\n // ============================================\n // File Management\n // ============================================\n function addFiles(newFiles: File[], originalEvent?: Event): void {\n if (isDisabled.value) return;\n\n const acceptVal = props.accept.value;\n const isMultiple = Boolean(props.multiple.value);\n let incoming = Array.from(newFiles);\n\n if (!isMultiple) incoming = incoming.slice(0, 1);\n\n incoming = incoming.filter(\n (f) =>\n matchesAccept(f, acceptVal ? acceptVal.split(',').map((t) => t.trim()) : []) &&\n isFileSizeAllowed(f, maxSizeLimit.value),\n );\n\n let updated: File[] = isMultiple ? [...files.value] : [];\n\n for (const f of incoming) {\n if (!updated.includes(f)) updated.push(f);\n }\n\n if (maxFilesLimit.value > 0 && updated.length > maxFilesLimit.value) {\n updated = updated.slice(0, maxFilesLimit.value);\n }\n\n files.value = updated;\n emit('change', { files: files.value, originalEvent, value: files.value });\n }\n function removeFile(file: File, originalEvent?: Event): void {\n files.value = files.value.filter((f) => f !== file);\n emit('remove', { file, files: files.value, originalEvent, value: files.value });\n emit('change', { files: files.value, originalEvent, value: files.value });\n }\n\n // ============================================\n // Mount\n // ============================================\n // ============================================\n // Template\n // ============================================\n onElement(inputRef, (inp) => {\n props.ref.value?.(inp);\n\n const sub = watch(props.ref, (cb) => {\n cb?.(inp);\n });\n\n return () => {\n sub.dispose();\n props.ref.value?.(null);\n };\n });\n\n onMounted(() => {\n const inp = inputRef.value!;\n const dz = dropzoneRef.value!;\n let skipNextClick = false;\n const pressControl = createInteraction({\n disabled: isDisabled,\n onPress: () => {\n inp.click();\n },\n });\n\n // Native input → add files\n onEvent(inp, 'change', (e: Event) => {\n const input = e.target as HTMLInputElement;\n\n if (input.files?.length) addFiles(Array.from(input.files), e);\n\n input.value = ''; // reset so the same file triggers change again\n });\n // Click dropzone → open file picker\n onEvent(dz, 'click', (e: MouseEvent) => {\n if (e.target === inp) return;\n\n if (skipNextClick) {\n skipNextClick = false;\n\n return;\n }\n\n if (!isDisabled.value) inp.click();\n });\n // Keyboard: Enter / Space → open picker\n onEvent(dz, 'keydown', (e: KeyboardEvent) => {\n skipNextClick = pressControl.handleKeydown(e) && e.key === 'Enter';\n });\n\n const dropZone = createDropZone({\n disabled: isDisabled.value,\n element: dz,\n onDrop: (droppedFiles) => addFiles(droppedFiles),\n onHoverChange: (hovered) => {\n isDragging.value = hovered;\n },\n });\n\n onCleanup(() => dropZone.dispose());\n });\n\n return html`\n <div class=\"file-input-wrapper\" part=\"wrapper\">\n <label class=\"label-outside\" id=\"${labelId}\" part=\"label\" ?hidden=${() => !props.label.value}\n >${props.label}</label\n >\n <div\n class=\"dropzone\"\n part=\"dropzone\"\n ref=${dropzoneRef}\n role=\"button\"\n :tabindex=\"${() => (isDisabled.value ? '-1' : '0')}\"\n :aria-disabled=\"${() => String(isDisabled.value)}\"\n :aria-label=\"${() => (!props.label.value ? 'File upload drop zone' : null)}\"\n :aria-labelledby=\"${() => (props.label.value ? labelId : null)}\"\n aria-describedby=\"${helperId}\">\n <input\n type=\"file\"\n ref=${inputRef}\n part=\"input\"\n id=\"${fileInputId}\"\n :accept=\"${props.accept}\"\n ?multiple=\"${props.multiple}\"\n ?required=\"${props.required}\"\n ?disabled=\"${isDisabled}\"\n :name=\"${props.name}\"\n hidden\n inert\n tabindex=\"-1\" />\n <div class=\"dropzone-content\">\n <span class=\"dropzone-icon\" aria-hidden=\"true\">\n <ore-icon name=\"upload\" size=\"36\" stroke-width=\"1.5\" aria-hidden=\"true\"></ore-icon>\n </span>\n <span class=\"dropzone-title\">Drop files here or <u>click to browse</u></span>\n <span class=\"dropzone-hint\" ?hidden=${() => !hintText.value}>${hintText}</span>\n </div>\n </div>\n <ul class=\"file-list\" role=\"list\" aria-label=\"Selected files\" ?hidden=${() => files.value.length === 0}>\n ${() =>\n files.value.map(\n (file: File) => html`\n <li class=\"file-item\">\n <span class=\"file-icon\" aria-hidden=\"true\">\n <ore-icon name=\"file\" size=\"18\" stroke-width=\"1.75\" aria-hidden=\"true\"></ore-icon>\n </span>\n <span class=\"file-meta\">\n <span class=\"file-name\" title=\"${file.name}\">${file.name}</span>\n <span class=\"file-size\">${formatBytes(file.size)}</span>\n </span>\n <button\n class=\"file-remove\"\n type=\"button\"\n aria-label=\"${`Remove ${file.name}`}\"\n @click=${(e: Event) => removeFile(file, e)}>\n <ore-icon name=\"x\" size=\"12\" stroke-width=\"2.5\" aria-hidden=\"true\"></ore-icon>\n </button>\n </li>\n `,\n )}\n </ul>\n <div class=\"helper-text\" id=\"${helperId}\" part=\"helper\" ?hidden=${() => isInvalid.value || !props.helper.value}>\n ${props.helper}\n </div>\n <div\n class=\"helper-text helper-text-error\"\n id=\"${errorId}\"\n role=\"alert\"\n part=\"error\"\n ?hidden=${() => !isInvalid.value}>\n ${() => props.error.value ?? ''}\n </div>\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [\n ...fieldMixins,\n sizeVariantMixin(FILE_INPUT_SIZE_PRESET),\n forcedColorsFocusMixin('.dropzone'),\n componentStyles,\n ],\n});\n","@layer refine.base {\n :host {\n display: block;\n }\n\n form {\n display: grid;\n gap: var(--form-gap, var(--size-4, 1rem));\n align-items: start;\n }\n}\n\n@layer refine.orientation {\n :host([orientation='horizontal']) form {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n }\n}\n","import { define, html, prop } from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\n\nimport type { ValidationTrigger } from '../../headless';\nimport type { ComponentSize, VisualVariant } from '../../types';\n\nimport { FORM_CTX } from '../shared/form-context';\nimport componentStyles from './form.css?inline';\n\n/** Form component properties */\nexport type OreFormProps = {\n /** Disabled state */\n disabled?: boolean;\n /** No validate */\n novalidate?: boolean;\n /** Layout orientation for child fields */\n orientation?: 'horizontal' | 'vertical';\n /** Form size preset */\n size?: ComponentSize;\n /** Validate on: 'submit' | 'change' | 'blur' | 'input' */\n validateOn?: ValidationTrigger;\n /** Form visual variant — propagated to all child form fields via FormContext */\n variant?: VisualVariant;\n};\n\n/** Events emitted by the form component */\nexport type OreFormEvents = {\n /** Emitted when the form is reset */\n reset: { originalEvent: Event };\n /** Emitted when the form is submitted */\n submit: { formData: FormData; originalEvent: SubmitEvent };\n};\n\n/**\n * A wrapper for standard HTML form that provides context to child ore-* form fields.\n * Manages shared state like size, variant, and validation timing.\n *\n * @element ore-form\n *\n * @attr {boolean} disabled - Disable all child fields\n * @attr {boolean} novalidate - Disable native browser validation\n * @attr {string} validate-on - When to trigger validation: 'submit' | 'change' | 'blur' | 'input' (default: 'submit')\n *\n * @fires submit - detail: { formData, originalEvent }\n * @fires reset - detail: { originalEvent }\n *\n * @slot - Form controls and content rendered inside the form element.\n * @cssprop --form-gap - Gap between form control rows\n * @part form - Form root element.\n * @example\n * ```html\n * <ore-form @submit=${(e) => console.log(e.detail.formData)}>\n * <ore-input name=\"username\" label=\"Username\" required></ore-input>\n * <ore-select name=\"role\" label=\"Role\">\n * <option value=\"user\">User</option>\n * <option value=\"admin\">Admin</option>\n * </ore-select>\n * <ore-button type=\"submit\">Submit</ore-button>\n * </ore-form>\n * ```\n */\nexport const FORM_TAG = 'ore-form' as const;\ndefine<OreFormProps, OreFormEvents>(FORM_TAG, {\n props: {\n disabled: prop.bool(false),\n novalidate: prop.bool(false),\n orientation: prop.oneOf(['horizontal', 'vertical'] as const, 'vertical'),\n size: prop.string<ComponentSize>(),\n validateOn: prop.oneOf(['submit', 'change', 'blur', 'input'] as const, 'submit'),\n variant: prop.string<VisualVariant>(),\n },\n setup(props, { bind, el, emit, provide }) {\n const shadowRoot = el.shadowRoot;\n\n // Reflect orientation to host so CSS and tests can read it\n bind({ attr: { orientation: props.orientation } });\n // Provide context to all child ore-* form fields\n provide(FORM_CTX, {\n disabled: computed(() => Boolean(props.disabled.value)),\n size: props.size,\n validateOn: computed(() => props.validateOn.value ?? 'submit'),\n variant: props.variant,\n });\n\n function handleSubmit(e: Event) {\n const submitEvent = e as SubmitEvent;\n const formEl = shadowRoot?.querySelector('form');\n\n if (!formEl) return;\n\n e.preventDefault();\n\n const formData = new FormData(formEl);\n\n emit('submit', { formData, originalEvent: submitEvent });\n }\n\n function handleReset(e: Event) {\n emit('reset', { originalEvent: e });\n }\n\n return html`\n <form\n part=\"form\"\n :novalidate=\"${props.novalidate}\"\n :aria-disabled=\"${() => (props.disabled.value ? 'true' : null)}\"\n @submit=\"${handleSubmit}\"\n @reset=\"${handleReset}\">\n <slot></slot>\n </form>\n `;\n },\n shadow: { delegatesFocus: false },\n styles: [componentStyles],\n});\n","@layer refine.base {\n :host {\n display: inline-flex;\n width: fit-content;\n }\n\n :host([fullwidth]) {\n width: 100%;\n }\n\n .wrapper {\n display: inline-flex;\n gap: var(--size-1);\n align-items: center;\n width: 100%;\n }\n\n /* Align buttons to the top when the label is outside (it adds height above the field) */\n :host([label-placement='outside']) .wrapper {\n align-items: flex-end;\n }\n\n /* Spin buttons */\n button {\n display: inline-flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n width: var(--size-10);\n min-width: var(--size-10);\n height: var(--size-10);\n min-height: var(--size-10);\n padding: 0;\n color: var(--color-contrast-600);\n cursor: pointer;\n background: transparent;\n border: none;\n border-radius: var(--rounded-md);\n transition: color var(--transition-fast);\n }\n\n button:hover:not(:disabled) {\n color: var(--color-contrast-800);\n background: var(--color-contrast-100);\n }\n\n button:active:not(:disabled) {\n background: var(--color-contrast-200);\n }\n\n button:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n }\n\n button:focus-visible {\n outline: 2px solid var(--color-primary-500);\n outline-offset: 2px;\n }\n\n /* Centre the typed number inside the field */\n .field::part(input) {\n text-align: center;\n }\n\n .field {\n width: var(--size-20);\n }\n\n :host([fullwidth]) .field {\n flex: 1;\n width: auto;\n min-width: 0;\n }\n}\n","import { clamp } from '@vielzeug/arsenal';\nimport { define, html, inject, prop, ref } from '@vielzeug/ore';\nimport { computed, signal, watch as rippleWatch } from '@vielzeug/ripple';\n\nimport type { ComponentSize, ThemeColor, VisualVariant } from '../../types';\n\nimport { createSpinnerControl } from '../../headless';\nimport '../../content/icon/icon';\nimport '../input/input';\nimport { disablableBundle, roundableBundle, sizableBundle, themableBundle } from '../../shared';\nimport { disabledStateMixin } from '../../styles';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport styles from './number-input.css?inline';\n\nexport type OreNumberInputEvents = {\n change: { originalEvent?: Event; value: number | null };\n input: { originalEvent?: Event; value: number | null };\n};\n\n/** Number Input props */\nexport type OreNumberInputProps = {\n /** Theme color */\n color?: ThemeColor;\n /** Disable interaction */\n disabled?: boolean;\n /** Error message */\n error?: string;\n /** Stretch to full width of container */\n fullwidth?: boolean;\n /** Helper text */\n helper?: string;\n /** Visible label */\n label?: string;\n /** Label placement: 'inset' renders the label inside the control box, 'outside' renders it above */\n 'label-placement'?: 'inset' | 'outside';\n /** Large step (for Page Up/Down, default: 10 × step) */\n 'large-step'?: number;\n /** Maximum allowed value */\n max?: number;\n /** Minimum allowed value */\n min?: number;\n /** Form field name */\n name?: string;\n /** Placeholder text */\n placeholder?: string;\n /** Make the input read-only */\n readonly?: boolean;\n /**\n * JS-only callback fired with the inner `<input>` element when it mounts,\n * and with `null` when it unmounts.\n * Set as a JS property: `bitNumberInput.ref = (el) => { ... }`.\n */\n ref?: ((el: HTMLInputElement | null) => void) | null;\n /** Border radius */\n rounded?: string;\n /** Component size */\n size?: ComponentSize;\n /** Step size for increment/decrement */\n step?: number;\n /** Current numeric value */\n value?: number;\n /** Visual variant */\n variant?: VisualVariant;\n};\n\n/**\n * A numeric spin-button input with +/− controls, min/max clamping, and full keyboard support.\n *\n * @element ore-number-input\n *\n * @attr {number} value - Current value\n * @attr {number} min - Minimum value\n * @attr {number} max - Maximum value\n * @attr {number} step - Increment/decrement step (default: 1)\n * @attr {number} large-step - Step for Page Up/Down (default: 10)\n * @attr {boolean} disabled - Disables the control\n * @attr {boolean} readonly - Read-only mode\n * @attr {string} label - Visible label\n * @attr {string} name - Form field name\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - 'sm' | 'md' | 'lg'\n * @attr {string} placeholder - Input placeholder\n *\n * @fires change - On committed value change. detail: { value: number | null, originalEvent?: Event }\n * @fires input - On every keystroke. detail: { value: number | null, originalEvent?: Event }\n *\n * @slot prefix - Content before the input (e.g. icon)\n * @slot suffix - Content after the input (e.g. unit label)\n * @slot label - Custom label content\n * @slot helper - Custom helper text content\n * @slot error - Custom error content\n *\n * @cssprop --number-input-height - Control height\n * @cssprop --number-input-border-color - Border color\n * @cssprop --number-input-radius - Border radius\n * @cssprop --number-input-bg - Background\n * @cssprop --number-input-btn-bg - Spin button background\n *\n * @part control - Control container.\n * @part decrement-btn - Decrement stepper button.\n * @part input - Input element.\n * @part increment-btn - Increment stepper button.\n * @example\n * ```html\n * <ore-number-input label=\"Quantity\" value=\"1\" min=\"1\" max=\"99\" step=\"1\"></ore-number-input>\n * ```\n */\nexport const NUMBER_INPUT_TAG = 'ore-number-input' as const;\ndefine<OreNumberInputProps, OreNumberInputEvents>(NUMBER_INPUT_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n ...roundableBundle,\n error: prop.string(),\n fullwidth: prop.bool(false),\n helper: prop.string(),\n label: prop.string(),\n 'label-placement': prop.oneOf(['inset', 'outside'] as const, 'inset'),\n 'large-step': prop.json(undefined as number | undefined),\n max: prop.json(undefined as number | undefined),\n min: prop.json(undefined as number | undefined),\n name: prop.string(),\n placeholder: prop.string(),\n readonly: prop.bool(false),\n ref: prop.json(undefined as ((el: HTMLInputElement | null) => void) | null | undefined),\n step: prop.number(1),\n value: prop.json(undefined as number | undefined),\n variant: prop.string<VisualVariant>(),\n },\n setup(props, { bind, emit, onElement, watch }) {\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(bind, props, formCtx);\n const isDisabled = fCtxProps.disabled;\n const isReadonly = computed(() => Boolean(props.readonly.value));\n\n // Internal numeric value signal (string representation for the input)\n const fieldValue = signal(props.value.value != null ? String(props.value.value) : '');\n\n // Keep fieldValue in sync when props.value changes externally\n rippleWatch(props.value, (v) => {\n const next = v != null ? String(v) : '';\n\n if (fieldValue.value !== next) fieldValue.value = next;\n });\n\n function parseValue(): number | null {\n const v = fieldValue.value.trim();\n\n if (!v) return null;\n\n const n = Number.parseFloat(v);\n\n return Number.isNaN(n) ? null : n;\n }\n\n function commit(val: number | null, originalEvent?: Event) {\n const min = props.min.value != null ? Number(props.min.value) : undefined;\n const max = props.max.value != null ? Number(props.max.value) : undefined;\n const clamped = val != null ? clamp(val, min, max) : null;\n const nextValue = clamped != null ? String(clamped) : '';\n\n if (fieldValue.value !== nextValue) fieldValue.value = nextValue;\n\n emit('change', { originalEvent, value: clamped });\n }\n\n const spinner = createSpinnerControl({\n commit,\n disabled: isDisabled,\n largeStep: props['large-step'],\n max: props.max,\n min: props.min,\n parse: parseValue,\n readonly: isReadonly,\n step: props.step,\n });\n\n // Composition uses ore-input's own documented `ref` prop (fired with the raw\n // <input> on mount, `null` on unmount) instead of reaching into its shadow DOM —\n // see `packages/refine/AGENTS.md` / input.ts's `ref` JSDoc for the supported contract.\n // Set imperatively (rather than declared in the template) because ore's template\n // engine treats a function-valued attr binding as a reactive getter to invoke, not\n // a literal value to assign — a plain property assignment avoids that entirely.\n const bitInputRef = ref<HTMLElementTagNameMap['ore-input']>();\n let stopAriaWatch: (() => void) | null = null;\n let detachListeners: (() => void) | null = null;\n let refSub: { dispose(): void } | null = null;\n\n const handleFieldRef = (rawInput: HTMLInputElement | null): void => {\n if (!rawInput) {\n stopAriaWatch?.();\n detachListeners?.();\n refSub?.dispose();\n stopAriaWatch = null;\n detachListeners = null;\n refSub = null;\n props.ref.value?.(null);\n\n return;\n }\n\n rawInput.setAttribute('inputmode', 'decimal');\n // The wrapper div is a plain layout container — WAI-ARIA spinbutton semantics\n // live on the actually-focusable element (the raw <input> rendered by ore-input).\n rawInput.setAttribute('role', 'spinbutton');\n\n const handleChange = (e: Event) => {\n const val = (e.target as HTMLInputElement).value;\n const n = val !== '' ? Number.parseFloat(val) : null;\n\n commit(Number.isNaN(n ?? NaN) ? null : n, e);\n };\n\n const handleInput = (e: Event) => {\n const val = (e.target as HTMLInputElement).value;\n const n = val !== '' ? Number.parseFloat(val) : null;\n\n fieldValue.value = val;\n emit('input', { originalEvent: e, value: Number.isNaN(n ?? NaN) ? null : n });\n };\n\n rawInput.addEventListener('change', handleChange);\n rawInput.addEventListener('input', handleInput);\n detachListeners = () => {\n rawInput.removeEventListener('change', handleChange);\n rawInput.removeEventListener('input', handleInput);\n };\n\n stopAriaWatch = watch(() => {\n const now = parseValue();\n\n if (now == null) rawInput.removeAttribute('aria-valuenow');\n else rawInput.setAttribute('aria-valuenow', String(now));\n\n if (props.min.value != null) rawInput.setAttribute('aria-valuemin', String(props.min.value));\n else rawInput.removeAttribute('aria-valuemin');\n\n if (props.max.value != null) rawInput.setAttribute('aria-valuemax', String(props.max.value));\n else rawInput.removeAttribute('aria-valuemax');\n\n if (isReadonly.value) rawInput.setAttribute('aria-readonly', 'true');\n else rawInput.removeAttribute('aria-readonly');\n });\n\n // Fire user ref callback\n props.ref.value?.(rawInput);\n\n refSub = rippleWatch(props.ref, (cb) => {\n cb?.(rawInput);\n });\n };\n\n // ore-input's own onElement/ref lifecycle calls this back with `null` when its\n // inner <input> unmounts, so no explicit teardown is needed here.\n onElement(bitInputRef, (bitInputEl) => {\n bitInputEl.ref = handleFieldRef;\n });\n\n bind({\n attr: {\n size: fCtxProps.size,\n value: () => fieldValue.value || null,\n variant: fCtxProps.variant,\n },\n });\n\n const isNonInteractive = computed(() => isDisabled.value || isReadonly.value);\n\n return html`\n <div class=\"wrapper\" part=\"control\" @keydown=\"${(e: KeyboardEvent) => spinner.handleKeydown(e)}\">\n <button\n type=\"button\"\n part=\"decrement-btn\"\n aria-label=\"Decrease\"\n ?disabled=\"${() => isNonInteractive.value || spinner.atMin()}\"\n @click=\"${(e: Event) => spinner.incrementBy(-(Number(props.step.value) || 1), e)}\">\n <ore-icon name=\"minus\" size=\"14\" stroke-width=\"2.5\" aria-hidden=\"true\"></ore-icon>\n </button>\n <ore-input\n class=\"field\"\n part=\"field\"\n ref=\"${bitInputRef}\"\n :value=\"${() => fieldValue.value}\"\n :label=\"${() => props.label.value ?? ''}\"\n :label-placement=\"${() => props['label-placement'].value ?? 'inset'}\"\n :placeholder=\"${() => props.placeholder.value ?? ''}\"\n :name=\"${() => props.name.value ?? ''}\"\n :helper=\"${() => props.helper.value ?? ''}\"\n :error=\"${() => props.error.value ?? ''}\"\n :size=\"${fCtxProps.size}\"\n :color=\"${() => props.color.value ?? ''}\"\n :variant=\"${() => props.variant.value ?? ''}\"\n :rounded=\"${() => props.rounded.value}\"\n ?disabled=\"${isDisabled}\"\n ?readonly=\"${isReadonly}\"\n ?fullwidth=\"${() => false}\">\n </ore-input>\n <button\n type=\"button\"\n part=\"increment-btn\"\n aria-label=\"Increase\"\n ?disabled=\"${() => isNonInteractive.value || spinner.atMax()}\"\n @click=\"${(e: Event) => spinner.incrementBy(Number(props.step.value) || 1, e)}\">\n <ore-icon name=\"plus\" size=\"14\" stroke-width=\"2.5\" aria-hidden=\"true\"></ore-icon>\n </button>\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [disabledStateMixin, styles],\n});\n","@layer refine.base {\n :host {\n --_cell-size: var(--otp-cell-size, var(--size-12));\n --_cell-gap: var(--otp-cell-gap, var(--size-2));\n --_cell-font-size: var(--otp-cell-font-size, var(--text-xl));\n --_cell-radius: var(--otp-cell-radius, var(--rounded-lg));\n --_cell-border: var(--otp-cell-border, var(--border));\n --_cell-border-color: var(--otp-cell-border-color, var(--color-contrast-300));\n --_cell-bg: var(--otp-cell-bg, var(--color-canvas));\n --_cell-focus-border: var(--otp-cell-focus-border, var(--_theme-base, var(--color-contrast-700)));\n\n display: inline-flex;\n flex-direction: column;\n gap: var(--size-1);\n }\n\n .otp-group {\n display: flex;\n gap: var(--_cell-gap);\n align-items: center;\n }\n\n .cell {\n box-sizing: border-box;\n display: block;\n width: var(--_cell-size);\n height: var(--_cell-size);\n padding: 0;\n font-size: var(--_cell-font-size);\n font-weight: var(--font-semibold);\n line-height: 1;\n color: var(--color-contrast-900);\n text-align: center;\n caret-color: var(--_cell-focus-border);\n background: var(--_cell-bg);\n border: var(--_cell-border) solid var(--_cell-border-color);\n border-radius: var(--_cell-radius);\n transition:\n border-color var(--transition-fast),\n box-shadow var(--transition-fast);\n }\n\n .cell::selection {\n background: var(--_theme-backdrop, var(--color-contrast-100));\n }\n\n .cell:focus {\n outline: none;\n border-color: var(--_cell-focus-border);\n box-shadow: 0 0 0 var(--border-2) color-mix(in oklch, var(--_cell-focus-border) 20%, transparent);\n }\n\n .cell:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n }\n\n .separator {\n font-size: var(--_cell-font-size);\n color: var(--color-contrast-400);\n user-select: none;\n }\n}\n\n@layer refine.variants {\n /* Solid (default) */\n :host(:not([variant])),\n :host([variant='solid']) {\n --_cell-bg: var(--otp-cell-bg, var(--color-contrast-50));\n --_cell-border-color: var(--otp-cell-border-color, var(--color-contrast-300));\n }\n\n :host(:not([variant])) .cell,\n :host([variant='solid']) .cell {\n box-shadow: var(--shadow-2xs);\n }\n\n /* Flat */\n :host([variant='flat']) {\n --_cell-bg: var(--otp-cell-bg, var(--color-contrast-100));\n --_cell-border-color: var(--otp-cell-border-color, var(--_theme-border, var(--color-contrast-200)));\n }\n\n :host([variant='flat']) .cell {\n box-shadow: var(--inset-shadow-2xs);\n }\n\n :host([variant='flat']) .cell:hover:not(:disabled) {\n background: var(--otp-cell-hover-bg, color-mix(in oklch, var(--_theme-base) 6%, var(--color-contrast-100)));\n border-color: var(\n --otp-cell-hover-border-color,\n color-mix(in oklch, var(--_theme-base) 35%, var(--color-contrast-300))\n );\n }\n\n :host([variant='flat']) .cell:focus {\n background: var(--otp-cell-focus-bg, color-mix(in oklch, var(--_theme-base) 8%, var(--color-canvas)));\n border-color: var(--otp-cell-focus-border-color, color-mix(in oklch, var(--_cell-focus-border) 60%, transparent));\n box-shadow: var(--_theme-shadow);\n }\n\n /* Bordered */\n :host([variant='bordered']) {\n --_cell-bg: var(--otp-cell-bg, var(--_theme-backdrop, var(--color-contrast-50)));\n --_cell-border-color: var(--otp-cell-border-color, color-mix(in oklch, var(--_cell-focus-border) 70%, transparent));\n }\n\n :host([variant='bordered']) .cell {\n color: var(--_theme-base);\n caret-color: var(--_theme-base);\n }\n\n :host([variant='bordered']) .cell:hover:not(:disabled) {\n border-color: var(--otp-cell-hover-border-color, var(--_cell-focus-border));\n }\n\n /* Outline */\n :host([variant='outline']) {\n --_cell-bg: var(--otp-cell-bg, transparent);\n }\n\n :host([variant='outline']) .cell {\n box-shadow: none;\n }\n\n /* Ghost */\n :host([variant='ghost']) {\n --_cell-bg: var(--otp-cell-bg, transparent);\n --_cell-border-color: var(--otp-cell-border-color, transparent);\n }\n\n :host([variant='ghost']) .cell {\n box-shadow: none;\n }\n\n :host([variant='ghost']) .cell:hover:not(:disabled) {\n background: var(--otp-cell-hover-bg, var(--color-contrast-100));\n }\n}\n\n@layer refine.utilities {\n :host([size='sm']) {\n --_cell-size: var(--size-9);\n --_cell-font-size: var(--text-base);\n }\n\n :host([size='lg']) {\n --_cell-size: var(--size-14);\n --_cell-font-size: var(--text-2xl);\n }\n}\n","import { define, useField, html, inject, prop } from '@vielzeug/ore';\nimport { computed, signal, watch } from '@vielzeug/ripple';\n\nimport type { ComponentSize, ThemeColor, VisualVariant } from '../../types';\n\nimport { createListControl } from '../../headless';\nimport { disablableBundle, sizableBundle, themableBundle } from '../../shared';\nimport { colorThemeMixin, forcedColorsFocusMixin, sizeVariantMixin } from '../../styles';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport styles from './otp-input.css?inline';\n\nexport type OreOtpInputEvents = {\n change: { complete: boolean; originalEvent?: Event; value: string };\n complete: { originalEvent?: Event; value: string };\n};\n\n/** OTP Input props */\nexport type OreOtpInputProps = {\n /** Theme color */\n color?: ThemeColor;\n /** Make inputs disabled */\n disabled?: boolean;\n /** Accessible label */\n label?: string;\n /** Number of input cells */\n length?: number;\n /** Mask input (show dots instead of characters) */\n masked?: boolean;\n /** Form field name */\n name?: string;\n /** Show a separator in the middle (e.g. \"–\") */\n separator?: string;\n /** Component size */\n size?: ComponentSize;\n /** Input type: 'numeric' (digits only) or 'alphanumeric' */\n type?: 'numeric' | 'alphanumeric';\n /** Current value */\n value?: string;\n /** Visual variant */\n variant?: Exclude<VisualVariant, 'text' | 'frost'>;\n};\n\n/**\n * A segmented OTP (One-Time Password) input with N individual cells.\n * Auto-advances focus on input, auto-backs on Backspace, handles paste.\n *\n * @element ore-otp-input\n *\n * @attr {number} length - Number of cells (default: 6)\n * @attr {string} type - 'numeric' (default) | 'alphanumeric'\n * @attr {string} value - Current code value\n * @attr {boolean} disabled - Disable all cells\n * @attr {boolean} masked - Show as password\n * @attr {string} size - 'sm' | 'md' | 'lg'\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} name - Form field name\n * @attr {string} label - Group aria-label\n * @attr {string} separator - Optional separator character shown in the middle\n *\n * @fires change - Emitted whenever a cell changes. detail: { value: string, complete: boolean, originalEvent?: Event }\n * @fires complete - Emitted when all cells are filled. detail: { value: string, originalEvent?: Event }\n *\n * @slot label - Custom label above the OTP input\n * @slot helper - Custom helper text below the OTP input\n * @slot error - Custom error content below the OTP input\n *\n * @cssprop --otp-cell-size - Width and height of each cell\n * @cssprop --otp-cell-gap - Gap between cells\n * @cssprop --otp-cell-font-size - Font size inside cells\n * @cssprop --otp-cell-radius - Border radius of cells\n * @cssprop --otp-cell-bg - Cell background color\n * @cssprop --otp-cell-border-color - Default border color\n * @cssprop --otp-cell-focus-border - Focused border/caret color\n * @cssprop --otp-cell-hover-bg - Cell background on hover (flat/ghost variants)\n * @cssprop --otp-cell-hover-border-color - Cell border on hover (flat/bordered variants)\n * @cssprop --otp-cell-focus-bg - Cell background when focused (flat variant)\n * @cssprop --otp-cell-focus-border-color - Cell border when focused (flat variant)\n *\n * @part group - Group container.\n * @part cell - Shadow part for the `cell` element.\n * @example\n * ```html\n * <ore-otp-input length=\"6\" color=\"primary\"></ore-otp-input>\n * ```\n */\nexport const OTP_INPUT_TAG = 'ore-otp-input' as const;\ndefine<OreOtpInputProps, OreOtpInputEvents>(OTP_INPUT_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n label: prop.string('One-time password'),\n length: prop.number(6),\n masked: prop.bool(false),\n name: prop.string(),\n separator: prop.string(),\n type: prop.oneOf(['numeric', 'alphanumeric'] as const, 'numeric'),\n value: prop.string(),\n variant: prop.string<Exclude<VisualVariant, 'text' | 'frost'>>(),\n },\n setup(props, { bind, el, emit, onMounted }) {\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(bind, props, formCtx);\n const lengthValue = computed(() => Number(props.length.value) || 6);\n const isDisabled = fCtxProps.disabled;\n const cells = computed(() => Array.from({ length: lengthValue.value }, (_, i) => i));\n const otpValue = signal(String(props.value.value || ''));\n const normalizedPropValue = () => String(props.value.value || '');\n\n // Form association: the joined cell value is the single form value for `name`,\n // since individual per-cell <input> elements inside the shadow root cannot\n // participate in an ancestor <form>'s submission on their own.\n useField<string>({ disabled: isDisabled, toFormValue: (v) => v, value: otpValue });\n\n bind({\n attr: {\n size: fCtxProps.size,\n value: () => otpValue.value || null,\n variant: fCtxProps.variant,\n },\n });\n\n function getInputs(): HTMLInputElement[] {\n return [...(el.shadowRoot?.querySelectorAll<HTMLInputElement>('input.cell') ?? [])];\n }\n\n const listControl = createListControl({\n getItems: () => getInputs(),\n keys: { next: ['ArrowRight'], prev: ['ArrowLeft'] },\n loop: false,\n onNavigate: (_action, index) => {\n const inputs = getInputs();\n\n inputs[index]?.focus();\n },\n });\n\n function getValue(): string {\n return getInputs()\n .map((i) => i.value)\n .join('');\n }\n function syncInputsFromValue(raw: string) {\n const allInputs = getInputs();\n const normalized = String(raw || '').slice(0, allInputs.length);\n\n for (const input of allInputs) input.value = '';\n\n normalized.split('').forEach((c, i) => {\n if (allInputs[i]) allInputs[i].value = c;\n });\n\n otpValue.value = getValue();\n }\n function emitOtpState(originalEvent?: Event, forceComplete?: boolean): void {\n const allInputs = getInputs();\n const full = getValue();\n const complete = forceComplete ?? (full.length === allInputs.length && full.split('').every(Boolean));\n\n otpValue.value = full;\n emit('change', { complete, originalEvent, value: full });\n\n if (complete) emit('complete', { originalEvent, value: full });\n }\n function isAllowed(char: string): boolean {\n if (props.type.value === 'numeric') return /^\\d$/.test(char);\n\n return /^[a-z\\d]$/i.test(char);\n }\n function handleInput(e: Event, index: number) {\n const input = e.target as HTMLInputElement;\n let val = input.value;\n\n // Keep only last character if multiple were typed somehow\n if (val.length > 1) val = val.slice(-1);\n\n // Validate character\n if (val && !isAllowed(val)) {\n input.value = '';\n\n return;\n }\n\n input.value = val;\n\n const allInputs = getInputs();\n\n emitOtpState(e);\n\n // Auto-advance\n if (val && index < allInputs.length - 1) {\n allInputs[index + 1].focus();\n allInputs[index + 1].select();\n }\n }\n function handleKeydown(e: KeyboardEvent, index: number) {\n const input = e.target as HTMLInputElement;\n const allInputs = getInputs();\n\n listControl.set(index);\n\n if (e.key === 'Backspace') {\n if (input.value) {\n input.value = '';\n } else if (index > 0) {\n const prevIndex = listControl.navigate('prev');\n const prevInput = allInputs[prevIndex];\n\n if (prevInput) {\n prevInput.select();\n prevInput.value = '';\n }\n }\n\n emitOtpState(e, false);\n e.preventDefault();\n } else {\n listControl.handleKeydown(e);\n }\n }\n function handlePaste(e: ClipboardEvent) {\n e.preventDefault();\n\n const pasted = e.clipboardData?.getData('text') ?? '';\n const chars = pasted\n .split('')\n .filter((c) => isAllowed(c))\n .slice(0, lengthValue.value);\n const allInputs = getInputs();\n\n chars.forEach((char, i) => {\n if (allInputs[i]) allInputs[i].value = char;\n });\n\n emitOtpState(e);\n\n // Focus the cell after last pasted char\n const focusIdx = Math.min(chars.length, allInputs.length - 1);\n\n allInputs[focusIdx]?.focus();\n }\n\n watch(props.value, (value) => {\n syncInputsFromValue(String(value || ''));\n });\n\n watch(props.length, () => {\n // Cells re-render when length changes; sync after DOM updates.\n requestAnimationFrame(() => syncInputsFromValue(normalizedPropValue()));\n });\n\n const separatorIdx = computed(() => {\n const len = Number(props.length.value) || 6;\n\n return props.separator.value != null ? Math.floor(len / 2) : -1;\n });\n\n onMounted(() => {\n // Populate cells from value prop on mount\n syncInputsFromValue(normalizedPropValue());\n });\n\n return html`\n <div class=\"otp-group\" part=\"group\" role=\"group\" :aria-label=\"${props.label}\">\n ${() =>\n cells.value.map(\n (i) => html`\n ${() =>\n separatorIdx.value > 0 && i === separatorIdx.value\n ? html`<span class=\"separator\" aria-hidden=\"true\">${() => props.separator.value || '-'}</span>`\n : ''}\n <input\n class=\"cell\"\n part=\"cell\"\n :type=\"${() => (props.masked.value ? 'password' : 'text')}\"\n :inputmode=\"${() => (props.type.value === 'numeric' ? 'numeric' : 'text')}\"\n maxlength=\"1\"\n :autocomplete=\"${() => (i === 0 ? 'one-time-code' : 'off')}\"\n :aria-label=\"${() => `Digit ${i + 1} of ${lengthValue.value}`}\"\n :disabled=\"${() => (isDisabled.value ? true : null)}\"\n @input=\"${(e: Event) => handleInput(e, i)}\"\n @keydown=\"${(e: KeyboardEvent) => handleKeydown(e, i)}\"\n @paste=\"${(e: ClipboardEvent) => (i === 0 ? handlePaste(e) : e.preventDefault())}\"\n @focus=\"${(e: FocusEvent) => (e.target as HTMLInputElement).select()}\" />\n `,\n )}\n </div>\n `;\n },\n styles: [colorThemeMixin, sizeVariantMixin({}), forcedColorsFocusMixin('.cell'), styles],\n});\n","@layer refine.base {\n :host {\n display: block;\n }\n\n fieldset {\n min-width: 0;\n padding: 0;\n margin: 0;\n border: none;\n }\n\n legend {\n padding: 0;\n margin-bottom: var(--size-2);\n font-size: var(--text-sm);\n font-weight: var(--font-medium);\n color: var(--color-contrast-600);\n }\n\n legend[hidden] {\n display: none;\n }\n\n .radio-group-items {\n display: flex;\n flex-direction: var(--radio-group-direction, column);\n gap: var(--radio-group-gap, var(--size-2));\n }\n\n .helper-text[hidden] {\n display: none;\n }\n\n .helper-text {\n padding-inline: 2px;\n margin-top: var(--size-1-5);\n font-size: var(--text-xs);\n line-height: var(--leading-tight);\n color: var(--color-contrast-500);\n }\n\n .error-text {\n padding-inline: 2px;\n margin-top: var(--size-1-5);\n font-size: var(--text-xs);\n line-height: var(--leading-tight);\n color: var(--color-error);\n }\n}\n\n@layer refine.variants {\n :host([orientation='horizontal']) .radio-group-items {\n --radio-group-direction: row;\n\n flex-wrap: wrap;\n }\n}\n","import { createContext, createStableId, define, useField, html, inject, prop } from '@vielzeug/ore';\nimport { when } from '@vielzeug/ore/directives';\nimport { type Readable } from '@vielzeug/ripple';\n\nimport type { ComponentSize, ThemeColor } from '../../types';\n\nimport {\n type ChoiceChangeDetail,\n lifecycleSignal,\n createChoiceField,\n createListControl,\n getChoiceLabel,\n getLightChildrenByTag,\n} from '../../headless';\nimport { disablableBundle, sizableBundle, themableBundle } from '../../shared';\nimport { colorThemeMixin, disabledStateMixin, sizeVariantMixin } from '../../styles';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport componentStyles from './radio-group.css?inline';\n\n/** Radio group component properties */\nexport type OreRadioGroupProps = {\n /** Theme color tint */\n color?: ThemeColor;\n /** Disabled state */\n disabled?: boolean;\n /** Error message text */\n error?: string;\n /** Helper text displayed below the items */\n helper?: string;\n /** Group label text */\n label?: string;\n /** Form field name */\n name?: string;\n /** Layout orientation */\n orientation?: 'horizontal' | 'vertical';\n /** Required field */\n required?: boolean;\n /** Items size preset */\n size?: ComponentSize;\n /** Initial selected value */\n value?: string;\n};\n\nexport type RadioGroupContext = {\n color: Readable<ThemeColor | undefined>;\n disabled: Readable<boolean>;\n name: Readable<string | undefined>;\n select: (value: string, originalEvent?: Event) => void;\n size: Readable<ComponentSize | undefined>;\n value: Readable<string | undefined>;\n};\n\nexport const RADIO_GROUP_CTX = createContext<RadioGroupContext | undefined>('OreRadioGroup');\n\n/** Events emitted by the radio-group component */\nexport type OreRadioGroupEvents = {\n /** Emitted when the selection changes */\n change: ChoiceChangeDetail;\n};\n\n/**\n * A group of radio buttons that allows users to select a single option from a set.\n * Supports keyboard navigation (arrows) and automatic value management.\n *\n * @element ore-radio-group\n *\n * @attr {string} value - Selected value\n * @attr {string} name - Form field name\n * @attr {string} label - Group label\n * @attr {string} orientation - Layout: 'vertical' | 'horizontal'\n * @attr {boolean} required - Required field\n *\n * @fires change - Emitted when a radio is selected. detail: { values: string[], labels: string[], originalEvent?: Event }\n *\n * @slot - Place `ore-radio` elements here\n *\n * @cssprop --radio-group-direction - Flex direction of the items list ('row' | 'column')\n * @cssprop --radio-group-gap - Gap between radio items\n * @part items - Items container.\n * @example\n * ```html\n * <ore-radio-group name=\"plan\" label=\"Choose a plan\" value=\"free\" required>\n * <ore-radio value=\"free\">Free</ore-radio>\n * <ore-radio value=\"pro\">Pro</ore-radio>\n * <ore-radio value=\"enterprise\">Enterprise</ore-radio>\n * </ore-radio-group>\n * <ore-radio-group name=\"direction\" orientation=\"horizontal\" color=\"primary\">\n * <ore-radio value=\"left\">Left</ore-radio>\n * <ore-radio value=\"right\">Right</ore-radio>\n * </ore-radio-group>\n * ```\n */\nexport const RADIO_GROUP_TAG = 'ore-radio-group' as const;\ndefine<OreRadioGroupProps, OreRadioGroupEvents>(RADIO_GROUP_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n error: prop.string(),\n helper: prop.string(),\n label: prop.string(),\n name: prop.string(),\n orientation: prop.oneOf(['horizontal', 'vertical'] as const, 'vertical'),\n required: prop.bool(false),\n value: prop.string(),\n },\n setup(props, { bind, el, emit, onCleanup, provide, slots, watch }) {\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(bind, props, formCtx);\n\n let _formField: { reportValidity(): void } | null = null;\n const choice = createChoiceField({\n disabled: fCtxProps.disabled,\n error: props.error,\n getFormField: () => _formField,\n helper: props.helper,\n label: props.label,\n prefix: 'radio-group',\n signal: lifecycleSignal(onCleanup),\n validateOn: formCtx?.validateOn,\n value: props.value,\n });\n\n _formField = useField<string>({ disabled: choice.disabled, toFormValue: (v) => v, value: choice.formValue });\n\n const selectedValue = choice.selectedValue;\n const isDisabled = fCtxProps.disabled;\n\n bind({\n attr: {\n size: fCtxProps.size,\n value: () => selectedValue.value || null,\n },\n });\n\n const getSlottedRadios = (): HTMLElement[] => getLightChildrenByTag(el, 'ore-radio');\n\n const getEnabledRadios = (): HTMLElement[] =>\n isDisabled.value ? [] : getSlottedRadios().filter((radio) => !radio.hasAttribute('disabled'));\n\n const getLabelForValue = (value: string): string => getChoiceLabel(getSlottedRadios(), value);\n\n const selectRadio = (val: string, originalEvent?: Event): void => {\n choice.setValues(val ? [val] : []);\n\n const labels = val ? [getLabelForValue(val)] : [];\n const values = val ? [val] : [];\n\n emit('change', { labels, originalEvent, values });\n choice.triggerValidation('blur');\n };\n\n provide(RADIO_GROUP_CTX, {\n color: props.color as Readable<ThemeColor | undefined>,\n disabled: isDisabled,\n name: props.name,\n select: selectRadio,\n size: props.size as Readable<ComponentSize | undefined>,\n value: selectedValue,\n });\n\n // Sync name/color/size/disabled/checked onto slotted ore-radio children.\n watch(() => {\n void slots.elements().value;\n void selectedValue.value;\n\n const radios = getSlottedRadios();\n\n for (const radio of radios) {\n const val = radio.getAttribute('value') ?? '';\n\n radio.toggleAttribute('checked', val === selectedValue.value);\n\n if (props.name.value) radio.setAttribute('name', props.name.value);\n else radio.removeAttribute('name');\n\n if (props.color.value) radio.setAttribute('color', props.color.value);\n else radio.removeAttribute('color');\n\n if (props.size.value) radio.setAttribute('size', props.size.value);\n else radio.removeAttribute('size');\n\n radio.toggleAttribute('disabled', isDisabled.value);\n }\n });\n\n // Roving tabindex: only the selected (or first) radio is tabbable.\n watch(() => {\n void slots.elements().value;\n\n const radios = getSlottedRadios();\n let hasFocusable = false;\n\n for (const radio of radios) {\n const isSelected = radio.getAttribute('value') === selectedValue.value;\n\n radio.setAttribute('tabindex', isSelected && !isDisabled.value ? '0' : '-1');\n\n if (isSelected && !isDisabled.value) hasFocusable = true;\n }\n\n if (!hasFocusable && radios.length > 0) {\n const first = radios.find((r) => !r.hasAttribute('disabled'));\n\n if (first) first.setAttribute('tabindex', '0');\n }\n });\n\n const listControl = createListControl<HTMLElement>({\n getItems: getEnabledRadios,\n keys: { next: ['ArrowDown', 'ArrowRight'], prev: ['ArrowUp', 'ArrowLeft'] },\n loop: true,\n onNavigate: (_action, index, event) => {\n const radio = getEnabledRadios()[index];\n\n if (!radio) return;\n\n radio.focus();\n\n if (radio.tagName === 'ORE-RADIO') {\n selectRadio(radio.getAttribute('value') ?? '', event);\n }\n },\n });\n\n bind({\n on: {\n change: (e: Event) => {\n if (e.target === el) return;\n\n e.stopPropagation();\n selectRadio((e.target as HTMLElement).getAttribute('value') ?? '', e);\n },\n keydown: (e: KeyboardEvent) => {\n const radios = getEnabledRadios();\n\n if (!radios.length) return;\n\n const focused = radios.indexOf(document.activeElement as HTMLElement);\n\n if (focused === -1) return;\n\n listControl.set(focused);\n listControl.handleKeydown(e);\n },\n },\n });\n\n const legendId = createStableId('radio-group-legend');\n\n return html`\n <fieldset\n role=\"radiogroup\"\n aria-required=\"${() => String(Boolean(props.required.value))}\"\n :aria-invalid=\"${choice.ariaInvalid}\"\n :aria-errormessage=\"${choice.ariaErrorMessage}\"\n :aria-describedby=\"${choice.ariaDescribedBy}\">\n <legend id=\"${legendId}\" ?hidden=${() => !props.label.value}>\n ${props.label}${when(\n () => Boolean(props.required.value),\n () => html`<span aria-hidden=\"true\"> *</span>`,\n )}\n </legend>\n <div class=\"radio-group-items\" part=\"items\">\n <slot></slot>\n </div>\n <div\n class=\"helper-text\"\n part=\"helper\"\n id=\"${choice.assistiveId}\"\n :role=\"${() => (choice.errorText.value ? 'alert' : null)}\"\n aria-live=\"polite\"\n ?hidden=\"${() => !choice.errorText.value && !choice.helperText.value}\">\n ${() => choice.errorText.value || choice.helperText.value}\n </div>\n </fieldset>\n `;\n },\n styles: [colorThemeMixin, sizeVariantMixin(), disabledStateMixin, componentStyles],\n});\n","@layer refine.base {\n /* ========================================\n Base Styles & Defaults\n ======================================== */\n\n :host {\n --_size: var(--radio-size, var(--size-5));\n --_font-size: var(--radio-font-size, var(--text-sm));\n --_bg: var(--radio-bg, var(--color-contrast-200));\n --_border: var(--radio-border-color, var(--color-contrast-300));\n\n display: inline-flex;\n flex-wrap: wrap;\n gap: var(--_gap, var(--size-2));\n align-items: center;\n min-height: var(--_touch-target);\n cursor: pointer;\n user-select: none;\n }\n\n .radio-wrapper {\n position: relative;\n display: block;\n flex-shrink: 0;\n width: var(--_size);\n height: var(--_size);\n }\n\n .circle {\n position: relative;\n box-sizing: border-box;\n width: var(--_size);\n height: var(--_size);\n background: var(--_bg);\n border: var(--border-2) solid var(--_border);\n border-radius: 50%;\n transition:\n background var(--transition-normal),\n border-color var(--transition-normal),\n box-shadow var(--transition-normal);\n }\n\n /* ========================================\n Focus State\n ======================================== */\n\n :host(:focus-visible) .circle {\n box-shadow: var(--_focus-shadow);\n }\n\n /* ========================================\n Inner Dot\n ======================================== */\n\n .dot {\n position: absolute;\n top: 50%;\n left: 50%;\n width: 50%;\n height: 50%;\n background: var(--_dot-color);\n border-radius: 50%;\n opacity: 0;\n transform: translate(-50%, -50%) scale(0.5);\n transition:\n opacity var(--transition-spring),\n transform var(--transition-spring);\n }\n\n /* ========================================\n Label\n ======================================== */\n\n .label {\n font-size: var(--_font-size);\n color: var(--color-contrast);\n }\n\n /* ========================================\n Helper / Error Text\n ======================================== */\n\n .helper-text[hidden] {\n display: none;\n }\n\n .helper-text {\n width: 100%;\n padding-inline-start: calc(var(--_size) + var(--size-2));\n font-size: var(--text-xs);\n line-height: var(--leading-tight);\n color: var(--color-contrast-500);\n }\n\n .helper-text[role='alert'] {\n color: var(--color-error);\n }\n}\n\n@layer refine.overrides {\n /* Map theme variables to radio-specific variables */\n :host {\n --_active-bg: var(--radio-checked-bg, var(--_theme-base));\n --_dot-color: var(--radio-color, var(--_theme-contrast));\n --_focus-shadow: var(--_theme-shadow);\n }\n\n /* ========================================\n Checked State\n ======================================== */\n\n :host([checked]) .circle {\n background: var(--_active-bg);\n border-color: var(--_active-bg);\n }\n\n :host([checked]) .dot {\n opacity: 1;\n transform: translate(-50%, -50%) scale(1);\n }\n}\n","import { define, useField, html, inject, prop } from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\n\nimport type { CheckableProps, ComponentSize, ThemeColor } from '../../types';\n\nimport { type CheckableChangePayload, lifecycleSignal, createCheckable, createListControl } from '../../headless';\nimport { CONTROL_SIZE_PRESET, disablableBundle, sizableBundle, themableBundle } from '../../shared';\nimport {\n coarsePointerMixin,\n colorThemeMixin,\n disabledStateMixin,\n forcedColorsFormControlMixin,\n sizeVariantMixin,\n} from '../../styles';\nimport { RADIO_GROUP_CTX } from '../radio-group/radio-group';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport { renderHelperRegion } from '../shared/templates';\nimport componentStyles from './radio.css?inline';\n\n/** Radio component properties */\n\nexport type OreRadioEvents = {\n change: CheckableChangePayload;\n};\n\nexport type OreRadioProps = CheckableProps & {\n /** Theme color */\n color?: ThemeColor;\n /** Disable interaction */\n disabled?: boolean;\n /** Error message (marks field as invalid) */\n error?: string;\n /** Helper text displayed below the radio */\n helper?: string;\n /** Component size */\n size?: ComponentSize;\n};\n\n/**\n * A customizable radio button component for mutually exclusive selections.\n *\n * @element ore-radio\n *\n * @attr {boolean} checked - Checked state\n * @attr {boolean} disabled - Disable radio interaction\n * @attr {string} value - Field value (required for radio groups)\n * @attr {string} name - Form field name (required for radio groups)\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - Radio size: 'sm' | 'md' | 'lg'\n * @attr {string} error - Error message (marks field as invalid)\n * @attr {string} helper - Helper text displayed below the radio\n *\n * @fires change - Emitted when radio is selected. detail: { checked: boolean, value: string, originalEvent?: Event }\n *\n * @slot - Radio button label text\n *\n * @cssprop --radio-size - Control size (width and height)\n * @cssprop --radio-bg - Unchecked background color\n * @cssprop --radio-border-color - Unchecked border color\n * @cssprop --radio-checked-bg - Selected indicator background color\n * @cssprop --radio-color - Selected indicator dot color\n * @cssprop --radio-font-size - Label font size\n * @part radio - The radio wrapper element\n * @part circle - The visual radio circle\n * @part label - The label element\n * @part helper-text - The helper/error text element\n *\n * @example\n * ```html\n * <ore-radio name=\"plan\" value=\"free\">Free</ore-radio>\n * <ore-radio name=\"plan\" value=\"pro\" checked color=\"primary\">Pro</ore-radio>\n * <ore-radio name=\"plan\" value=\"enterprise\" disabled>Enterprise</ore-radio>\n * ```\n */\nexport const RADIO_TAG = 'ore-radio' as const;\ndefine<OreRadioProps, OreRadioEvents>(RADIO_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n checked: prop.bool(false),\n error: prop.string(),\n helper: prop.string(),\n name: prop.string(),\n value: prop.string(),\n },\n setup(props, { bind, el, emit, onCleanup }) {\n const groupCtx = inject(RADIO_GROUP_CTX);\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(bind, props, formCtx);\n\n const effectiveName = computed(() => groupCtx?.name.value || props.name.value || '');\n const effectiveSize = computed(() => groupCtx?.size.value ?? fCtxProps.size.value);\n const effectiveColor = computed(() => groupCtx?.color.value ?? props.color.value);\n const checkedFromState = computed(() => {\n if (groupCtx) return groupCtx.value.value === props.value.value;\n\n return Boolean(props.checked.value);\n });\n\n const getRadioGroup = (): HTMLElement[] => {\n const radioName = effectiveName.value;\n\n if (!radioName) return [];\n\n return Array.from(document.querySelectorAll<HTMLElement>(`ore-radio[name=\"${radioName}\"]`)).filter(\n (r) => !r.hasAttribute('disabled'),\n );\n };\n\n const selectRadio = (radio: HTMLElement, originalEvent?: Event): void => {\n if (groupCtx) {\n groupCtx.select(radio.getAttribute('value') ?? '', originalEvent);\n\n return;\n }\n\n radio.click();\n };\n\n const listControl = createListControl({\n getItems: () => getRadioGroup(),\n keys: { next: ['ArrowDown', 'ArrowRight'], prev: ['ArrowUp', 'ArrowLeft'] },\n loop: true,\n onNavigate: (_action, index, event) => {\n const nextRadio = getRadioGroup()[index];\n\n if (!nextRadio) return;\n\n nextRadio.focus();\n selectRadio(nextRadio, event);\n },\n });\n\n const activateSelf = (originalEvent?: Event): void => {\n if (checkable.checked.value) return;\n\n if (groupCtx) {\n groupCtx.select(props.value.value ?? '', originalEvent);\n\n return;\n }\n\n checkable.toggle(originalEvent ?? new Event('change'));\n };\n\n let _formField: { reportValidity(): void } | null = null;\n const checkable = createCheckable({\n checked: checkedFromState,\n disabled: computed(() => fCtxProps.disabled.value || Boolean(groupCtx?.disabled.value)),\n error: props.error,\n getFormField: () => _formField,\n helper: props.helper,\n onToggle: (payload) => {\n emit('change', payload);\n },\n prefix: 'radio',\n signal: lifecycleSignal(onCleanup),\n validateOn: formCtx?.validateOn,\n value: props.value,\n });\n\n _formField = useField<string | null>({\n disabled: checkable.disabled,\n toFormValue: (v) => v,\n value: checkable.checkableFormValue,\n });\n\n const { assistiveId, checked, disabled, errorText, helperText, labelId, toggle } = checkable;\n\n bind({\n attr: {\n ariaChecked: () => (checked.value ? 'true' : 'false'),\n ariaDescribedby: () => (errorText.value || helperText.value ? assistiveId : null),\n ariaDisabled: () => (disabled.value ? 'true' : null),\n ariaInvalid: () => (errorText.value ? 'true' : null),\n ariaLabelledby: labelId,\n checked,\n color: effectiveColor,\n disabled: () => (disabled.value ? true : undefined),\n name: () => effectiveName.value || undefined,\n role: 'radio',\n size: effectiveSize,\n tabindex: () => {\n if (disabled.value) return undefined;\n\n return checked.value ? 0 : -1;\n },\n },\n class: () => ({\n 'is-checked': checked.value,\n 'is-disabled': disabled.value,\n }),\n on: {\n click: (e: MouseEvent) => {\n if (disabled.value) return;\n\n if (groupCtx) {\n groupCtx.select(props.value.value ?? '', e);\n } else {\n if (!effectiveName.value) return;\n\n if (!checked.value) {\n const radioName = props.name.value;\n const allRadios = document.querySelectorAll<HTMLElement>(`ore-radio[name=\"${radioName}\"]`);\n\n allRadios.forEach((radio) => {\n if (radio !== el) radio.removeAttribute('checked');\n });\n\n toggle(e);\n }\n }\n },\n keydown: (e: KeyboardEvent) => {\n if (e.key === ' ' || e.key === 'Enter') {\n e.preventDefault();\n activateSelf(e);\n\n return;\n }\n\n const radios = getRadioGroup();\n\n if (radios.length === 0) return;\n\n const selfIndex = radios.indexOf(el);\n\n if (selfIndex === -1) return;\n\n listControl.set(selfIndex);\n listControl.handleKeydown(e);\n },\n },\n });\n\n return html`\n <div class=\"radio-wrapper\" part=\"radio\">\n <div class=\"circle\" part=\"circle\">\n <div class=\"dot\" part=\"dot\"></div>\n </div>\n </div>\n <span class=\"label\" part=\"label\" id=\"${labelId}\"><slot></slot></span>\n ${renderHelperRegion(assistiveId, errorText, helperText)}\n `;\n },\n styles: [\n colorThemeMixin,\n forcedColorsFormControlMixin,\n disabledStateMixin,\n coarsePointerMixin,\n sizeVariantMixin(CONTROL_SIZE_PRESET),\n componentStyles,\n ],\n});\n","@layer refine.base {\n :host {\n --_star-size: var(--rating-star-size, var(--size-7));\n --_color-empty: var(--rating-color-empty, var(--color-contrast-200));\n --_color-filled: var(--rating-color-filled, var(--_theme-base, var(--color-warning)));\n --_gap: var(--rating-gap, var(--size-0_5));\n\n display: inline-flex;\n flex-wrap: wrap;\n align-items: center;\n }\n\n .stars {\n position: relative;\n display: flex;\n gap: var(--_gap);\n align-items: center;\n }\n\n .sparkle-layer {\n position: absolute;\n inset: 0;\n overflow: visible;\n pointer-events: none;\n }\n\n .sparkle {\n position: absolute;\n pointer-events: none;\n background: var(--_color-filled);\n border-radius: 50%;\n animation: var(--_motion-animation, sparkle-fly var(--_dur, 500ms) var(--ease-out) forwards);\n }\n\n @keyframes sparkle-fly {\n from {\n opacity: 0.9;\n transform: translate(-50%, -50%) rotate(var(--_angle)) translateY(0) scale(1);\n }\n\n to {\n opacity: 0;\n transform: translate(-50%, -50%) rotate(var(--_angle)) translateY(calc(-1 * var(--_dist))) scale(0);\n }\n }\n\n .star-btn {\n all: unset;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--_star-size);\n min-width: var(--_touch-target);\n height: var(--_star-size);\n min-height: var(--_touch-target);\n color: var(--_color-empty);\n cursor: pointer;\n border-radius: var(--rounded-sm);\n transition:\n color var(--transition-fast),\n transform 120ms var(--ease-spring);\n }\n\n .star-btn[data-filled] {\n color: var(--_color-filled);\n }\n\n :host([solid]) .star-btn ore-icon::part(svg) {\n fill: none;\n }\n\n :host([solid]) .star-btn[data-filled] ore-icon::part(svg) {\n fill: currentcolor;\n }\n\n .star-btn:hover:not([disabled]),\n .star-btn:focus-visible:not([disabled]) {\n transform: scale(1.08);\n }\n\n .star-btn:focus-visible {\n outline: var(--border-2) solid var(--_color-filled);\n outline-offset: var(--border-2);\n }\n\n .star-btn[disabled] {\n cursor: default;\n }\n\n :host([readonly]) .star-btn,\n :host([disabled]) .star-btn {\n pointer-events: none;\n }\n\n :host([disabled]) {\n opacity: 0.5;\n }\n}\n\n@layer refine.utilities {\n :host([size='sm']) {\n --_star-size: var(--size-5);\n }\n\n :host([size='lg']) {\n --_star-size: var(--size-9);\n }\n\n @media (forced-colors: active) {\n /* Distinguish filled vs unfilled stars with system button colors */\n .star-btn {\n color: ButtonText;\n }\n\n .star-btn[data-filled] {\n color: Highlight;\n forced-color-adjust: none;\n }\n\n .star-btn:focus-visible {\n outline: 2px solid Highlight;\n box-shadow: none;\n }\n }\n\n /* ========================================\n Helper / Error Text\n ======================================== */\n\n .helper-text[hidden] {\n display: none;\n }\n\n .helper-text {\n width: 100%;\n margin-block-start: var(--size-1);\n font-size: var(--text-xs);\n line-height: var(--leading-tight);\n color: var(--color-contrast-500);\n }\n\n .helper-text[role='alert'] {\n color: var(--color-error);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .sparkle {\n display: none;\n }\n}\n","import { createStableId, define, useField, html, inject, prop } from '@vielzeug/ore';\nimport { computed, signal } from '@vielzeug/ripple';\n\nimport type { ComponentSize, ThemeColor } from '../../types';\n\nimport { createErrorHelperState, createSliderControl } from '../../headless';\nimport '../../content/icon/icon';\nimport { disablableBundle, sizableBundle, themableBundle } from '../../shared';\nimport { coarsePointerMixin, colorThemeMixin, reducedMotionMixin, sizeVariantMixin } from '../../styles';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport { renderHelperRegion } from '../shared/templates';\nimport styles from './rating.css?inline';\n\nexport type OreRatingEvents = {\n change: { originalEvent?: Event; value: number };\n};\n\n/** Rating props */\nexport type OreRatingProps = {\n /** Theme color */\n color?: ThemeColor;\n /** Disable interaction */\n disabled?: boolean;\n /** Error message — marks the field as invalid (fallback when the `error` slot is empty) */\n error?: string;\n /** Helper text displayed below the stars (fallback when the `helper` slot is empty) */\n helper?: string;\n /** Accessible group label */\n label?: string;\n /** Maximum rating (number of stars) */\n max?: number;\n /** Form field name */\n name?: string;\n /** Make rating read-only */\n readonly?: boolean;\n /** Component size */\n size?: ComponentSize;\n /** Render selected stars as solid-filled instead of outline-only */\n solid?: boolean;\n /** Current rating value */\n value?: number;\n};\n\n/**\n * A star rating input.\n *\n * @element ore-rating\n *\n * @attr {number} value - Current rating value (default: 0)\n * @attr {number} max - Maximum number of stars (default: 5)\n * @attr {boolean} readonly - Read-only display mode\n * @attr {boolean} disabled - Disabled state\n * @attr {string} label - aria-label for the group (default: 'Rating')\n * @attr {string} color - Theme color for filled stars: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - 'sm' | 'md' | 'lg'\n * @attr {string} name - Form field name\n * @attr {boolean} solid - Fill selected stars (outline remains default when omitted)\n * @attr {string} helper - Helper text below the stars\n * @attr {string} error - Error message below the stars\n *\n * @fires change - Emitted when value changes. detail: { value: number, originalEvent?: Event }\n *\n * @cssprop --rating-star-size - Star diameter\n * @cssprop --rating-color-empty - Empty star color\n * @cssprop --rating-color-filled - Filled star color\n * @cssprop --rating-gap - Gap between stars\n *\n * @part stars - Stars container.\n * @part star - Star item element.\n * @part helper-text - The helper/error text element.\n * @example\n * ```html\n * <ore-rating value=\"3\" max=\"5\" color=\"warning\"></ore-rating>\n * <ore-rating value=\"4\" solid></ore-rating>\n * ```\n */\nexport const RATING_TAG = 'ore-rating' as const;\ndefine<OreRatingProps, OreRatingEvents>(RATING_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n error: prop.string(),\n helper: prop.string(),\n label: prop.string('Rating'),\n max: prop.number(5),\n name: prop.string(),\n readonly: prop.bool(false),\n solid: prop.bool(false),\n value: prop.number(0),\n },\n setup(props, { bind, el, emit }) {\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(bind, props, formCtx);\n\n const normalizedValue = computed(() => {\n const max = Math.max(1, Number(props.max!.value) || 5);\n const raw = Number(props.value!.value);\n const safe = Number.isFinite(raw) ? raw : 0;\n\n return Math.min(max, Math.max(0, safe));\n });\n\n const fd = useField({\n disabled: fCtxProps.disabled,\n value: computed(() => String(normalizedValue.value || 0)),\n });\n\n const triggerValidation = (on: 'blur' | 'change') => {\n if (formCtx?.validateOn?.value === on) {\n fd.reportValidity();\n }\n };\n\n const assistiveId = createStableId('helper');\n const assistive = createErrorHelperState({ error: props.error, helper: props.helper });\n const errorText = computed(() => assistive.value.errorText);\n const helperText = computed(() => assistive.value.helperText);\n const ariaDescribedBy = computed(() => (errorText.value || helperText.value ? assistiveId : null));\n\n const isInteractive = computed(() => !props.readonly!.value && !fCtxProps.disabled.value);\n const hovered = signal<number | null>(null);\n const displayValue = computed(() => hovered.value ?? normalizedValue.value);\n const getStarButtons = () => {\n return [...(el.shadowRoot?.querySelectorAll<HTMLButtonElement>('[data-star]') ?? [])];\n };\n const ratingControl = createSliderControl({\n max: computed(() => Number(props.max!.value) || 5),\n min: signal(1),\n step: signal(1),\n });\n\n function spawnSparkles(star: number) {\n const layer = el.shadowRoot?.querySelector<HTMLElement>('.sparkle-layer');\n const btn = el.shadowRoot?.querySelector<HTMLElement>(`[data-star=\"${star}\"]`);\n\n if (!layer || !btn) return;\n\n const cx = btn.offsetLeft + btn.offsetWidth / 2;\n const cy = btn.offsetTop + btn.offsetHeight / 2;\n const count = 10;\n\n for (let i = 0; i < count; i++) {\n const p = document.createElement('span');\n const angle = (360 / count) * i + (Math.random() * 30 - 15);\n const dist = 18 + Math.random() * 20;\n const size = 3 + Math.random() * 4;\n const dur = 380 + Math.random() * 220;\n\n p.className = 'sparkle';\n p.style.cssText = [\n `left:${cx}px`,\n `top:${cy}px`,\n `--_angle:${angle}deg`,\n `--_dist:${dist}px`,\n `width:${size}px`,\n `height:${size}px`,\n `--_dur:${dur}ms`,\n `animation-delay:${Math.random() * 60}ms`,\n ].join(';');\n layer.appendChild(p);\n p.addEventListener('animationend', () => p.remove(), { once: true });\n }\n }\n function select(star: number, originalEvent?: Event) {\n if (!isInteractive.value) return;\n\n const max = Math.max(1, Number(props.max!.value) || 5);\n const nextValue = Math.min(max, Math.max(0, star));\n\n if (nextValue === normalizedValue.value) return;\n\n // Write through the host attribute; ore handles host reflection.\n el.setAttribute('value', String(nextValue));\n emit('change', { originalEvent, value: nextValue });\n triggerValidation('change');\n spawnSparkles(nextValue);\n }\n function handleKeydown(e: KeyboardEvent, star: number) {\n const next = ratingControl.nextFromKey(e.key, star);\n\n if (next == null) return;\n\n e.preventDefault();\n select(next, e);\n\n const buttons = getStarButtons();\n\n buttons[next - 1]?.focus();\n }\n\n const stars = computed(() => {\n const max = Number(props.max!.value) || 5;\n\n return Array.from({ length: max }, (_, i) => i + 1);\n });\n\n bind({ attr: { size: fCtxProps.size } });\n\n return html`\n <div\n class=\"stars\"\n part=\"stars\"\n role=\"radiogroup\"\n :aria-label=\"${props.label}\"\n :aria-describedby=\"${ariaDescribedBy}\">\n ${() =>\n stars.value.map(\n (star) =>\n html`<button\n class=\"star-btn\"\n part=\"star\"\n type=\"button\"\n role=\"radio\"\n :aria-label=\"${() => `${star} ${star === 1 ? 'star' : 'stars'}`}\"\n :aria-checked=\"${() => String(star === normalizedValue.value)}\"\n :data-star=\"${star}\"\n ?data-filled=\"${() => star <= displayValue.value}\"\n :disabled=\"${() => (!isInteractive.value ? true : null)}\"\n @click=\"${(e: Event) => select(star, e)}\"\n @pointerenter=\"${() => {\n if (isInteractive.value) hovered.value = star;\n }}\"\n @pointerleave=\"${() => {\n hovered.value = null;\n }}\"\n @keydown=\"${(e: KeyboardEvent) => handleKeydown(e, star)}\">\n <ore-icon name=\"star\" size=\"var(--_star-size)\" stroke-width=\"1.5\" aria-hidden=\"true\"></ore-icon>\n </button>`,\n )}\n <div class=\"sparkle-layer\"></div>\n </div>\n ${renderHelperRegion(assistiveId, errorText, helperText)}\n `;\n },\n styles: [colorThemeMixin, sizeVariantMixin({}), coarsePointerMixin, reducedMotionMixin, styles],\n});\n","@layer refine.base {\n /* ========================================\n Base Styles & Defaults\n ======================================== */\n\n :host {\n --_size: var(--slider-size, var(--size-5));\n --_height: var(--slider-height, var(--size-3));\n --_track: var(--slider-track-bg, var(--color-contrast-300));\n --_fill: var(--slider-fill, var(--color-neutral));\n --_thumb: var(--slider-thumb-bg, var(--color-contrast-100));\n --_thumb-size: calc(var(--_size) - var(--size-1));\n --_font-size: var(--text-sm);\n --_shadow: var(--color-neutral-focus-shadow);\n\n position: relative;\n display: inline-flex;\n flex-wrap: wrap;\n gap: var(--_gap, var(--size-3));\n align-items: center;\n width: 100%;\n touch-action: none;\n cursor: pointer;\n user-select: none;\n }\n}\n\n/* ========================================\n Track, Fill & Thumb\n ======================================== */\n\n.slider-container {\n position: relative;\n display: flex;\n flex: 1;\n align-items: center;\n width: 100%;\n height: var(--_size);\n min-height: var(--_touch-target);\n}\n\n.slider-track {\n position: relative;\n width: 100%;\n height: var(--_height);\n background: var(--_track);\n border-radius: var(--rounded-full);\n}\n\n/* Fill: always driven by --_fill-start / --_fill-width */\n.slider-fill {\n position: absolute;\n top: 0;\n left: var(--_fill-start, 0%);\n width: var(--_fill-width, 0%);\n height: 100%;\n background: var(--_fill);\n border-radius: var(--rounded-full);\n transition:\n left var(--transition-normal),\n width var(--transition-normal);\n}\n\n:host([data-dragging]) .slider-fill {\n transition: none;\n}\n\n.slider-thumb {\n position: absolute;\n top: 50%;\n z-index: 1;\n width: var(--_thumb-size);\n height: var(--_thumb-size);\n cursor: grab;\n background: var(--_thumb);\n border: 2px solid var(--_fill);\n border-radius: var(--rounded-full);\n box-shadow: var(--shadow-sm);\n transform: translate(-50%, -50%);\n transition:\n box-shadow var(--transition-normal),\n transform var(--transition-fast),\n left var(--transition-normal);\n will-change: transform;\n}\n\n:host([data-dragging]) .slider-thumb {\n transition:\n box-shadow var(--transition-normal),\n transform var(--transition-fast);\n}\n\n/* ── Single-value thumb ─────────────────────────────────── */\n\n.slider-thumb-sole {\n left: var(--_thumb-pos, 0%);\n}\n\n:host(:focus-visible) .slider-thumb-sole,\n:host(:active) .slider-thumb-sole {\n box-shadow: var(--_shadow);\n transform: translate(-50%, -50%) scale(1.1);\n}\n\n/* ── Range thumbs ───────────────────────────────────────── */\n\n.slider-thumb-start {\n left: var(--_thumb-start, 0%);\n}\n\n.slider-thumb-end {\n left: var(--_thumb-end, 100%);\n}\n\n.slider-thumb-start:focus-visible,\n.slider-thumb-end:focus-visible {\n z-index: 2;\n cursor: grabbing;\n outline: var(--border-2) solid var(--_fill);\n outline-offset: 2px;\n box-shadow: var(--_shadow);\n transform: translate(-50%, -50%) scale(1.1);\n}\n\n/* ── Visibility gating ──────────────────────────────────── */\n\n:host(:not([range])) .slider-thumb-start,\n:host(:not([range])) .slider-thumb-end {\n display: none;\n}\n\n:host([range]) .slider-thumb-sole {\n display: none;\n}\n\n@media (forced-colors: active) {\n /* Replace box-shadow focus ring with outline for sole-thumb focus visibility */\n :host(:focus-visible) .slider-thumb-sole {\n outline: 2px solid Highlight;\n outline-offset: 2px;\n box-shadow: none;\n }\n}\n\n@layer refine.overrides {\n :host {\n --_fill: var(--slider-fill, var(--_theme-base));\n --_shadow: var(--_theme-shadow);\n }\n}\n\n/* ========================================\n Label\n ======================================== */\n\n.label {\n font-size: var(--_font-size);\n color: var(--color-contrast);\n white-space: nowrap;\n}\n\n.helper-text[hidden] {\n display: none;\n}\n\n.helper-text {\n width: 100%;\n font-size: var(--text-xs);\n line-height: var(--leading-tight);\n color: var(--color-contrast-500);\n}\n\n.helper-text[role='alert'] {\n color: var(--color-error);\n}\n\n@media (pointer: coarse) {\n :host {\n --_thumb-size: calc(var(--_size) + var(--size-2));\n --_size: var(--size-7);\n }\n}\n","import { createStableId, define, useField, html, inject, prop, ref } from '@vielzeug/ore';\nimport { computed, signal, watch } from '@vielzeug/ripple';\n\nimport type { ComponentSize, ThemeColor } from '../../types';\n\nimport { createErrorHelperState, createSliderControl } from '../../headless';\nimport { disablableBundle, sizableBundle, SLIDER_SIZE_PRESET, themableBundle } from '../../shared';\nimport { coarsePointerMixin, colorThemeMixin, disabledStateMixin, sizeVariantMixin } from '../../styles';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport { renderHelperRegion } from '../shared/templates';\nimport componentStyles from './slider.css?inline';\n\nconst guard =\n <E extends Event = Event>(condition: () => unknown, handler: (e: E) => void): ((e: E) => void) =>\n (e) => {\n if (condition()) handler(e);\n };\n\n/** Slider component properties */\n\nexport type OreSliderEvents = {\n change: { from?: number; originalEvent?: Event; to?: number; value: number | { from: number; to: number } };\n};\n\nexport type OreSliderProps = {\n /** Theme color */\n color?: ThemeColor;\n /** Disable interaction */\n disabled?: boolean;\n /** Error message — marks the field as invalid (fallback when the `error` slot is empty) */\n error?: string;\n /** Range mode: lower bound */\n from?: number | string;\n /** Range mode a11y label for the start thumb (e.g. \"$20\") */\n 'from-value-text'?: string;\n /** Helper text displayed below the slider (fallback when the `helper` slot is empty) */\n helper?: string;\n /** Maximum value */\n max?: number | string;\n /** Minimum value */\n min?: number | string;\n /** Single-value mode: form field name */\n name?: string;\n /** Activate two-thumb range selection */\n range?: boolean;\n /** Component size */\n size?: ComponentSize;\n /** Step increment */\n step?: number | string;\n /** Range mode: upper bound */\n to?: number | string;\n /** Range mode a11y label for the end thumb (e.g. \"$80\") */\n 'to-value-text'?: string;\n /** Single-value mode: current value */\n value?: number | string;\n /** Single-value mode a11y label override (e.g. \"75%\"). Overrides raw aria-valuenow. */\n 'value-text'?: string;\n};\n\n/**\n * A slider for selecting a single numeric value or a numeric range.\n *\n * Add the boolean `range` attribute to activate two-thumb range mode.\n *\n * @element ore-slider\n *\n * @attr {number} min - Minimum value (default: 0)\n * @attr {number} max - Maximum value (default: 100)\n * @attr {number} step - Step increment (default: 1)\n * @attr {number} value - Current value (single mode)\n * @attr {number} from - Lower bound (range mode)\n * @attr {number} to - Upper bound (range mode)\n * @attr {boolean} range - Activate range mode\n * @attr {boolean} disabled - Disable interaction\n * @attr {string} name - Form field name (single mode)\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - 'sm' | 'md' | 'lg'\n * @attr {string} helper - Helper text below the slider\n * @attr {string} error - Error message below the slider\n *\n * @fires change - detail always includes `value`; single mode: { value: number }, range mode: { value: { from, to }, from, to }, plus optional originalEvent\n *\n * @slot - Slider label text\n *\n * @part slider - Slider container\n * @part track - Track element\n * @part fill - Fill element\n * @part thumb - Single-value thumb\n * @part thumb-start - Range start thumb\n * @part thumb-end - Range end thumb\n * @part label - Label element\n * @part helper-text - The helper/error text element\n *\n * @cssprop --slider-height - Track height\n * @cssprop --slider-size - Thumb dimensions\n * @cssprop --slider-track-bg - Track background color\n * @cssprop --slider-fill - Active fill color\n * @cssprop --slider-thumb-bg - Thumb background color\n *\n * @example\n * ```html\n * <ore-slider value=\"50\" name=\"volume\">Volume</ore-slider>\n * <ore-slider range from=\"20\" to=\"80\" color=\"primary\">Price range</ore-slider>\n * ```\n */\nexport const SLIDER_TAG = 'ore-slider' as const;\ndefine<OreSliderProps, OreSliderEvents>(SLIDER_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n error: prop.string(),\n from: prop.number(0),\n 'from-value-text': prop.string(),\n helper: prop.string(),\n max: prop.number(100),\n min: prop.number(0),\n name: prop.string(),\n range: prop.bool(false),\n step: prop.number(1),\n to: prop.number(100),\n 'to-value-text': prop.string(),\n value: prop.number(0),\n 'value-text': prop.string(),\n },\n setup(props, { aria, bind, el, emit, onCleanup, onEvent, onMounted, slots }) {\n // Treat `range` as static — determined at first render\n const isRange = props.range.value;\n // ── Shared helpers ────────────────────────────────────────────\n const sliderControl = createSliderControl({\n max: props.max,\n min: props.min,\n step: props.step,\n });\n // ── Single-value state ────────────────────────────────────────\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(bind, props, formCtx);\n const isDragging = signal(false);\n const isDisabled = fCtxProps.disabled;\n const labelledById = signal<string | undefined>(undefined);\n const assistiveId = createStableId('helper');\n const assistive = createErrorHelperState({ error: props.error, helper: props.helper });\n const errorText = computed(() => assistive.value.errorText);\n const helperText = computed(() => assistive.value.helperText);\n const ariaDescribedBy = computed(() => (errorText.value || helperText.value ? assistiveId : null));\n\n bind({\n attr: {\n 'data-dragging': () => (isDragging.value ? true : undefined),\n size: fCtxProps.size,\n },\n });\n\n let sliderFd:\n | {\n reportValidity: () => boolean;\n }\n | undefined;\n const valueSignal = signal('0');\n\n if (!isRange) {\n sliderFd = useField({ disabled: isDisabled, value: valueSignal });\n watch(\n props.value,\n (v) => {\n valueSignal.value = String(v);\n },\n { immediate: true },\n );\n bind({\n attr: {\n ariaDescribedby: () => ariaDescribedBy.value ?? null,\n ariaDisabled: () => (isDisabled.value ? 'true' : null),\n ariaLabelledby: () => labelledById.value ?? null,\n ariaValuemax: () => sliderControl.max(),\n ariaValuemin: () => sliderControl.min(),\n ariaValuenow: () => Number(valueSignal.value || 0),\n ariaValuetext: () => props['value-text'].value ?? null,\n role: () => 'slider',\n tabindex: () => (isDisabled.value ? null : '0'),\n },\n });\n }\n\n // ── Range state ───────────────────────────────────────────────\n const startVal = signal(0);\n const endVal = signal(100);\n\n if (isRange) {\n sliderFd = useField<{\n from: number;\n to: number;\n }>({\n disabled: isDisabled,\n toFormValue: ({ from, to }) => {\n const name = props.name.value;\n\n if (!name) return null;\n\n const fd = new FormData();\n\n fd.append(`${name}[from]`, String(from));\n fd.append(`${name}[to]`, String(to));\n\n return fd;\n },\n value: computed(() => ({ from: startVal.value, to: endVal.value })),\n });\n watch(\n props.from,\n (v) => {\n startVal.value = sliderControl.snap(Number(v));\n },\n { immediate: true },\n );\n watch(\n props.to,\n (v) => {\n endVal.value = sliderControl.snap(Number(v));\n },\n { immediate: true },\n );\n }\n\n // ── Refs ──────────────────────────────────────────────────────\n const containerRef = ref<HTMLDivElement>();\n const labelRef = ref<HTMLSpanElement>();\n const thumbStartRef = ref<HTMLDivElement>();\n const thumbEndRef = ref<HTMLDivElement>();\n const startId = createStableId('slider-start');\n const endId = createStableId('slider-end');\n // ── CSS update helpers ────────────────────────────────────────\n const updateSingleCSS = (value: number) => {\n const pct = sliderControl.toPercent(value);\n\n el.style.setProperty('--_thumb-pos', `${pct}%`);\n el.style.setProperty('--_fill-start', '0%');\n el.style.setProperty('--_fill-width', `${pct}%`);\n };\n const updateRangeCSS = () => {\n const s = sliderControl.toPercent(startVal.value);\n const e = sliderControl.toPercent(endVal.value);\n\n el.style.setProperty('--_thumb-start', `${s}%`);\n el.style.setProperty('--_thumb-end', `${e}%`);\n el.style.setProperty('--_fill-start', `${s}%`);\n el.style.setProperty('--_fill-width', `${e - s}%`);\n };\n\n // ── Range mode setup ──────────────────────────────────────────\n const triggerValidation = (on: 'blur' | 'change') => {\n if (formCtx?.validateOn?.value === on) {\n sliderFd?.reportValidity();\n }\n };\n\n const setupRangeMode = (container: HTMLDivElement) => {\n updateRangeCSS();\n\n const clientToValue = (clientX: number) => {\n const rect = container.getBoundingClientRect();\n\n return sliderControl.fromClientX(clientX, rect);\n };\n let dragging: 'start' | 'end' | null = null;\n const applyDrag = (val: number) => {\n if (dragging === 'start') startVal.value = Math.min(sliderControl.snap(val), endVal.value);\n else if (dragging === 'end') endVal.value = Math.max(sliderControl.snap(val), startVal.value);\n\n startVal.value = sliderControl.clamp(startVal.value);\n endVal.value = sliderControl.clamp(endVal.value);\n updateRangeCSS();\n emit('change', {\n from: startVal.value,\n to: endVal.value,\n value: { from: startVal.value, to: endVal.value },\n });\n triggerValidation('change');\n };\n\n onEvent(\n container,\n 'pointerdown',\n guard(\n () => !isDisabled.value,\n (e: PointerEvent) => {\n e.preventDefault();\n\n const val = clientToValue(e.clientX);\n\n dragging = Math.abs(val - startVal.value) <= Math.abs(val - endVal.value) ? 'start' : 'end';\n (e.target as Element).setPointerCapture(e.pointerId);\n applyDrag(val);\n },\n ),\n );\n onEvent(\n container,\n 'pointermove',\n guard(\n () => !!dragging,\n (e: PointerEvent) => {\n e.preventDefault();\n\n if (!isDragging.value) isDragging.value = true;\n\n applyDrag(clientToValue(e.clientX));\n },\n ),\n );\n onEvent(\n container,\n 'pointerup',\n guard(\n () => !!dragging,\n (e: PointerEvent) => {\n e.preventDefault();\n dragging = null;\n isDragging.value = false;\n (e.target as Element).releasePointerCapture(e.pointerId);\n },\n ),\n );\n\n const makeThumbKeydown = (getVal: () => number, setVal: (v: number) => void) => (e: KeyboardEvent) => {\n if (isDisabled.value) return;\n\n const next = sliderControl.nextFromKey(e.key, getVal());\n\n if (next === null) return;\n\n e.preventDefault();\n setVal(sliderControl.snap(next));\n updateRangeCSS();\n emit('change', {\n from: startVal.value,\n originalEvent: e,\n to: endVal.value,\n value: { from: startVal.value, to: endVal.value },\n });\n triggerValidation('change');\n };\n const thumbStartEl = thumbStartRef.value;\n const thumbEndEl = thumbEndRef.value;\n\n if (thumbStartEl) {\n onEvent(\n thumbStartEl,\n 'keydown',\n makeThumbKeydown(\n () => startVal.value,\n (v) => {\n startVal.value = Math.min(v, endVal.value);\n },\n ),\n );\n onCleanup(\n aria(thumbStartEl, {\n label: 'Range start',\n valuemax: () => endVal.value,\n valuemin: () => sliderControl.min(),\n valuenow: () => startVal.value,\n valuetext: () => props['from-value-text'].value ?? null,\n }),\n );\n }\n\n if (thumbEndEl) {\n onEvent(\n thumbEndEl,\n 'keydown',\n makeThumbKeydown(\n () => endVal.value,\n (v) => {\n endVal.value = Math.max(v, startVal.value);\n },\n ),\n );\n onCleanup(\n aria(thumbEndEl, {\n label: 'Range end',\n valuemax: () => sliderControl.max(),\n valuemin: () => startVal.value,\n valuenow: () => endVal.value,\n valuetext: () => props['to-value-text'].value ?? null,\n }),\n );\n }\n };\n // ── Single-value mode setup ───────────────────────────────────\n const setupSingleMode = (container: HTMLDivElement) => {\n updateSingleCSS(Number(valueSignal.value));\n\n const updateValue = (clientX: number) => {\n if (isDisabled.value) return;\n\n const rect = container.getBoundingClientRect();\n const newValue = sliderControl.fromClientX(clientX, rect);\n\n if (Number(valueSignal.value) !== newValue) {\n valueSignal.value = newValue.toString();\n updateSingleCSS(newValue);\n emit('change', { value: newValue });\n triggerValidation('change');\n }\n };\n let isPointerDragging = false;\n\n onEvent(\n container,\n 'pointerdown',\n guard(\n () => !isDisabled.value,\n (e: PointerEvent) => {\n e.preventDefault();\n isPointerDragging = true;\n updateValue(e.clientX);\n (e.target as Element).setPointerCapture(e.pointerId);\n },\n ),\n );\n onEvent(\n container,\n 'pointermove',\n guard(\n () => isPointerDragging,\n (e: PointerEvent) => {\n e.preventDefault();\n\n if (!isDragging.value) isDragging.value = true;\n\n updateValue(e.clientX);\n },\n ),\n );\n onEvent(\n container,\n 'pointerup',\n guard(\n () => isPointerDragging,\n (e: PointerEvent) => {\n e.preventDefault();\n isPointerDragging = false;\n isDragging.value = false;\n (e.target as Element).releasePointerCapture(e.pointerId);\n },\n ),\n );\n onEvent(\n el,\n 'keydown',\n guard(\n () => !isDisabled.value,\n (e: KeyboardEvent) => {\n const val = Number(valueSignal.value || 0);\n const next = sliderControl.nextFromKey(e.key, val);\n\n if (next === null) return;\n\n e.preventDefault();\n\n const newValue = sliderControl.clamp(next);\n\n if (newValue !== val) {\n valueSignal.value = newValue.toString();\n updateSingleCSS(newValue);\n emit('change', { originalEvent: e, value: newValue });\n triggerValidation('change');\n }\n },\n ),\n );\n };\n\n onMounted(() => {\n const container = containerRef.value;\n\n if (!container) return;\n\n if (slots.has().value && labelRef.value) {\n const labelId = createStableId('slider-label');\n\n labelRef.value.id = labelId;\n\n if (!isRange) labelledById.value = labelId;\n }\n\n if (isRange) setupRangeMode(container);\n else setupSingleMode(container);\n });\n\n return html`\n <div class=\"slider-container\" part=\"slider\" ref=${containerRef}>\n <div class=\"slider-track\" part=\"track\">\n <div class=\"slider-fill\" part=\"fill\"></div>\n <div class=\"slider-thumb slider-thumb-sole\" part=\"thumb\"></div>\n <div\n class=\"slider-thumb slider-thumb-start\"\n part=\"thumb-start\"\n ref=${thumbStartRef}\n role=\"slider\"\n tabindex=\"${() => (isDisabled.value ? '-1' : '0')}\"\n :aria-describedby=\"${ariaDescribedBy}\"\n id=\"${startId}\"></div>\n <div\n class=\"slider-thumb slider-thumb-end\"\n part=\"thumb-end\"\n ref=${thumbEndRef}\n role=\"slider\"\n tabindex=\"${() => (isDisabled.value ? '-1' : '0')}\"\n :aria-describedby=\"${ariaDescribedBy}\"\n id=\"${endId}\"></div>\n </div>\n </div>\n <span class=\"label\" part=\"label\" ref=${labelRef}><slot></slot></span>\n ${renderHelperRegion(assistiveId, errorText, helperText)}\n `;\n },\n styles: [\n disabledStateMixin,\n colorThemeMixin,\n sizeVariantMixin(SLIDER_SIZE_PRESET),\n componentStyles,\n coarsePointerMixin,\n ],\n});\n","@layer refine.base {\n :host {\n --_width: var(--switch-width, var(--size-10));\n --_height: var(--switch-height, var(--size-5));\n --_padding: var(--size-0-5);\n --_thumb-size: calc(var(--_height) - var(--_padding) * 2);\n --_track-bg: var(--switch-track-bg, var(--color-contrast-300));\n --_thumb-bg: var(--switch-thumb-bg, white);\n --_font-size: var(--switch-font-size, var(--text-sm));\n\n display: inline-flex;\n flex-wrap: wrap;\n gap: var(--_gap, var(--size-2-5));\n align-items: center;\n min-height: var(--size-11);\n touch-action: manipulation;\n cursor: pointer;\n user-select: none;\n }\n\n /* ========================================\n Track & Thumb\n ======================================== */\n\n .switch-wrapper {\n display: flex;\n flex-shrink: 0;\n }\n\n .switch-track {\n position: relative;\n width: var(--_width);\n height: var(--_height);\n background: var(--_track-bg);\n border-radius: var(--rounded-full);\n transition:\n background var(--transition-normal),\n box-shadow var(--transition-normal);\n }\n\n .switch-thumb {\n position: absolute;\n inset-inline-start: var(--_padding);\n top: var(--_padding);\n width: var(--_thumb-size);\n height: var(--_thumb-size);\n background: var(--_thumb-bg);\n border-radius: var(--rounded-full);\n box-shadow: var(--shadow-sm);\n transition:\n transform var(--transition-spring),\n box-shadow var(--transition-normal);\n will-change: transform;\n }\n\n /* ========================================\n Focus State\n ======================================== */\n\n input:focus-visible ~ .switch-track {\n box-shadow: var(--_focus-shadow);\n }\n\n /* ========================================\n Label\n ======================================== */\n\n .label {\n font-size: var(--_font-size);\n color: var(--color-contrast);\n }\n}\n\n@layer refine.overrides {\n /* Map theme variables to switch-specific variables */\n :host {\n --_active-bg: var(--switch-checked-bg, var(--_theme-base));\n --_focus-shadow: var(--_theme-shadow);\n }\n\n /* ========================================\n Checked State\n ======================================== */\n\n :host([checked]) .switch-track {\n background: var(--_active-bg);\n }\n\n :host([checked]) .switch-thumb {\n transform: translateX(calc(var(--_width) - var(--_height)));\n }\n\n /* In RTL the thumb starts at the inline-end edge; slide left to reach inline-start */\n :host(:dir(rtl)[checked]) .switch-thumb {\n transform: translateX(calc(-1 * (var(--_width) - var(--_height))));\n }\n\n /* ========================================\n Hover & Active States\n ======================================== */\n\n :host(:hover:not([disabled], [checked])) .switch-track {\n background: var(--color-contrast-400);\n }\n\n :host(:hover:not([disabled])[checked]) .switch-track {\n filter: brightness(1.1);\n }\n\n /* ========================================\n Helper / Error Text\n ======================================== */\n\n .helper-text[hidden] {\n display: none;\n }\n\n .helper-text {\n width: 100%;\n padding-inline-start: calc(var(--_width) + var(--size-2-5));\n font-size: var(--text-xs);\n line-height: var(--leading-tight);\n color: var(--color-contrast-500);\n }\n\n .helper-text[role='alert'] {\n color: var(--color-error);\n }\n}\n","import { define, useField, html, inject, prop } from '@vielzeug/ore';\n\nimport type { CheckableProps, ComponentSize, ThemeColor } from '../../types';\n\nimport { type CheckableChangePayload, lifecycleSignal, createCheckable } from '../../headless';\nimport { disablableBundle, sizableBundle, SWITCH_SIZE_PRESET, themableBundle } from '../../shared';\nimport { colorThemeMixin, disabledStateMixin, forcedColorsFormControlMixin, sizeVariantMixin } from '../../styles';\nimport { applyCheckableBinding } from '../shared/field-binding';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport { renderHelperRegion } from '../shared/templates';\nimport componentStyles from './switch.css?inline';\n\nexport type OreSwitchEvents = {\n change: CheckableChangePayload;\n};\n\nexport type OreSwitchProps = CheckableProps & {\n /** Theme color */\n color?: ThemeColor;\n /** Disable interaction */\n disabled?: boolean;\n /** Error message (marks field as invalid) */\n error?: string;\n /** Helper text displayed below the switch */\n helper?: string;\n /** Component size */\n size?: ComponentSize;\n};\n\n/**\n * A toggle switch component for binary on/off states.\n *\n * @element ore-switch\n *\n * @attr {boolean} checked - Checked/on state\n * @attr {boolean} disabled - Disable switch interaction\n * @attr {string} value - Field value\n * @attr {string} name - Form field name\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - Switch size: 'sm' | 'md' | 'lg'\n * @attr {string} error - Error message (marks field as invalid)\n * @attr {string} helper - Helper text displayed below the switch\n *\n * @fires change - Emitted when switch is toggled. detail: { checked: boolean, value: string, originalEvent?: Event }\n *\n * @slot - Switch label text\n *\n * @cssprop --switch-width - Track width\n * @cssprop --switch-height - Track height\n * @cssprop --switch-track-bg - Inactive track background color\n * @cssprop --switch-checked-bg - Active/checked track background color\n * @cssprop --switch-thumb-bg - Thumb background color\n * @cssprop --switch-font-size - Label font size\n * @part switch - The switch wrapper element\n * @part track - The switch track element\n * @part thumb - The switch thumb element\n * @part label - The label element\n * @part helper-text - The helper/error text element\n *\n * @example\n * ```html\n * <ore-switch name=\"notifications\" checked color=\"primary\">Enable notifications</ore-switch>\n * <ore-switch name=\"darkMode\" size=\"sm\">Dark mode</ore-switch>\n * <ore-switch disabled helper=\"Contact admin to change\">Admin only</ore-switch>\n * ```\n */\nexport const SWITCH_TAG = 'ore-switch' as const;\ndefine<OreSwitchProps, OreSwitchEvents>(SWITCH_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n checked: prop.bool(false),\n error: prop.string(),\n helper: prop.string(),\n name: prop.string(),\n value: prop.string('on'),\n },\n setup(props, { bind, emit, onCleanup }) {\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(bind, props, formCtx);\n\n let _formField: { reportValidity(): void } | null = null;\n const checkable = createCheckable({\n checked: props.checked,\n clearIndeterminateFirst: false,\n disabled: fCtxProps.disabled,\n error: props.error,\n getFormField: () => _formField,\n helper: props.helper,\n onToggle: (payload) => {\n checkable.triggerValidation('change');\n emit('change', payload);\n },\n prefix: 'switch',\n signal: lifecycleSignal(onCleanup),\n validateOn: formCtx?.validateOn,\n value: props.value,\n });\n\n _formField = useField<string | null>({\n disabled: checkable.disabled,\n toFormValue: (v) => v,\n value: checkable.checkableFormValue,\n });\n\n const { assistiveId, checked, disabled, errorText, handleClick, handleKeydown, helperText, labelId } = checkable;\n\n applyCheckableBinding(\n bind,\n fCtxProps.size,\n { assistiveId, checked, disabled, errorText, handleClick, handleKeydown, helperText, labelId },\n 'switch',\n );\n\n return html`\n <div class=\"switch-wrapper\" part=\"switch\">\n <div class=\"switch-track\" part=\"track\">\n <div class=\"switch-thumb\" part=\"thumb\"></div>\n </div>\n </div>\n <span class=\"label\" part=\"label\" id=\"${labelId}\"><slot></slot></span>\n ${renderHelperRegion(assistiveId, errorText, helperText)}\n `;\n },\n styles: [\n colorThemeMixin,\n forcedColorsFormControlMixin,\n disabledStateMixin,\n sizeVariantMixin(SWITCH_SIZE_PRESET),\n componentStyles,\n ],\n});\n","@layer refine.base {\n :host {\n --_font-size: var(--textarea-font-size, var(--text-sm));\n --_gap: var(--textarea-gap, var(--size-2));\n --_padding: var(--textarea-padding, var(--size-2) var(--size-3));\n --_radius: var(--textarea-radius, var(--rounded-lg));\n --_placeholder: var(--textarea-placeholder-color, var(--color-contrast-500));\n --_bg: var(--textarea-bg, var(--color-contrast-100));\n --_border-color: var(--textarea-border-color, var(--color-contrast-300));\n --_min-height: var(--textarea-min-height, var(--size-24));\n --_max-height: var(--textarea-max-height, none);\n --_resize: var(--textarea-resize, vertical);\n\n display: inline-flex;\n flex-direction: column;\n align-items: stretch;\n min-width: 12rem;\n }\n\n .textarea-wrapper {\n display: flex;\n flex-direction: column;\n gap: var(--size-1-5);\n min-width: 0; /* Allow shrinking below content size */\n }\n\n /* Inset placement (default): label positioned inside field border */\n :host(:not([label-placement='outside'])) .textarea-wrapper {\n position: relative;\n }\n\n :host(:not([label-placement='outside'])) .label {\n position: absolute;\n inset-block-start: var(--size-2);\n inset-inline-start: var(--_padding-x, var(--size-3));\n z-index: 1;\n pointer-events: none;\n }\n\n :host(:not([label-placement='outside'])) .textarea-wrapper:has(.label:not([hidden])) .field {\n padding-block-start: calc(var(--size-2) + 1lh + 2px);\n }\n\n .field {\n box-sizing: border-box;\n display: grid; /* Grid automatically sizes to content */\n min-width: 0; /* Allow shrinking */\n padding: var(--_padding);\n background: var(--_bg);\n border: var(--border) solid var(--_border-color);\n border-radius: var(--_radius);\n box-shadow: var(--shadow-2xs);\n transition:\n background var(--transition-fast),\n backdrop-filter var(--transition-fast),\n border-color var(--transition-fast),\n box-shadow var(--transition-fast);\n }\n\n /* ========================================\n Label Styles\n ======================================== */\n\n .label,\n label.label {\n /* Default: inset style */\n margin-bottom: 2px;\n font-size: var(--text-xs);\n font-weight: var(--font-medium);\n line-height: var(--leading-tight);\n color: var(--color-contrast-500);\n cursor: pointer;\n user-select: none;\n transition: color var(--transition-fast);\n }\n\n /* Outside placement overrides */\n :host([label-placement='outside']) .label,\n :host([label-placement='outside']) label.label {\n margin-bottom: 0;\n font-size: var(--text-sm);\n line-height: var(--leading-none);\n }\n\n /* ========================================\n Helper / Error Text\n ======================================== */\n\n .helper-text[hidden] {\n display: none;\n }\n\n .helper-text {\n padding-inline: 2px;\n font-size: var(--text-xs);\n line-height: var(--leading-tight);\n color: var(--color-contrast-500);\n }\n\n /* ========================================\n Textarea Element\n ======================================== */\n\n textarea {\n box-sizing: border-box;\n min-width: 12rem; /* Match :host min-width to prevent resize below minimum */\n min-height: var(--_min-height);\n max-height: var(--_max-height);\n padding: 0;\n font: inherit;\n font-size: var(--_font-size);\n line-height: var(--leading-relaxed);\n color: var(--textarea-color, var(--text-color-body));\n resize: vertical; /* Default resize, can be overridden by inline style */\n outline: none;\n background: transparent;\n border: none;\n }\n\n textarea::placeholder {\n color: var(--_placeholder);\n transition: color var(--transition-fast);\n }\n\n textarea:focus-visible {\n outline: none;\n }\n\n /* ========================================\n Character Counter\n ======================================== */\n\n .counter {\n align-self: flex-end;\n padding-inline: 2px;\n margin-top: var(--size-1);\n font-size: var(--text-xs);\n line-height: var(--leading-tight);\n color: var(--color-contrast-400);\n transition: color var(--transition-fast);\n }\n\n .counter.near-limit {\n color: var(--color-warning);\n }\n\n .counter.at-limit {\n color: var(--color-error);\n }\n\n /* ========================================\n Hover & Focus States\n ======================================== */\n\n :host(:not([disabled], [variant='bordered'], [variant='flat'])) .field:hover {\n border-color: var(--color-contrast-400);\n }\n\n :host(:not([disabled], [variant='text'], [variant='flat'])) .field:focus-within {\n background: var(--color-canvas);\n border-color: var(--_theme-focus);\n box-shadow: var(--_theme-shadow, var(--color-primary-focus-shadow));\n }\n\n :host(:not([disabled])) .field:focus-within ~ .label,\n :host(:not([disabled])) .textarea-wrapper:has(.field:focus-within) .label {\n color: var(--_theme-focus);\n }\n\n /* Error State */\n :host([error]:not([error=''])) .field {\n border-color: var(--color-error);\n }\n\n :host([error]:not([error=''])) .field:focus-within {\n border-color: var(--color-error);\n box-shadow: var(--color-error-focus-shadow);\n }\n\n :host([error]:not([error=''])) .label {\n color: var(--color-error);\n }\n}\n\n@layer refine.variants {\n /* Solid (Default) */\n :host(:not([variant])),\n :host([variant='solid']) {\n --_bg: var(--textarea-bg, var(--color-contrast-50));\n --_border-color: var(--textarea-border-color, var(--color-contrast-300));\n }\n\n :host(:not([variant])) .field,\n :host([variant='solid']) .field {\n box-shadow: var(--shadow-2xs);\n }\n\n :host(:not([variant], [disabled])) .field:focus-within,\n :host([variant='solid']:not([disabled])) .field:focus-within {\n box-shadow: var(--_theme-shadow);\n }\n\n /* Flat */\n :host([variant='flat']) {\n --_bg: var(--textarea-bg, var(--color-contrast-100));\n --_border-color: var(--textarea-border-color, var(--_theme-border));\n }\n\n :host([variant='flat']) .field {\n box-shadow: var(--inset-shadow-2xs);\n }\n\n :host([variant='flat']) .field:hover {\n background: var(--textarea-hover-bg, color-mix(in oklch, var(--_theme-base) 6%, var(--color-contrast-100)));\n border-color: var(\n --textarea-hover-border-color,\n color-mix(in oklch, var(--_theme-base) 35%, var(--color-contrast-300))\n );\n }\n\n :host([variant='flat']) .field:focus-within {\n background: var(--textarea-focus-bg, color-mix(in oklch, var(--_theme-base) 8%, var(--color-canvas)));\n border-color: var(--textarea-focus-border-color, color-mix(in oklch, var(--_theme-focus) 60%, transparent));\n box-shadow: var(--_theme-shadow);\n }\n\n /* Bordered */\n :host([variant='bordered']) {\n --_bg: var(--textarea-bg, var(--_theme-backdrop));\n --_border-color: var(--textarea-border-color, color-mix(in oklch, var(--_theme-focus) 70%, transparent));\n }\n\n :host([variant='bordered']) textarea {\n color: var(--_theme-base);\n }\n\n :host([variant='bordered']) textarea::placeholder {\n color: var(--textarea-placeholder-color, color-mix(in oklch, var(--_theme-base) 45%, transparent));\n }\n\n :host([variant='bordered']) .field:hover {\n border-color: var(--textarea-hover-border-color, var(--_theme-focus));\n }\n\n /* Outline */\n :host([variant='outline']) {\n --_bg: var(--textarea-bg, transparent);\n }\n\n :host([variant='outline']) .field {\n box-shadow: none;\n }\n\n :host([variant='outline']:not([disabled])) .field:focus-within {\n box-shadow: var(--_theme-shadow);\n }\n\n /* Ghost */\n :host([variant='ghost']) {\n --_bg: var(--textarea-bg, transparent);\n --_border-color: var(--textarea-border-color, transparent);\n }\n\n :host([variant='ghost']) .field {\n box-shadow: none;\n }\n\n :host([variant='ghost']) .field:hover {\n background: var(--textarea-hover-bg, var(--color-contrast-100));\n }\n\n :host([variant='ghost']:not([disabled])) .field:focus-within {\n box-shadow: var(--_theme-shadow);\n }\n}\n\n@layer refine.utilities {\n /* Auto-resize hides overflow */\n :host([auto-resize]) textarea {\n overflow: hidden;\n }\n\n /* Full width */\n :host([fullwidth]) {\n width: 100%;\n }\n}\n","import { define, useField, html, inject, prop, ref } from '@vielzeug/ore';\nimport { live } from '@vielzeug/ore/directives';\nimport { watch as rippleWatch } from '@vielzeug/ripple';\n\nimport type { TextFieldProps } from '../../shared';\nimport type { VisualVariant } from '../../types';\n\nimport { lifecycleSignal, createTextField } from '../../headless';\nimport { disablableBundle, roundableBundle, sizableBundle, TEXTAREA_SIZE_PRESET, themableBundle } from '../../shared';\nimport { fieldMixins, forcedColorsFocusMixin, sizeVariantMixin } from '../../styles';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport componentStyles from './textarea.css?inline';\n\n/** Textarea component properties */\n\nexport type OreTextareaEvents = {\n change: { originalEvent: Event; value: string };\n input: { originalEvent: Event; value: string };\n};\n\nexport type OreTextareaProps = TextFieldProps<Exclude<VisualVariant, 'frost' | 'text'>> & {\n /** Allow auto-grow with content */\n 'auto-resize'?: boolean;\n /** Maximum character count; shows a counter when set */\n maxlength?: number;\n /** Disable a manual resize handle */\n 'no-resize'?: boolean;\n /**\n * JS-only callback fired with the inner `<textarea>` element when it mounts,\n * and with `null` when it unmounts. Intended for composed components that\n * need imperative access to the raw element.\n * Set as a JS property: `bitTextarea.ref = (el) => { ... }`.\n */\n ref?: ((el: HTMLTextAreaElement | null) => void) | null;\n /** Resize direction override */\n resize?: 'none' | 'horizontal' | 'both' | 'vertical';\n /** Number of visible text rows */\n rows?: number;\n};\n\n/**\n * A multi-line text input with label, helper text, character counter, and auto-resize.\n *\n * @element ore-textarea\n *\n * @attr {string} label - Label text\n * @attr {string} label-placement - 'inset' | 'outside'\n * @attr {string} value - Current value\n * @attr {string} placeholder - Placeholder text\n * @attr {string} name - Form field name\n * @attr {number} rows - Visible row count\n * @attr {number} maxlength - Max character count (shows counter)\n * @attr {string} helper - Helper text below the textarea\n * @attr {string} error - Error message\n * @attr {boolean} disabled - Disable interaction\n * @attr {boolean} readonly - Read-only mode\n * @attr {boolean} required - Required field\n * @attr {boolean} no-resize - Disable manual resize\n * @attr {boolean} auto-resize - Grow with content\n * @attr {string} resize - Resize direction: 'none' | 'horizontal' | 'both' | 'vertical'\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'outline' | 'ghost'\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n *\n * @fires input - Fired on every keystroke with current value. detail: { value: string; originalEvent: Event }\n * @fires change - Fired on blur with changed value. detail: { value: string; originalEvent: Event }\n *\n * @slot helper - Complex helper content\n *\n * @cssprop --textarea-bg - Background color\n * @cssprop --textarea-border-color - Border color\n * @cssprop --textarea-placeholder-color - Placeholder text color\n * @cssprop --textarea-radius - Border radius\n * @cssprop --textarea-padding - Inner padding (block inline)\n * @cssprop --textarea-gap - Gap between label and field\n * @cssprop --textarea-font-size - Font size\n * @cssprop --textarea-min-height - Minimum field height\n * @cssprop --textarea-max-height - Maximum field height (none = unlimited)\n * @cssprop --textarea-resize - CSS resize direction ('vertical' | 'horizontal' | 'both' | 'none')\n * @cssprop --textarea-hover-bg - Field background on hover (flat/ghost variants)\n * @cssprop --textarea-hover-border-color - Field border on hover (flat/bordered variants)\n * @cssprop --textarea-focus-bg - Field background when focused (flat variant)\n * @cssprop --textarea-focus-border-color - Field border when focused (flat variant)\n *\n * @part wrapper - Outer wrapper element.\n * @part label - Label element.\n * @part field - Field container.\n * @part textarea - The native `<textarea>` element.\n * @part helper - The helper text element.\n * @part error - The error text element (`role=\"alert\"`).\n *\n * @example\n * ```html\n * <ore-textarea></ore-textarea>\n * ```\n */\nexport const TEXTAREA_TAG = 'ore-textarea' as const;\ndefine<OreTextareaProps, OreTextareaEvents>(TEXTAREA_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n ...roundableBundle,\n 'auto-resize': prop.bool(false),\n error: prop.string(),\n fullwidth: prop.bool(false),\n helper: prop.string(),\n label: prop.string(),\n 'label-placement': prop.oneOf(['inset', 'outside'] as const, 'inset'),\n maxlength: prop.json(undefined as number | undefined),\n name: prop.string(),\n 'no-resize': prop.bool(false),\n placeholder: prop.string(),\n readonly: prop.bool(false),\n ref: prop.json(undefined as ((el: HTMLTextAreaElement | null) => void) | null | undefined),\n required: prop.bool(false),\n resize: prop.string<'none' | 'both' | 'horizontal' | 'vertical'>(),\n rows: prop.json(undefined as number | undefined),\n value: prop.string(),\n variant: prop.string<'flat' | 'solid' | 'bordered' | 'outline' | 'ghost'>(),\n },\n setup(props, { bind, emit, onCleanup, onElement, watch }) {\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(bind, props, formCtx);\n\n const textareaRef = ref<HTMLTextAreaElement>();\n\n const autoGrow = () => {\n if (!props['auto-resize'].value || !textareaRef.value) return;\n\n const textareaEl = textareaRef.value;\n\n textareaEl.style.height = 'auto';\n textareaEl.style.height = `${textareaEl.scrollHeight}px`;\n };\n\n const abortSignal = lifecycleSignal(onCleanup);\n let _formField: { reportValidity(): void } | null = null;\n const tf = createTextField({\n disabled: fCtxProps.disabled,\n error: props.error,\n getFormField: () => _formField,\n helper: props.helper,\n label: props.label,\n labelPlacement: props['label-placement'],\n maxLength: props.maxlength,\n onBeforeInput: autoGrow,\n onChange: (event: Event, value: string) => {\n emit('change', { originalEvent: event, value });\n },\n onInput: (event: Event, value: string) => {\n emit('input', { originalEvent: event, value });\n },\n prefix: 'textarea',\n signal: abortSignal,\n validateOn: formCtx?.validateOn,\n value: props.value,\n });\n\n _formField = useField<string>({ disabled: tf.disabled, toFormValue: (v) => v, value: tf.value });\n\n const {\n ariaDescribedBy,\n ariaErrorMessage,\n ariaInvalid,\n ariaLabelledBy,\n assistiveId,\n counter,\n errorId,\n errorText,\n fieldId: textareaId,\n helperText,\n labelId,\n labelVisible,\n } = tf;\n\n onElement(textareaRef, (textareaEl) => {\n const unwireEl = tf.wire(textareaEl);\n\n props.ref.value?.(textareaEl);\n\n const sub = rippleWatch(props.ref, (cb) => {\n cb?.(textareaEl);\n });\n\n const stopLayoutEffect = watch(() => {\n textareaEl.style.resize =\n props['auto-resize'].value || props['no-resize'].value ? 'none' : props.resize.value || 'vertical';\n\n if (props['auto-resize'].value) {\n requestAnimationFrame(autoGrow);\n }\n });\n\n return () => {\n sub.dispose();\n props.ref.value?.(null);\n unwireEl();\n stopLayoutEffect();\n };\n });\n\n bind({\n attr: {\n error: () => errorText.value || undefined,\n size: fCtxProps.size,\n variant: fCtxProps.variant,\n },\n });\n\n const counterClass = () =>\n counter?.value.counterAtLimit\n ? 'counter at-limit'\n : counter?.value.counterNearLimit\n ? 'counter near-limit'\n : 'counter';\n const counterHidden = () => !counter;\n const counterText = () => counter?.value.counterText.replace(' / ', '/') ?? '';\n const helperHidden = () => !!errorText.value || !helperText.value;\n const errorHidden = () => !errorText.value;\n\n return html`\n <div class=\"textarea-wrapper\" part=\"wrapper\">\n <label class=\"label\" part=\"label\" for=\"${textareaId}\" id=\"${labelId}\" ?hidden=\"${() => !labelVisible.value}\"\n >${props.label}</label\n >\n <div class=\"field\" part=\"field\">\n <textarea\n part=\"textarea\"\n ref=\"${textareaRef}\"\n id=\"${textareaId}\"\n :name=\"${props.name}\"\n :placeholder=\"${props.placeholder}\"\n :rows=\"${props.rows}\"\n :maxlength=\"${props.maxlength}\"\n ?disabled=\"${props.disabled}\"\n ?readonly=\"${props.readonly}\"\n ?required=\"${props.required}\"\n :value=\"${live(tf.value)}\"\n :aria-describedby=\"${ariaDescribedBy}\"\n :aria-errormessage=\"${ariaErrorMessage}\"\n :aria-invalid=\"${ariaInvalid}\"\n :aria-labelledby=\"${ariaLabelledBy}\"></textarea>\n </div>\n <span class=\"${counterClass}\" aria-live=\"polite\" ?hidden=\"${counterHidden}\">${counterText}</span>\n <div id=\"${assistiveId}\" class=\"helper-text\" aria-live=\"polite\" part=\"helper\" ?hidden=\"${helperHidden}\">\n ${() => helperText.value}\n </div>\n <div id=\"${errorId}\" class=\"helper-text\" role=\"alert\" part=\"error\" ?hidden=\"${errorHidden}\">\n ${() => errorText.value}\n </div>\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [...fieldMixins, sizeVariantMixin(TEXTAREA_SIZE_PRESET), forcedColorsFocusMixin('textarea'), componentStyles],\n});\n","@layer refine.base {\n :host {\n --_selected-bg: var(--time-picker-selected-bg, var(--_theme-focus));\n --_hover-bg: var(--time-picker-option-hover-bg, color-mix(in oklch, var(--_selected-bg) 12%, transparent));\n\n position: relative;\n display: inline-block;\n }\n\n :host([fullwidth]) {\n display: block;\n }\n\n :host([color='secondary']) {\n --_selected-bg: var(--time-picker-selected-bg, var(--_theme-base));\n }\n\n /* Prevent display:flex/grid from overriding [hidden] attribute */\n [hidden] {\n display: none !important;\n }\n\n /* ── Trigger ─────────────────────────────────────────────────────────────── */\n\n .trigger {\n cursor: pointer;\n }\n\n .trigger::part(input) {\n cursor: pointer;\n caret-color: transparent;\n user-select: none;\n }\n\n /* ── Dropdown ────────────────────────────────────────────────────────────── */\n\n .dropdown {\n position: absolute;\n top: calc(100% + var(--size-1));\n left: 0;\n z-index: var(--z-dropdown, 200);\n display: flex;\n flex-direction: column;\n min-width: 12rem;\n overflow: hidden;\n pointer-events: none;\n background: var(--time-picker-bg, var(--_bg));\n border: var(--border) solid var(--time-picker-border-color, var(--_border-color));\n border-radius: var(--time-picker-radius, var(--_radius));\n box-shadow: var(--time-picker-shadow, var(--shadow-lg));\n\n /* Hidden by default */\n opacity: 0;\n backdrop-filter: blur(var(--blur-sm));\n transform: translateY(var(--overlay-enter-translate-y));\n transition: var(\n --_motion-transition,\n opacity var(--transition-fast),\n transform var(--transition-fast),\n display var(--transition-fast) allow-discrete\n );\n }\n\n .dropdown[data-open] {\n pointer-events: auto;\n opacity: 1;\n transform: translateY(0);\n\n @starting-style {\n opacity: 0;\n transform: translateY(var(--overlay-enter-translate-y));\n }\n }\n\n /* ── Columns row ────────────────────────────────────────────────────────── */\n\n .cols-row {\n display: flex;\n flex-direction: row;\n align-items: stretch;\n }\n\n /* ── Columns (hours / sep / minutes / [period]) ──────────────────────────── */\n\n .col,\n .col-sep {\n display: flex;\n flex-direction: column;\n align-items: center;\n }\n\n .col {\n flex: 1;\n min-width: var(--size-14);\n border-block-end: var(--border) solid var(--_border-color);\n }\n\n .col-period {\n flex: 0 0 auto;\n min-width: var(--size-16);\n }\n\n /* ── Column header label ─────────────────────────────────────────────────── */\n\n .col-label {\n width: 100%;\n padding: var(--size-1) var(--size-2);\n font-size: var(--text-xs);\n font-weight: var(--font-medium);\n color: var(--color-contrast-400);\n text-align: center;\n letter-spacing: 0.05em;\n border-block-end: var(--border) solid var(--_border-color);\n }\n\n /* ── Scrollable option list ──────────────────────────────────────────────── */\n\n .col-scroll {\n width: 100%;\n max-height: 11rem;\n padding-block: var(--size-1);\n overflow-y: auto;\n scrollbar-width: thin;\n }\n\n /* ── Separator between hours and minutes ─────────────────────────────────── */\n\n .col-sep {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n padding-block-start: var(--size-8); /* visually align with first option row */\n padding-inline: var(--size-0-5);\n font-size: var(--text-lg);\n font-weight: var(--font-semibold);\n color: var(--color-contrast-500);\n user-select: none;\n border-block-end: var(--border) solid var(--_border-color);\n }\n\n /* ── Option cells ────────────────────────────────────────────────────────── */\n\n .option {\n display: flex;\n align-items: center;\n justify-content: center;\n height: var(--size-8);\n padding-inline: var(--size-2);\n margin-inline: var(--size-1);\n font-size: var(--text-sm);\n color: var(--color-contrast-800);\n cursor: pointer;\n outline: none;\n border-radius: var(--rounded-sm);\n transition:\n background var(--transition-fast),\n color var(--transition-fast);\n }\n\n .option:hover:not([data-disabled]) {\n color: var(--color-contrast-900);\n background: var(--_hover-bg);\n }\n\n .option:focus-visible {\n box-shadow: 0 0 0 2px var(--_selected-bg);\n }\n\n .option[aria-selected='true'] {\n font-weight: var(--font-semibold);\n color: var(--color-white, #fff);\n background: var(--_selected-bg);\n }\n\n .option[data-disabled] {\n pointer-events: none;\n cursor: not-allowed;\n opacity: 0.3;\n }\n\n /* ── Reduced motion ──────────────────────────────────────────────────────── */\n\n @media (prefers-reduced-motion: reduce) {\n .option {\n transition: none;\n }\n }\n}\n","import { define, useField, html, inject, prop } from '@vielzeug/ore';\nimport { computed, signal } from '@vielzeug/ripple';\n\nimport type { VisualVariant } from '../../shared';\n\nimport '../../content/icon/icon';\nimport '../input/input';\nimport { disablableBundle, roundableBundle, sizableBundle, themableBundle } from '../../shared';\nimport { colorThemeMixin, reducedMotionMixin } from '../../styles';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport componentStyles from './time-picker.css?inline';\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport type OreTimePickerEvents = {\n change: { value: string | null };\n};\n\nexport type OreTimePickerProps = {\n /** Theme color */\n color?: string;\n /** Disable the picker */\n disabled?: boolean;\n /** Validation error message */\n error?: string;\n /** Expand to container width */\n fullwidth?: boolean;\n /** Helper text below the field */\n helper?: string;\n /** Visible label */\n label?: string;\n /** Label placement */\n 'label-placement'?: 'inset' | 'outside';\n /** Maximum selectable time in HH:MM format (24-hour) */\n max?: string;\n /** Minimum selectable time in HH:MM format (24-hour) */\n min?: string;\n /** Minute step interval (1–59) */\n 'minute-step'?: number;\n /** Form field name */\n name?: string;\n /** Placeholder shown in the trigger */\n placeholder?: string;\n /** Mark field as required */\n required?: boolean;\n /** Border radius */\n rounded?: string;\n /** Component size */\n size?: string;\n /** Display format: '12' for AM/PM, '24' for 24-hour (default: '24') */\n 'time-format'?: '12' | '24';\n /** Selected time in HH:MM format (24-hour) */\n value?: string;\n /** Visual variant */\n variant?: Exclude<VisualVariant, 'text' | 'frost'>;\n};\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\n/** Parse \"HH:MM\" → { hours: 0-23, minutes: 0-59 } | null */\nfunction parseTime(val: string | undefined | null): { hours: number; minutes: number } | null {\n if (!val) return null;\n\n const match = /^(\\d{1,2}):(\\d{2})$/.exec(val.trim());\n\n if (!match) return null;\n\n const h = Number(match[1]);\n const m = Number(match[2]);\n\n if (h < 0 || h > 23 || m < 0 || m > 59) return null;\n\n return { hours: h, minutes: m };\n}\n\n/** Format { hours, minutes } → \"HH:MM\" (24-hour, zero-padded) */\nfunction formatTime(h: number, m: number): string {\n return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}`;\n}\n\n/** Format for display label (respects 12/24 mode) */\nfunction formatDisplay(h: number, m: number, format: '12' | '24'): string {\n if (format === '12') {\n const period = h >= 12 ? 'PM' : 'AM';\n const displayH = h % 12 === 0 ? 12 : h % 12;\n\n return `${String(displayH).padStart(2, '0')}:${String(m).padStart(2, '0')} ${period}`;\n }\n\n return formatTime(h, m);\n}\n\n/** Clamp value to [min, max] in total minutes */\nfunction clampTime(\n h: number,\n m: number,\n minVal: string | undefined | null,\n maxVal: string | undefined | null,\n): { hours: number; minutes: number } {\n const total = h * 60 + m;\n const minParsed = parseTime(minVal);\n const maxParsed = parseTime(maxVal);\n const minMins = minParsed ? minParsed.hours * 60 + minParsed.minutes : 0;\n const maxMins = maxParsed ? maxParsed.hours * 60 + maxParsed.minutes : 23 * 60 + 59;\n const clamped = Math.min(Math.max(total, minMins), maxMins);\n\n return { hours: Math.floor(clamped / 60), minutes: clamped % 60 };\n}\n\n/**\n * An accessible time picker with a scrollable clock dropdown.\n * Supports 12/24-hour display formats, min/max bounds, minute steps, and form association.\n *\n * @element ore-time-picker\n *\n * @attr {string} value - Selected time in HH:MM (24-hour) format\n * @attr {string} min - Minimum selectable time (HH:MM)\n * @attr {string} max - Maximum selectable time (HH:MM)\n * @attr {string} label - Label text\n * @attr {string} label-placement - 'inset' | 'outside'\n * @attr {string} placeholder - Trigger placeholder\n * @attr {boolean} disabled - Disable the picker\n * @attr {boolean} required - Required field\n * @attr {string} name - Form field name\n * @attr {string} error - Error message\n * @attr {string} helper - Helper text\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'outline' | 'ghost'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n * @attr {string} time-format - '12' or '24' (default: '24')\n * @attr {number} minute-step - Minute increment (default: 5)\n *\n * @fires change - Fired when a time is selected. detail: { value: string | null }\n *\n * @slot label - Custom label for the trigger field\n * @slot prefix - Content before the trigger text (e.g. icon)\n * @slot helper - Custom helper text\n * @slot error - Custom error content\n *\n * @cssprop --time-picker-bg - Dropdown background\n * @cssprop --time-picker-border-color - Dropdown border color\n * @cssprop --time-picker-radius - Dropdown border radius\n * @cssprop --time-picker-shadow - Dropdown shadow\n * @cssprop --time-picker-selected-bg - Selected option background\n * @cssprop --time-picker-option-hover-bg - Option hover background\n *\n * @part field - The trigger field\n * @part dropdown - The floating time dropdown\n * @part column - A scrollable column (hours / minutes / period)\n * @part option - An individual time option cell\n *\n * @example\n * ```html\n * <!-- 24-hour clock, 15-minute steps -->\n * <ore-time-picker label=\"Meeting time\" value=\"09:30\" minute-step=\"15\" color=\"primary\"></ore-time-picker>\n *\n * <!-- 12-hour AM/PM format -->\n * <ore-time-picker label=\"Appointment\" time-format=\"12\" minute-step=\"30\"></ore-time-picker>\n *\n * <!-- Outside label, bordered variant -->\n * <ore-time-picker label=\"Start time\" label-placement=\"outside\" variant=\"bordered\"></ore-time-picker>\n * ```\n */\nexport const TIME_PICKER_TAG = 'ore-time-picker' as const;\n\ndefine<OreTimePickerProps, OreTimePickerEvents>(TIME_PICKER_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n ...roundableBundle,\n error: prop.string(),\n fullwidth: prop.bool(false),\n helper: prop.string(),\n label: prop.string(),\n 'label-placement': prop.oneOf(['inset', 'outside'] as const, 'inset'),\n max: prop.string(),\n min: prop.string(),\n 'minute-step': prop.number(5),\n name: prop.string(),\n placeholder: prop.string(),\n required: prop.bool(false),\n 'time-format': prop.oneOf(['12', '24'] as const, '24'),\n value: prop.string(),\n variant: prop.string<'flat' | 'solid' | 'bordered' | 'outline' | 'ghost'>(),\n },\n\n setup(props, { bind, el, emit, onMounted }) {\n // ── Signals ──────────────────────────────────────────────────────────────\n\n const isOpen = signal(false);\n const selectedTime = signal<{ hours: number; minutes: number } | null>(parseTime(props.value.value));\n\n // ── Form context ─────────────────────────────────────────────────────────\n\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(bind, props, formCtx);\n const isDisabled = fCtxProps.disabled;\n\n // ── Form value ────────────────────────────────────────────────────────────\n\n useField<string>({\n disabled: isDisabled,\n toFormValue: (v) => v || null,\n value: computed(() => {\n const t = selectedTime.value;\n\n return t ? formatTime(t.hours, t.minutes) : '';\n }),\n });\n\n // ── Computed helpers ──────────────────────────────────────────────────────\n\n const fmt = computed(() => props['time-format'].value ?? '24');\n const minuteStep = computed(() => Math.max(1, Math.min(59, props['minute-step'].value ?? 5)));\n\n const triggerText = computed(() => {\n if (!selectedTime.value) return props.placeholder.value || '';\n\n return formatDisplay(selectedTime.value.hours, selectedTime.value.minutes, fmt.value as '12' | '24');\n });\n\n /** All hour options for the column (0-23 in 24h; 1-12 in 12h) */\n const hourOptions = computed<number[]>(() => {\n if (fmt.value === '12') {\n return Array.from({ length: 12 }, (_, i) => i + 1);\n }\n\n return Array.from({ length: 24 }, (_, i) => i);\n });\n\n /** All minute options for the column, stepped */\n const minuteOptions = computed<number[]>(() => {\n const step = minuteStep.value;\n const opts: number[] = [];\n\n for (let m = 0; m < 60; m += step) opts.push(m);\n\n return opts;\n });\n\n const dialogId = `time-picker-${Math.random().toString(36).slice(2, 9)}-dropdown`;\n\n /** Convert 24h hour to display hour in current format */\n function toDisplayHour(h24: number): number {\n if (fmt.value === '24') return h24;\n\n const h12 = h24 % 12;\n\n return h12 === 0 ? 12 : h12;\n }\n\n /** Convert display hour + period → 24h hour */\n function to24Hour(displayHour: number, period: 'AM' | 'PM'): number {\n if (fmt.value === '24') return displayHour;\n\n if (period === 'AM') return displayHour === 12 ? 0 : displayHour;\n\n return displayHour === 12 ? 12 : displayHour + 12;\n }\n\n /** Whether a given HH:MM is out of [min, max] */\n function isTimeDisabled(h: number, m: number): boolean {\n const total = h * 60 + m;\n const minParsed = parseTime(props.min.value);\n const maxParsed = parseTime(props.max.value);\n\n if (minParsed && total < minParsed.hours * 60 + minParsed.minutes) return true;\n\n if (maxParsed && total > maxParsed.hours * 60 + maxParsed.minutes) return true;\n\n return false;\n }\n\n // ── State for focused/pending selection ───────────────────────────────────\n\n /** Pending hour (24h) while user is navigating columns */\n const pendingHour = signal<number>(selectedTime.value?.hours ?? 0);\n /** Pending minute */\n const pendingMinute = signal<number>(selectedTime.value?.minutes ?? 0);\n /** Pending period (12h mode) */\n const pendingPeriod = signal<'AM' | 'PM'>((selectedTime.value?.hours ?? 0) >= 12 ? 'PM' : 'AM');\n\n // ── Sync value prop externally ────────────────────────────────────────────\n\n let lastValueProp = props.value.value;\n\n onMounted(() => {\n const interval = setInterval(() => {\n const current = props.value.value;\n\n if (current !== lastValueProp) {\n lastValueProp = current;\n\n const parsed = parseTime(current);\n\n selectedTime.value = parsed;\n\n if (parsed) {\n pendingHour.value = parsed.hours;\n pendingMinute.value = parsed.minutes;\n pendingPeriod.value = parsed.hours >= 12 ? 'PM' : 'AM';\n }\n }\n }, 50);\n\n return () => clearInterval(interval);\n });\n\n // ── Commit ────────────────────────────────────────────────────────────────\n\n function commit(h24: number, m: number): void {\n const clamped = clampTime(h24, m, props.min.value, props.max.value);\n const snapped = Math.round(clamped.minutes / minuteStep.value) * minuteStep.value;\n const snappedMin = Math.min(snapped, 59);\n\n selectedTime.value = { hours: clamped.hours, minutes: snappedMin };\n emit('change', { value: formatTime(clamped.hours, snappedMin) });\n }\n\n function commitFromMinute(m: number): void {\n const h24 = fmt.value === '12' ? to24Hour(pendingHour.value, pendingPeriod.value) : pendingHour.value;\n\n pendingMinute.value = m;\n commit(h24, m);\n closePicker();\n }\n\n // ── Open / close ──────────────────────────────────────────────────────────\n\n function openPicker(): void {\n if (isDisabled.value) return;\n\n const current = selectedTime.value;\n\n if (current) {\n pendingHour.value = fmt.value === '12' ? toDisplayHour(current.hours) : current.hours;\n pendingMinute.value = current.minutes;\n pendingPeriod.value = current.hours >= 12 ? 'PM' : 'AM';\n } else {\n pendingHour.value = fmt.value === '12' ? 12 : 0;\n pendingMinute.value = 0;\n pendingPeriod.value = 'AM';\n }\n\n isOpen.value = true;\n }\n\n function closePicker(): void {\n isOpen.value = false;\n }\n\n function handleTriggerClick(): void {\n if (isOpen.value) closePicker();\n else openPicker();\n }\n\n // ── Outside click ─────────────────────────────────────────────────────────\n\n function handleOutsideClick(e: PointerEvent | MouseEvent): void {\n if (!isOpen.value) return;\n\n if (!e.composedPath().includes(el)) closePicker();\n }\n\n onMounted(() => {\n document.addEventListener('pointerdown', handleOutsideClick, { capture: true });\n\n return () => document.removeEventListener('pointerdown', handleOutsideClick, { capture: true });\n });\n\n // ── Keyboard ──────────────────────────────────────────────────────────────\n\n function handleTriggerKeydown(e: KeyboardEvent): void {\n if (isDisabled.value) return;\n\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleTriggerClick();\n } else if (e.key === 'Escape' && isOpen.value) {\n e.preventDefault();\n closePicker();\n } else if ((e.key === 'ArrowDown' || e.key === 'ArrowUp') && !isOpen.value) {\n e.preventDefault();\n openPicker();\n }\n }\n\n function handleDropdownKeydown(e: KeyboardEvent): void {\n if (e.key === 'Escape') {\n e.preventDefault();\n closePicker();\n }\n }\n\n function handleHourKeydown(e: KeyboardEvent): void {\n const opts = hourOptions.value;\n const idx = opts.indexOf(pendingHour.value);\n\n if (e.key === 'ArrowUp') {\n e.preventDefault();\n pendingHour.value = opts[(idx - 1 + opts.length) % opts.length];\n } else if (e.key === 'ArrowDown') {\n e.preventDefault();\n pendingHour.value = opts[(idx + 1) % opts.length];\n }\n }\n\n function handleMinuteKeydown(e: KeyboardEvent): void {\n const opts = minuteOptions.value;\n const idx = opts.indexOf(pendingMinute.value);\n\n if (e.key === 'ArrowUp') {\n e.preventDefault();\n pendingMinute.value = opts[(idx - 1 + opts.length) % opts.length];\n } else if (e.key === 'ArrowDown') {\n e.preventDefault();\n pendingMinute.value = opts[(idx + 1) % opts.length];\n }\n }\n\n function handlePeriodKeydown(e: KeyboardEvent): void {\n if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {\n e.preventDefault();\n pendingPeriod.value = pendingPeriod.value === 'AM' ? 'PM' : 'AM';\n }\n }\n\n // ── Host bindings ─────────────────────────────────────────────────────────\n\n bind({\n attr: {\n open: () => (isOpen.value ? true : undefined),\n },\n });\n\n // ── ore-input prop helpers ────────────────────────────────────────────────\n\n const inputValue = () => triggerText.value;\n const inputLabel = () => props.label.value ?? '';\n const inputPlaceholder = () => props.placeholder.value ?? '';\n const inputLabelPlacement = () => props['label-placement'].value ?? 'inset';\n const inputColor = () => props.color?.value ?? undefined;\n const inputSize = () => fCtxProps.size?.value ?? undefined;\n const inputVariant = () => fCtxProps.variant?.value ?? undefined;\n const inputRounded = () => props.rounded?.value ?? undefined;\n const inputHelper = () => props.helper.value ?? '';\n const inputError = () => props.error.value ?? '';\n const inputDisabled = () => (isDisabled.value ? true : undefined);\n const inputRequired = () => (props.required.value ? true : undefined);\n const inputFullwidth = () => (props.fullwidth.value ? true : undefined);\n\n return html`\n <!-- Trigger -->\n <ore-input\n class=\"trigger\"\n readonly\n tabindex=\"0\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n aria-controls=\"${dialogId}\"\n :aria-expanded=\"${() => String(isOpen.value)}\"\n :aria-disabled=\"${() => (isDisabled.value ? 'true' : null)}\"\n :value=\"${inputValue}\"\n :label=\"${inputLabel}\"\n :placeholder=\"${inputPlaceholder}\"\n :label-placement=\"${inputLabelPlacement}\"\n :color=\"${inputColor}\"\n :size=\"${inputSize}\"\n :variant=\"${inputVariant}\"\n :rounded=\"${inputRounded}\"\n :helper=\"${inputHelper}\"\n :error=\"${inputError}\"\n ?disabled=\"${inputDisabled}\"\n ?required=\"${inputRequired}\"\n ?fullwidth=\"${inputFullwidth}\"\n @click=\"${handleTriggerClick}\"\n @keydown=\"${handleTriggerKeydown}\">\n <ore-icon slot=\"suffix\" name=\"clock\" size=\"16\" stroke-width=\"1.75\" aria-hidden=\"true\"></ore-icon>\n </ore-input>\n\n <!-- Dropdown -->\n <div\n class=\"dropdown\"\n id=\"${dialogId}\"\n role=\"listbox\"\n aria-label=\"${() => (props.label.value ? `${props.label.value} — select time` : 'Select time')}\"\n ?data-open=\"${isOpen}\"\n @keydown=\"${handleDropdownKeydown}\">\n <div class=\"cols-row\">\n <!-- Hours column -->\n <div class=\"col\" part=\"column\" role=\"group\" aria-label=\"Hours\">\n <div class=\"col-label\" aria-hidden=\"true\">HH</div>\n <div class=\"col-scroll\">\n ${() =>\n hourOptions.value.map((h) => {\n const h24 = fmt.value === '12' ? to24Hour(h, pendingPeriod.value) : h;\n const disabled = isTimeDisabled(h24, pendingMinute.value);\n\n return html`<div\n class=\"option\"\n part=\"option\"\n role=\"option\"\n tabindex=\"${() => (pendingHour.value === h && !disabled ? '0' : '-1')}\"\n :aria-selected=\"${() => String(pendingHour.value === h)}\"\n :aria-disabled=\"${() => String(disabled)}\"\n ?data-disabled=\"${() => disabled}\"\n @click=\"${() => {\n if (!disabled) pendingHour.value = h;\n }}\"\n @keydown=\"${handleHourKeydown}\">\n ${String(h).padStart(2, '0')}\n </div>`;\n })}\n </div>\n </div>\n\n <div class=\"col-sep\" aria-hidden=\"true\">:</div>\n\n <!-- Minutes column -->\n <div class=\"col\" part=\"column\" role=\"group\" aria-label=\"Minutes\">\n <div class=\"col-label\" aria-hidden=\"true\">MM</div>\n <div class=\"col-scroll\">\n ${() =>\n minuteOptions.value.map((m) => {\n const h24 = fmt.value === '12' ? to24Hour(pendingHour.value, pendingPeriod.value) : pendingHour.value;\n const disabled = isTimeDisabled(h24, m);\n\n return html`<div\n class=\"option\"\n part=\"option\"\n role=\"option\"\n tabindex=\"${() => (pendingMinute.value === m && !disabled ? '0' : '-1')}\"\n :aria-selected=\"${() => String(pendingMinute.value === m)}\"\n :aria-disabled=\"${() => String(disabled)}\"\n ?data-disabled=\"${() => disabled}\"\n @click=\"${() => {\n if (!disabled) commitFromMinute(m);\n }}\"\n @keydown=\"${handleMinuteKeydown}\">\n ${String(m).padStart(2, '0')}\n </div>`;\n })}\n </div>\n </div>\n\n <!-- AM/PM column (12h mode only) -->\n ${() =>\n fmt.value === '12'\n ? html` <div class=\"col col-period\" part=\"column\" role=\"group\" aria-label=\"Period\">\n <div class=\"col-label\" aria-hidden=\"true\">AM/PM</div>\n <div class=\"col-scroll\">\n ${(['AM', 'PM'] as const).map(\n (p) =>\n html`<div\n class=\"option\"\n part=\"option\"\n role=\"option\"\n tabindex=\"${() => (pendingPeriod.value === p ? '0' : '-1')}\"\n :aria-selected=\"${() => String(pendingPeriod.value === p)}\"\n @click=\"${() => {\n pendingPeriod.value = p;\n }}\"\n @keydown=\"${handlePeriodKeydown}\">\n ${p}\n </div>`,\n )}\n </div>\n </div>`\n : html``}\n </div>\n </div>\n `;\n },\n\n shadow: { delegatesFocus: true },\n styles: [colorThemeMixin, reducedMotionMixin, componentStyles],\n});\n","@layer refine.base {\n :host {\n --_bg: var(--box-bg, var(--color-canvas));\n --_color: var(--box-color, var(--color-contrast-900));\n --_border-width: var(--box-border, var(--border));\n --_border-color: var(--box-border-color, var(--color-divider));\n --_radius: var(--box-radius, var(--rounded-lg));\n --_padding: var(--box-padding, var(--size-4));\n --_shadow: var(--box-shadow, var(--shadow-sm));\n\n position: relative;\n display: block;\n }\n\n .box {\n position: relative;\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n padding: var(--_padding);\n color: var(--_color);\n background: var(--_bg);\n border: var(--_border-width) solid var(--_border-color);\n border-radius: var(--_radius);\n box-shadow: var(--_shadow);\n backdrop-filter: blur(var(--blur-md));\n transition:\n backdrop-filter var(--transition-fast),\n box-shadow var(--transition-normal),\n background var(--transition-normal),\n border-color var(--transition-normal);\n }\n}\n\n@layer refine.variants {\n /* Color theme integration — custom props still take priority */\n :host([color]) {\n --_bg: var(--box-bg, var(--_theme-backdrop));\n --_border-color: var(--box-border-color, var(--_theme-border));\n }\n\n /* Flat - border only, no shadow */\n :host([variant='flat']) {\n --_shadow: none;\n }\n\n /* Glass */\n :host([variant='glass']:not([color])) {\n --_bg: color-mix(in oklch, var(--color-secondary) 20%, transparent);\n --_border-color: color-mix(in oklch, var(--color-secondary-contrast) 15%, transparent);\n }\n\n :host([variant='glass'][color]) {\n --_bg: color-mix(in oklch, var(--_theme-base) 20%, transparent);\n --_border-color: color-mix(in oklch, var(--_theme-contrast) 15%, transparent);\n --_color: var(--_theme-content);\n }\n\n :host([variant='glass']) .box {\n box-shadow: var(--shadow-md), var(--inset-shadow-xs);\n backdrop-filter: blur(var(--blur-lg)) saturate(180%) brightness(1.05);\n }\n\n /* Subtle hover for solid/default + color (glass & frost manage their own hover) */\n :host([color]:not([variant='glass'], [variant='frost']):hover) {\n --_bg: color-mix(in oklch, var(--_theme-base) 16%, var(--color-contrast-50));\n --_border-color: var(--_theme-focus);\n }\n}\n\n@layer refine.utilities {\n :host([fullwidth]) {\n width: 100%;\n }\n}\n","import { define, html, prop } from '@vielzeug/ore';\n\nimport type { ElevationLevel, PaddingSize, RoundedSize, ThemeColor } from '../../types';\n\nimport { frostVariantMixin, rainbowEffectMixin, surfaceMixins } from '../../styles';\nimport componentStyles from './box.css?inline';\n\n/** Box component properties */\nexport type OreBoxProps = {\n /** Theme color */\n color?: ThemeColor;\n /** Animated border effect */\n effect?: 'rainbow';\n /** Shadow elevation level (0–5) */\n elevation?: ElevationLevel;\n /** Full width mode (100% of container) */\n fullwidth?: boolean;\n /** Internal padding size */\n padding?: PaddingSize;\n /** Border radius size */\n rounded?: RoundedSize;\n /** Visual style variant */\n variant?: 'solid' | 'flat' | 'glass' | 'frost';\n};\n\n/**\n * ore-box — A foundational layout primitive with theming support.\n *\n * @element ore-box\n *\n * @attr {string} variant - Style variant: 'solid' | 'flat' | 'glass' | 'frost'\n * @attr {string} color - Color theme: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} padding - Padding size: 'none' | 'sm' | 'md' | 'lg' | 'xl'\n * @attr {string} elevation - Shadow elevation: '0' | '1' | '2' | '3' | '4' | '5'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n * @attr {string} effect - Animated border effect: 'rainbow'\n * @attr {boolean} fullwidth - Expand to full width\n *\n * @slot - Default slot for content\n *\n * @part box - The inner box element\n *\n * @cssprop --box-bg - Background color\n * @cssprop --box-color - Text color\n * @cssprop --box-border - Border width\n * @cssprop --box-border-color - Border color\n * @cssprop --box-radius - Border radius\n * @cssprop --box-padding - Inner padding\n * @cssprop --box-shadow - Box shadow\n *\n * @example\n * ```html\n * <ore-box padding=\"lg\" elevation=\"2\">Simple content</ore-box>\n * <ore-box variant=\"glass\" color=\"primary\">Glass effect</ore-box>\n * <ore-box variant=\"frost\" effect=\"rainbow\">Frosted glass</ore-box>\n * ```\n */\nexport const BOX_TAG = 'ore-box' as const;\ndefine<OreBoxProps>(BOX_TAG, {\n props: {\n color: prop.string<ThemeColor>(),\n effect: prop.string<'rainbow'>(),\n elevation: prop.number<ElevationLevel>(),\n fullwidth: prop.bool(),\n padding: prop.string<PaddingSize>(),\n rounded: prop.string<RoundedSize>(),\n variant: prop.string<'flat' | 'solid' | 'frost' | 'glass'>(),\n },\n setup() {\n return html`<div class=\"box\" part=\"box\"><slot></slot></div>`;\n },\n\n styles: [...surfaceMixins, frostVariantMixin('.box'), rainbowEffectMixin('.box'), componentStyles],\n});\n","@layer refine.base {\n :host {\n display: block;\n }\n}\n\n@layer refine.utilities {\n :host([align='start']) {\n align-self: start;\n }\n\n :host([align='center']) {\n align-self: center;\n }\n\n :host([align='end']) {\n align-self: end;\n }\n\n :host([align='stretch']) {\n align-self: stretch;\n }\n\n :host([justify='start']) {\n justify-self: start;\n }\n\n :host([justify='center']) {\n justify-self: center;\n }\n\n :host([justify='end']) {\n justify-self: end;\n }\n\n :host([justify='stretch']) {\n justify-self: stretch;\n }\n}\n","import { define, html, prop } from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\n\nimport styles from './grid-item.css?inline';\n\n/** Grid item component properties */\nexport type OreGridItemProps = {\n /** Align self vertically within the grid cell */\n align?: 'start' | 'center' | 'end' | 'stretch';\n /** Named grid area to place the item into. */\n area?: string;\n /** Explicit grid-column value — overrides col-span (e.g. '2 / 5', 'span 3', '1 / -1'). */\n col?: string;\n /** Span N columns. Use 'full' to span all columns (1 / -1). */\n colSpan?: '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11' | '12' | 'full';\n /** Justify self horizontally within the grid cell */\n justify?: 'start' | 'center' | 'end' | 'stretch';\n /** Explicit grid-row value — overrides row-span (e.g. '1 / 3', 'span 2'). */\n row?: string;\n /** Span N rows. Use 'full' to span all rows (1 / -1). */\n rowSpan?: '1' | '2' | '3' | '4' | '5' | '6' | 'full';\n};\n\n/**\n * ore-grid-item — A grid cell with declarative placement and span control.\n *\n * Use `col-span` / `row-span` for the common case of spanning columns/rows.\n * Use `col` / `row` for full CSS grid-column / grid-row shorthand power\n * (e.g. explicit placement, mixed span + start, negative lines).\n *\n * @element ore-grid-item\n *\n * @attr {string} area - CSS grid-area value for named-area placement\n * @attr {string} col-span - Columns to span: '1'–'12' | 'full'\n * @attr {string} row-span - Rows to span: '1'–'6' | 'full'\n * @attr {string} col - CSS grid-column value (overrides col-span)\n * @attr {string} row - CSS grid-row value (overrides row-span)\n * @attr {string} align - align-self: 'start' | 'center' | 'end' | 'stretch'\n * @attr {string} justify - justify-self: 'start' | 'center' | 'end' | 'stretch'\n *\n * @slot - Grid item content\n *\n * @example\n * <!-- Span 2 columns -->\n * <ore-grid-item col-span=\"2\">Wide</ore-grid-item>\n *\n * @example\n * <!-- Full-width row -->\n * <ore-grid-item col-span=\"full\">Banner</ore-grid-item>\n *\n * @example\n * <!-- Named area placement -->\n * <ore-grid-item area=\"sidebar\">Nav</ore-grid-item>\n *\n * @example\n * <!-- Explicit placement -->\n * <ore-grid-item col=\"2 / 5\" row=\"1 / 3\">Placed</ore-grid-item>\n */\nexport const GRID_ITEM_TAG = 'ore-grid-item' as const;\ndefine<OreGridItemProps>(GRID_ITEM_TAG, {\n props: {\n align: prop.string<'start' | 'center' | 'end' | 'stretch'>(),\n area: prop.string(),\n col: prop.string(),\n colSpan: prop.string<'1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11' | '12' | 'full'>(),\n justify: prop.string<'start' | 'center' | 'end' | 'stretch'>(),\n row: prop.string(),\n rowSpan: prop.string<'1' | '2' | '3' | '4' | '5' | '6' | 'full'>(),\n },\n setup(props, { bind, el: _el }) {\n const gridColumn = computed(() => {\n const col = props.col.value;\n const span = props.colSpan.value;\n\n if (col) return col;\n\n if (span === 'full') return '1 / -1';\n\n if (span) return `span ${span}`;\n\n return '';\n });\n\n const gridRow = computed(() => {\n const row = props.row.value;\n const span = props.rowSpan.value;\n\n if (row) return row;\n\n if (span === 'full') return '1 / -1';\n\n if (span) return `span ${span}`;\n\n return '';\n });\n\n bind({\n style: {\n gridArea: props.area,\n gridColumn,\n gridRow,\n },\n });\n\n return html`<slot></slot>`;\n },\n styles: [styles],\n});\n","@layer refine.base {\n :host {\n --_cols: var(--grid-cols, repeat(auto-fit, minmax(250px, 1fr)));\n --_rows: var(--grid-rows, auto);\n --_gap: var(--grid-gap, var(--size-4));\n --_row-gap: var(--grid-row-gap, var(--_gap));\n --_col-gap: var(--grid-col-gap, var(--_gap));\n\n display: grid;\n grid-template-rows: var(--_rows);\n grid-template-columns: var(--_cols);\n grid-auto-flow: row;\n gap: var(--_row-gap) var(--_col-gap);\n }\n\n :host([gap='none']) {\n --_row-gap: 0;\n --_col-gap: 0;\n }\n\n :host([gap='xs']) {\n --_row-gap: var(--size-1);\n --_col-gap: var(--size-1);\n }\n\n :host([gap='sm']) {\n --_row-gap: var(--size-2);\n --_col-gap: var(--size-2);\n }\n\n :host([gap='md']) {\n --_row-gap: var(--size-4);\n --_col-gap: var(--size-4);\n }\n\n :host([gap='lg']) {\n --_row-gap: var(--size-6);\n --_col-gap: var(--size-6);\n }\n\n :host([gap='xl']) {\n --_row-gap: var(--size-8);\n --_col-gap: var(--size-8);\n }\n\n :host([gap='2xl']) {\n --_row-gap: var(--size-12);\n --_col-gap: var(--size-12);\n }\n\n :host([align='start']) {\n align-items: start;\n }\n\n :host([align='center']) {\n align-items: center;\n }\n\n :host([align='end']) {\n align-items: end;\n }\n\n :host([align='stretch']) {\n align-items: stretch;\n }\n\n :host([align='baseline']) {\n align-items: baseline;\n }\n\n :host([justify='start']) {\n justify-items: start;\n }\n\n :host([justify='center']) {\n justify-items: center;\n }\n\n :host([justify='end']) {\n justify-items: end;\n }\n\n :host([justify='stretch']) {\n justify-items: stretch;\n }\n\n :host([flow='row']) {\n grid-auto-flow: row;\n }\n\n :host([flow='column']) {\n grid-auto-flow: column;\n }\n\n :host([flow='row-dense']) {\n grid-auto-flow: row dense;\n }\n\n :host([flow='column-dense']) {\n grid-auto-flow: column dense;\n }\n\n :host([fullwidth]) {\n width: 100%;\n }\n}\n","import { define, html, prop } from '@vielzeug/ore';\nimport { resizeObserver } from '@vielzeug/ore/observers';\n\nimport styles from './grid.css?inline';\n\nconst BREAKPOINTS: ['cols2xl' | 'colsXl' | 'colsLg' | 'colsMd' | 'colsSm', string][] = [\n ['cols2xl', '--size-screen-2xl'],\n ['colsXl', '--size-screen-xl'],\n ['colsLg', '--size-screen-lg'],\n ['colsMd', '--size-screen-md'],\n ['colsSm', '--size-screen-sm'],\n];\n\nconst AREAS_BREAKPOINTS: ['areas2xl' | 'areasXl' | 'areasLg' | 'areasMd' | 'areasSm', string][] = [\n ['areas2xl', '--size-screen-2xl'],\n ['areasXl', '--size-screen-xl'],\n ['areasLg', '--size-screen-lg'],\n ['areasMd', '--size-screen-md'],\n ['areasSm', '--size-screen-sm'],\n];\n\nconst resolveBp = (host: HTMLElement, varName: string, fallback: number): number => {\n const raw = getComputedStyle(host).getPropertyValue(varName).trim();\n const parsed = Number.parseFloat(raw);\n\n return Number.isFinite(parsed) ? parsed : fallback;\n};\n\nconst BP_FALLBACKS: Record<string, number> = {\n '--size-screen-2xl': 1536,\n '--size-screen-lg': 1024,\n '--size-screen-md': 768,\n '--size-screen-sm': 640,\n '--size-screen-xl': 1280,\n};\n\ntype ColCount = '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11' | '12' | 'auto';\n\n/** Grid component properties */\nexport type OreGridProps = {\n /** Align items vertically */\n align?: 'start' | 'center' | 'end' | 'stretch' | 'baseline';\n /** CSS grid-template-areas value */\n areas?: string;\n /** grid-template-areas at 2xl breakpoint (≥1536px) */\n areas2xl?: string;\n /** grid-template-areas at lg breakpoint (≥1024px) */\n areasLg?: string;\n /** grid-template-areas at md breakpoint (≥768px) */\n areasMd?: string;\n /** grid-template-areas at sm breakpoint (≥640px) */\n areasSm?: string;\n /** grid-template-areas at xl breakpoint (≥1280px) */\n areasXl?: string;\n /** Number of columns: '1'-'12' | 'auto' */\n cols?: ColCount;\n /** Columns at 2xl breakpoint (≥1536px) */\n cols2xl?: ColCount;\n /** Columns at lg breakpoint (≥1024px) */\n colsLg?: ColCount;\n /** Columns at md breakpoint (≥768px) */\n colsMd?: ColCount;\n /** Columns at sm breakpoint (≥640px) */\n colsSm?: ColCount;\n /** Columns at xl breakpoint (≥1280px) */\n colsXl?: ColCount;\n /** Grid auto flow direction */\n flow?: 'row' | 'column' | 'row-dense' | 'column-dense';\n /** Stretch the grid to fill its container's full width */\n fullwidth?: boolean;\n /** Gap between items */\n gap?: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n /** Justify items horizontally */\n justify?: 'start' | 'center' | 'end' | 'stretch';\n /** Minimum column width for responsive mode (default: 250px) */\n minColWidth?: string;\n /** Use auto-fit responsive columns */\n responsive?: boolean;\n /** Number of rows: '1'-'12' | 'auto' */\n rows?: '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11' | '12' | 'auto';\n};\n\n/**\n * ore-grid — Flexible grid layout with responsive column control.\n *\n * Columns are computed in JS and applied as `--_cols` inline, so they respond\n * to the element's own width via ResizeObserver. CSS custom properties\n * `--grid-cols`, `--grid-rows`, `--grid-gap`, `--grid-row-gap`, `--grid-col-gap`\n * are honoured as fallbacks when no attribute is set.\n *\n * @element ore-grid\n *\n * @attr {string} cols - Column count: '1'–'12' | 'auto'\n * @attr {string} cols-sm - Columns when width ≥ 640px\n * @attr {string} cols-md - Columns when width ≥ 768px\n * @attr {string} cols-lg - Columns when width ≥ 1024px\n * @attr {string} cols-xl - Columns when width ≥ 1280px\n * @attr {string} cols-2xl - Columns when width ≥ 1536px\n * @attr {string} rows - Row count: '1'–'12' | 'auto'\n * @attr {string} gap - Gap token: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'\n * @attr {string} align - align-items: 'start' | 'center' | 'end' | 'stretch' | 'baseline'\n * @attr {string} justify - justify-items: 'start' | 'center' | 'end' | 'stretch'\n * @attr {string} flow - grid-auto-flow: 'row' | 'column' | 'row-dense' | 'column-dense'\n * @attr {boolean} responsive - Enables auto-fit columns without a fixed count\n * @attr {string} min-col-width - Min column width for responsive mode (default: 250px)\n * @attr {boolean} fullwidth - Stretch the grid to fill its container's full width\n * @attr {string} areas - CSS grid-template-areas value (e.g. \"'header header' 'nav main'\")\n * @attr {string} areas-sm - grid-template-areas when width ≥ 640px\n * @attr {string} areas-md - grid-template-areas when width ≥ 768px\n * @attr {string} areas-lg - grid-template-areas when width ≥ 1024px\n * @attr {string} areas-xl - grid-template-areas when width ≥ 1280px\n * @attr {string} areas-2xl - grid-template-areas when width ≥ 1536px\n *\n * @slot - Grid items\n *\n * @cssprop --grid-cols - Fallback column template (used when no cols attr is set)\n * @cssprop --grid-rows - Fallback row template\n * @cssprop --grid-gap - Fallback gap\n * @cssprop --grid-row-gap - Fallback row gap\n * @cssprop --grid-col-gap - Fallback column gap\n *\n * @example\n * <ore-grid cols=\"1\" cols-sm=\"2\" cols-lg=\"4\" gap=\"md\">\n * <div>Item</div>\n * </ore-grid>\n *\n * @example\n * <!-- Responsive auto-fit -->\n * <ore-grid responsive min-col-width=\"200px\" gap=\"sm\">\n * <div>Card</div>\n * </ore-grid>\n *\n * @example\n * <!-- Named grid areas -->\n * <ore-grid cols=\"2\" rows=\"2\" areas=\"'header header' 'nav main'\">\n * <header style=\"grid-area: header\">Header</header>\n * <nav style=\"grid-area: nav\">Nav</nav>\n * <main style=\"grid-area: main\">Main</main>\n * </ore-grid>\n */\nexport const GRID_TAG = 'ore-grid' as const;\ndefine<OreGridProps>(GRID_TAG, {\n props: {\n align: prop.string<'start' | 'center' | 'end' | 'stretch' | 'baseline'>(),\n areas: prop.string(),\n areas2xl: prop.string(),\n areasLg: prop.string(),\n areasMd: prop.string(),\n areasSm: prop.string(),\n areasXl: prop.string(),\n cols: prop.string<ColCount>(),\n cols2xl: prop.string<ColCount>(),\n colsLg: prop.string<ColCount>(),\n colsMd: prop.string<ColCount>(),\n colsSm: prop.string<ColCount>(),\n colsXl: prop.string<ColCount>(),\n flow: prop.string<'row' | 'column' | 'row-dense' | 'column-dense'>(),\n fullwidth: prop.bool(false),\n gap: prop.string<'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'>(),\n justify: prop.string<'start' | 'center' | 'end' | 'stretch'>(),\n minColWidth: prop.string(),\n responsive: prop.bool(false),\n rows: prop.string<'1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11' | '12' | 'auto'>(),\n },\n\n setup(props, { el, onMounted, watch }) {\n const computeCols = (activeCols: string | undefined, responsive: boolean, minW: string): string | null => {\n if (activeCols === 'auto' || (!activeCols && responsive)) {\n return `repeat(auto-fit, minmax(${minW || '250px'}, 1fr))`;\n }\n\n return activeCols ? `repeat(${activeCols}, 1fr)` : null;\n };\n const updateCols = () => {\n const w = el.offsetWidth;\n const responsive = Boolean(props.responsive.value);\n const minW = props.minColWidth.value ?? '';\n let activeCols: string | undefined;\n\n for (const [key, cssVar] of BREAKPOINTS) {\n if (w >= resolveBp(el, cssVar, BP_FALLBACKS[cssVar]) && props[key].value) {\n activeCols = props[key].value!;\n break;\n }\n }\n activeCols ||= props.cols.value || undefined;\n\n const colsValue = computeCols(activeCols, responsive, minW);\n\n if (colsValue) {\n el.style.setProperty('--_cols', colsValue);\n } else {\n el.style.removeProperty('--_cols');\n }\n };\n\n // Re-run cols whenever any responsive prop changes\n watch(() => {\n void [\n props.cols.value,\n props.colsSm.value,\n props.colsMd.value,\n props.colsLg.value,\n props.colsXl.value,\n props.cols2xl.value,\n props.responsive.value,\n props.minColWidth.value,\n ];\n updateCols();\n });\n\n const updateAreas = () => {\n const w = el.offsetWidth;\n let active = '';\n\n for (const [key, cssVar] of AREAS_BREAKPOINTS) {\n if (w >= resolveBp(el, cssVar, BP_FALLBACKS[cssVar]) && props[key].value) {\n active = props[key].value!;\n break;\n }\n }\n active ||= props.areas.value || '';\n\n if (active) {\n el.style.setProperty('grid-template-areas', active);\n } else {\n el.style.removeProperty('grid-template-areas');\n }\n };\n\n // Rows\n watch(() => {\n const rows = props.rows.value;\n\n if (rows && rows !== 'auto') {\n el.style.setProperty('--_rows', `repeat(${rows}, 1fr)`);\n } else {\n el.style.removeProperty('--_rows');\n }\n });\n // Grid template areas (responsive)\n watch(() => {\n void [\n props.areas.value,\n props.areasSm.value,\n props.areasMd.value,\n props.areasLg.value,\n props.areasXl.value,\n props.areas2xl.value,\n ];\n updateAreas();\n });\n\n // Also, update on element resize (drives breakpoint switching)\n onMounted(() => {\n const size = resizeObserver(el);\n\n watch(() => {\n void size.value;\n updateCols();\n updateAreas();\n });\n });\n\n return html`<slot></slot>`;\n },\n\n styles: [styles],\n});\n","@layer refine.base {\n :host {\n --_navbar-height: var(--navbar-height, var(--size-14));\n --_navbar-width: var(--navbar-width, min(100%, 80rem));\n --_navbar-offset: var(--navbar-offset, var(--size-3));\n --_navbar-bg: var(--navbar-bg, var(--color-canvas));\n --_navbar-color: var(--navbar-color, var(--color-contrast-900));\n --_navbar-border-color: var(--navbar-border-color, var(--color-divider));\n --_navbar-shadow: var(--navbar-shadow, var(--shadow-md));\n --_navbar-radius: var(--navbar-radius, var(--rounded-lg));\n\n box-sizing: border-box;\n display: block;\n width: 100%;\n color: var(--_navbar-color);\n }\n\n :host([data-mode='sticky']) {\n position: sticky;\n top: 0;\n z-index: var(--z-sticky, 40);\n }\n\n :host([data-mode='floating']) {\n position: fixed;\n inset-inline: var(--_navbar-offset);\n top: var(--_navbar-offset);\n z-index: var(--z-sticky, 40);\n }\n\n /* Preview mode: use absolute positioning so component stays within container bounds */\n :host([data-preview-mode][data-mode='floating']) {\n position: absolute;\n inset-inline: var(--_navbar-offset);\n top: auto;\n }\n\n :host([floating][sticky][data-scrolled]) {\n inset-inline: 0;\n top: 0;\n width: 100%;\n }\n\n :host([data-preview-mode][floating][sticky][data-scrolled]) {\n position: absolute;\n inset-inline: 0;\n top: auto;\n width: auto;\n }\n\n :host > nav {\n position: relative;\n display: flex;\n flex-direction: column;\n width: 100%;\n }\n\n .navbar {\n box-sizing: border-box;\n display: flex;\n flex-wrap: nowrap;\n gap: var(--size-2);\n align-items: center;\n width: 100%;\n max-width: var(--_navbar-width);\n min-height: var(--_navbar-height);\n padding: var(--size-2) var(--size-4);\n margin-inline: auto;\n overflow: auto hidden;\n color: inherit;\n white-space: nowrap;\n background: var(--_navbar-bg);\n border-top: none;\n border-right: none;\n border-bottom: var(--border) solid var(--_navbar-border-color);\n border-left: none;\n border-radius: 0;\n backdrop-filter: var(--navbar-backdrop-filter, blur(var(--blur-md)));\n transition: var(\n --_motion-transition,\n background var(--transition-normal),\n border-color var(--transition-normal),\n box-shadow var(--transition-normal),\n transform var(--transition-normal)\n );\n }\n\n :host([data-mode='floating']) .navbar {\n border-top: var(--border) solid var(--_navbar-border-color);\n border-right: var(--border) solid var(--_navbar-border-color);\n border-bottom: var(--border) solid var(--_navbar-border-color);\n border-left: var(--border) solid var(--_navbar-border-color);\n border-radius: var(--_navbar-radius);\n }\n\n :host([data-mode='sticky']) .navbar,\n :host([floating][sticky][data-scrolled]) .navbar {\n max-width: 100%;\n border-inline: none;\n border-radius: 0;\n }\n\n :host([data-mode-transitioning][data-mode='sticky']) .navbar {\n animation: navbar-floating-to-sticky var(--transition-normal) var(--ease-in-out);\n }\n\n :host([data-mode-transitioning][data-mode='floating']) .navbar {\n animation: navbar-sticky-to-floating var(--transition-normal) var(--ease-in-out);\n }\n\n .navbar-logo,\n .navbar-start,\n .navbar-center,\n .navbar-end {\n display: flex;\n align-items: center;\n min-width: 0;\n white-space: nowrap;\n }\n\n .navbar-logo {\n flex: 0 0 auto;\n }\n\n .navbar-start {\n flex: 0 0 auto;\n gap: var(--size-1);\n }\n\n .navbar-center {\n display: flex;\n flex: 0 1 auto;\n gap: var(--size-1);\n justify-content: flex-start;\n min-width: 0;\n }\n\n .navbar-end {\n flex: 0 0 auto;\n gap: var(--size-1);\n margin-inline-start: auto;\n }\n\n .mobile-toggle {\n display: none;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n width: var(--size-9);\n height: var(--size-9);\n padding: 0;\n color: var(--color-contrast-700);\n cursor: pointer;\n background: transparent;\n border: var(--border) solid transparent;\n border-radius: var(--rounded-md);\n transition:\n background var(--transition-fast),\n border-color var(--transition-fast),\n color var(--transition-fast);\n }\n\n .mobile-toggle:hover {\n color: var(--color-contrast-900);\n background: var(--color-contrast-100);\n border-color: var(--color-contrast-200);\n }\n\n .mobile-toggle:focus-visible {\n outline: var(--focus-ring);\n }\n\n .mobile-menu-panel {\n position: relative;\n z-index: 1;\n box-sizing: border-box;\n display: none;\n width: 100%;\n max-width: var(--_navbar-width);\n padding: var(--size-2);\n margin-block-start: var(--size-2);\n margin-inline: auto;\n background: var(--_navbar-bg);\n border: var(--border) solid var(--_navbar-border-color);\n border-radius: var(--rounded-lg);\n box-shadow: var(--_shadow, var(--_navbar-shadow));\n backdrop-filter: var(--navbar-backdrop-filter, blur(var(--blur-md)));\n transform-origin: top;\n animation: navbar-mobile-in var(--transition-fast) var(--ease-out);\n }\n\n :host([data-mobile][data-mobile-open]) .mobile-menu-panel {\n display: grid;\n gap: var(--size-1);\n }\n\n :host([data-mobile][data-mobile-open][data-mode='floating']) .mobile-menu-panel {\n margin-block-start: var(--size-1-5);\n }\n\n :host([data-mobile][data-mobile-open][data-mode='sticky']) .mobile-menu-panel,\n :host([data-mobile][data-mobile-open][floating][sticky][data-scrolled]) .mobile-menu-panel {\n position: absolute;\n inset-inline: 0;\n top: 100%;\n z-index: 2;\n max-width: 100%;\n margin: 0;\n border-inline: none;\n border-top: none;\n border-radius: 0 0 var(--rounded-md) var(--rounded-md);\n }\n\n :host([data-mobile]) .mobile-toggle {\n display: inline-flex;\n order: -1;\n }\n\n :host([data-mobile]) .navbar-start,\n :host([data-mobile]) .navbar-center,\n :host([data-mobile]) .navbar-end {\n display: none;\n }\n\n :host([data-mobile][data-mobile-open]) .navbar {\n border-bottom-right-radius: var(--rounded-md);\n border-bottom-left-radius: var(--rounded-md);\n }\n\n @starting-style {\n .mobile-menu-panel {\n opacity: 0;\n transform: translateY(var(--overlay-enter-translate-y));\n }\n }\n\n @keyframes navbar-mobile-in {\n from {\n opacity: 0;\n transform: translateY(var(--overlay-enter-translate-y));\n }\n\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n\n @keyframes navbar-floating-to-sticky {\n from {\n opacity: 0.92;\n transform: translateY(6px) scale(0.985);\n }\n\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n }\n\n @keyframes navbar-sticky-to-floating {\n from {\n opacity: 0.95;\n transform: translateY(-2px) scale(1);\n }\n\n to {\n opacity: 1;\n transform: translateY(0) scale(0.99);\n }\n }\n\n .item {\n box-sizing: border-box;\n display: inline-flex;\n flex-shrink: 0;\n gap: var(--size-1);\n align-items: center;\n min-height: var(--_touch-target);\n padding: var(--size-1-5) var(--size-2-5);\n font-size: var(--text-sm);\n font-weight: var(--font-medium);\n color: var(--navbar-item-color, var(--color-contrast-700));\n white-space: nowrap;\n text-decoration: none;\n cursor: pointer;\n border-radius: var(--rounded-md);\n transition:\n background var(--transition-fast),\n color var(--transition-fast);\n }\n\n .item:hover,\n .item:focus-visible {\n color: var(--navbar-item-hover-color, var(--color-contrast-900));\n outline: var(--focus-ring);\n outline-offset: 1px;\n background: var(--navbar-item-hover-bg, var(--color-contrast-100));\n }\n\n :host([active]) .item {\n color: var(--navbar-item-active-color, var(--color-primary));\n background: var(--navbar-item-active-bg, color-mix(in oklch, var(--color-primary) 12%, transparent));\n }\n\n :host([disabled]) .item,\n :host([disabled]) .item:hover,\n :host([disabled]) .item:focus-visible {\n color: var(--color-contrast-400);\n pointer-events: none;\n cursor: not-allowed;\n outline: none;\n background: transparent;\n }\n\n .item-icon,\n .item-end {\n display: inline-flex;\n align-items: center;\n }\n\n .item-label {\n min-width: 0;\n white-space: nowrap;\n }\n\n :host([navbar-mobile]) {\n display: block;\n width: 100%;\n }\n\n :host([navbar-mobile]) .item {\n display: flex;\n justify-content: flex-start;\n width: 100%;\n }\n}\n\n@layer refine.variants {\n :host([variant='flat']) {\n --_navbar-bg: color-mix(in oklch, var(--color-canvas) 88%, transparent);\n --_navbar-shadow: none;\n }\n\n :host([variant='bordered']) {\n --_navbar-bg: var(--color-canvas);\n --_navbar-border-color: color-mix(in oklch, var(--color-contrast-500) 32%, transparent);\n }\n\n :host([variant='outline']) {\n --_navbar-bg: transparent;\n --_navbar-shadow: none;\n --_navbar-border-color: color-mix(in oklch, var(--color-contrast-500) 40%, transparent);\n }\n\n :host([variant='glass']) {\n --_navbar-bg: color-mix(in oklch, var(--color-canvas) 70%, transparent);\n --navbar-backdrop-filter: blur(var(--blur-lg)) saturate(180%);\n }\n\n :host([color]) {\n --_navbar-border-color: color-mix(in oklch, var(--_theme-border) 30%, transparent);\n }\n}\n\n@media (width <= 768px) {\n @layer refine.base {\n :host([data-mode='floating']) {\n inset-inline: var(--size-2);\n top: var(--size-2);\n }\n\n :host([floating][sticky][data-scrolled]) {\n inset-inline: 0;\n top: 0;\n }\n }\n}\n","import { createContext, define, html, inject, prop } from '@vielzeug/ore';\nimport { resizeObserver } from '@vielzeug/ore/observers';\nimport { computed, type Readable, signal, watch } from '@vielzeug/ripple';\n\nimport type { ElevationLevel, RoundedSize, ThemeColor, VisualVariant } from '../../types';\n\nimport '../../content/icon/icon';\nimport {\n coarsePointerMixin,\n colorThemeMixin,\n elevationMixin,\n frostVariantMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n} from '../../styles';\nimport { computeSafeRel } from '../../utils';\nimport navbarStyles from './navbar.css?inline';\n\nconst listen = <E extends Event = Event>(\n el: EventTarget | null | undefined,\n name: string,\n handler: (e: E) => void,\n options?: AddEventListenerOptions,\n): (() => void) => {\n if (!el) return () => {};\n\n el.addEventListener(name, handler as EventListener, options);\n\n return () => el.removeEventListener(name, handler as EventListener, options);\n};\n\ntype NavbarMode = 'floating' | 'sticky';\n\nconst hasElementContent = (el: Element): boolean => {\n if (!(el instanceof HTMLElement)) return true;\n\n if (el.tagName.includes('-')) return true;\n\n if (el.childElementCount > 0) return true;\n\n return (el.textContent ?? '').trim().length > 0;\n};\n\nconst parseMaxWidthPx = (query: string | undefined): number | undefined => {\n const value = String(query ?? '').trim();\n\n if (!value) return undefined;\n\n const match = /max-width\\s*:\\s*([0-9]+(?:\\.[0-9]+)?)px/i.exec(value);\n\n if (!match) return undefined;\n\n const parsed = Number.parseFloat(match[1]);\n\n return Number.isFinite(parsed) ? parsed : undefined;\n};\n\nconst resolveContainerElement = (el: HTMLElement): HTMLElement | null => {\n let container = el.parentElement;\n\n while (container?.tagName.toLowerCase() === 'ore-grid-item') {\n container = container.parentElement;\n }\n\n return container;\n};\n\nconst readContainerWidth = (el: HTMLElement): number => {\n const parentWidth = resolveContainerElement(el)?.clientWidth ?? 0;\n\n if (parentWidth > 0) return parentWidth;\n\n return el.offsetWidth;\n};\n\nconst findScrollContainer = (start: HTMLElement): HTMLElement | null => {\n let current: HTMLElement | null = start.parentElement;\n\n while (current) {\n const styles = window.getComputedStyle(current);\n const overflowY = styles.overflowY;\n\n if (overflowY === 'auto' || overflowY === 'scroll' || overflowY === 'overlay') {\n return current;\n }\n\n current = current.parentElement;\n }\n\n return null;\n};\n\n/** Context provided by `ore-navbar` to `ore-navbar-item` children. */\nexport type NavbarContext = {\n isMobile: Readable<boolean>;\n mobileMenuOpen: Readable<boolean>;\n};\n\n/** Injection key for navbar context. */\nexport const NAVBAR_CTX = createContext<NavbarContext>('NavbarContext');\n\n/** Navbar component events */\nexport type OreNavbarEvents = {\n 'mobile-menu-change': { open: boolean };\n};\n\n/** Navbar component element interface */\nexport type NavbarElement = HTMLElement &\n OreNavbarProps & {\n closeMobileMenu(): void;\n openMobileMenu(): void;\n toggleMobileMenu(): void;\n };\n\ntype MobileSidebarElement = HTMLElement & {\n closeMobile?: () => void;\n openMobile?: () => void;\n toggleMobile?: () => void;\n};\n\n/** Navbar component properties */\nexport type OreNavbarProps = {\n /** CSS media query used for mobile layout switching */\n breakpoint?: string;\n /** Theme color */\n color?: ThemeColor;\n /** Evaluate mobile breakpoint against container width only when possible. */\n 'container-breakpoints'?: boolean;\n /** Shadow elevation level (0-5) */\n elevation?: ElevationLevel;\n /** Start as detached floating navbar */\n floating?: boolean;\n /** Accessible nav landmark label */\n label?: string;\n /** CSS selector for an external sidebar toggled by the mobile button */\n 'mobile-sidebar'?: string;\n /** Border radius size */\n rounded?: RoundedSize;\n /** Scroll threshold in px used by floating+sticky transition */\n 'scroll-threshold'?: number;\n /** Stick to top of viewport */\n sticky?: boolean;\n /** Visual style variant */\n variant?: Exclude<VisualVariant, 'ghost' | 'text'>;\n};\n\n/** Navbar item properties */\nexport type OreNavbarItemProps = {\n /** Whether this item represents the current page */\n active?: boolean;\n /** Whether this item is disabled */\n disabled?: boolean;\n /** Link target URL. Renders an anchor when provided. */\n href?: string;\n /** Relationship of linked URL (anchor-only) */\n rel?: string;\n /** Browsing context for link (anchor-only) */\n target?: string;\n};\n\n/**\n * `ore-navbar` — Responsive navigation with sticky/floating modes and a mobile overflow panel.\n *\n * @element ore-navbar\n * @element ore-navbar-item - Navigation link or button placed in the default or mobile-menu slot\n *\n * @attr {string} label - Accessible nav landmark label\n * @attr {boolean} sticky - Makes navbar sticky at top\n * @attr {boolean} floating - Makes navbar detached and floating\n * @attr {number} scroll-threshold - Scroll threshold for floating+sticky transition\n * @attr {string} breakpoint - CSS media query used for mobile mode\n * @attr {boolean} container-breakpoints - Evaluates parseable max-width breakpoints against container width\n * @attr {string} variant - Visual variant: 'flat' | 'solid' | 'bordered' | 'outline' | 'frost' | 'glass'\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n * @attr {string} elevation - Shadow elevation: '0' | '1' | '2' | '3' | '4' | '5'\n *\n * @fires mobile-menu-change - Emitted when mobile menu open state changes. detail: { open: boolean }\n *\n * @slot logo - Brand/logo content rendered at the leading edge\n * @slot start - Content rendered in the left/start region\n * @slot - Center navigation content rendered between the start and end regions\n * @slot end - Content rendered in the right/end region\n * @slot mobile-menu - Controls and links rendered inside the mobile overflow panel\n *\n * @cssprop --navbar-height - Navbar bar height\n * @cssprop --navbar-width - Max width of the navbar content\n * @cssprop --navbar-offset - Horizontal offset for floating/sticky positioning\n * @cssprop --navbar-bg - Navbar background color\n * @cssprop --navbar-color - Navbar text color\n * @cssprop --navbar-border-color - Navbar border color\n * @cssprop --navbar-shadow - Navbar box shadow\n * @cssprop --navbar-radius - Border radius (floating/sticky modes)\n * @cssprop --navbar-backdrop-filter - Backdrop filter for blur effect\n * @cssprop --navbar-item-color - Nav item text color\n * @cssprop --navbar-item-hover-color - Nav item hover text color\n * @cssprop --navbar-item-hover-bg - Nav item hover background\n * @cssprop --navbar-item-active-color - Nav item active/current text color\n * @cssprop --navbar-item-active-bg - Nav item active/current background\n * @part nav - Outer navigation landmark\n * @part bar - Main navbar row container\n * @part logo - Logo slot container\n * @part start - Leading action/content region\n * @part center - Center content region\n * @part end - Trailing action/content region\n * @part mobile-toggle - Mobile menu toggle button\n * @part mobile-menu - Mobile overflow panel\n * @part item-icon - Leading icon inside navbar items\n * @part item-label - Label text inside navbar items\n * @part item-end - Trailing content inside navbar items\n * @part item - Clickable navbar item root\n * @example\n * ```html\n * <ore-navbar sticky elevation=\"1\">\n * <a href=\"/\" slot=\"logo\"><strong>MyApp</strong></a>\n * <ore-navbar-item href=\"/dashboard\">Dashboard</ore-navbar-item>\n * <ore-navbar-item href=\"/docs\">Docs</ore-navbar-item>\n * <ore-button slot=\"end\" variant=\"solid\" color=\"primary\" size=\"sm\">Sign in</ore-button>\n * </ore-navbar>\n * ```\n */\nexport const NAVBAR_TAG = 'ore-navbar' as const;\ndefine<OreNavbarProps, OreNavbarEvents>(NAVBAR_TAG, {\n props: {\n breakpoint: prop.string('(max-width: 768px)'),\n color: prop.string<ThemeColor>(),\n 'container-breakpoints': prop.bool(false),\n elevation: prop.number<ElevationLevel>(),\n floating: prop.bool(false),\n label: prop.string('Main navigation'),\n 'mobile-sidebar': prop.string(),\n rounded: prop.string<RoundedSize>(),\n 'scroll-threshold': prop.number(80),\n sticky: prop.bool(false),\n variant: prop.string<'flat' | 'solid' | 'bordered' | 'outline' | 'frost'>(),\n },\n setup(props, { bind, el, emit, onMounted, provide, slots }) {\n const hasLogo = () => slots.has('logo').value;\n const hasMobileMenu = () => slots.elements('mobile-menu').value.some(hasElementContent);\n const mobileSidebarTarget = signal<MobileSidebarElement | null>(null);\n const isExternalMobileMode = signal(false);\n const isExternalMobileOpen = signal(false);\n const isMobile = signal(false);\n const isMobileMenuOpen = signal(false);\n const isModeTransitioning = signal(false);\n const isScrolled = signal(false);\n const scrollBase = signal(0);\n const mediaMatches = signal(false);\n const sizeMatches = signal(false);\n const maxWidthPx = signal<number | undefined>(parseMaxWidthPx(props.breakpoint.value));\n const isPreviewMode = signal(false);\n\n const getExternalSidebar = () => {\n const selector = String(props['mobile-sidebar'].value ?? '').trim();\n\n if (!selector) return null;\n\n const root = el.getRootNode();\n const scopedTarget =\n root instanceof ShadowRoot || root instanceof Document\n ? (root.querySelector(selector) as MobileSidebarElement | null)\n : null;\n\n return scopedTarget ?? (document.querySelector(selector) as MobileSidebarElement | null);\n };\n\n provide(NAVBAR_CTX, {\n isMobile: computed(() => isMobile.value) as Readable<boolean>,\n mobileMenuOpen: computed(() => isMobileMenuOpen.value) as Readable<boolean>,\n });\n\n const computeMode = (): NavbarMode | undefined => {\n if (props.floating.value && props.sticky.value) {\n return isScrolled.value ? 'sticky' : 'floating';\n }\n\n if (props.floating.value) return 'floating';\n\n if (props.sticky.value) return 'sticky';\n\n return undefined;\n };\n\n const setMobileMenu = (next: boolean) => {\n const open = Boolean(next);\n\n if (!hasMobileMenu()) {\n const target = mobileSidebarTarget.value ?? getExternalSidebar();\n\n if (target) {\n if (open) {\n target.openMobile?.();\n } else {\n target.closeMobile?.();\n }\n\n return;\n }\n }\n\n if (open && !hasMobileMenu()) return;\n\n if (isMobileMenuOpen.value === open) return;\n\n isMobileMenuOpen.value = open;\n emit('mobile-menu-change', { open });\n };\n\n const closeMobileMenu = () => setMobileMenu(false);\n const openMobileMenu = () => setMobileMenu(true);\n const toggleMobileMenu = () => {\n if (!hasMobileMenu()) {\n const target = mobileSidebarTarget.value ?? getExternalSidebar();\n\n if (target) {\n if (typeof target.toggleMobile === 'function') {\n target.toggleMobile();\n } else if (typeof target.openMobile === 'function' && typeof target.closeMobile === 'function') {\n const isOpen = target.hasAttribute('data-mobile-open');\n\n if (isOpen) target.closeMobile();\n else target.openMobile();\n }\n\n return;\n }\n }\n\n setMobileMenu(!isMobileMenuOpen.value);\n };\n\n const syncMobileMode = () => {\n const next =\n (mobileSidebarTarget.value && !hasMobileMenu() ? isExternalMobileMode.value : false) ||\n mediaMatches.value ||\n sizeMatches.value;\n\n isMobile.value = next;\n\n if (!next) closeMobileMenu();\n };\n\n const readScrollOffset = (scrollContainer: HTMLElement | null): number => {\n if (scrollContainer) {\n return scrollContainer.scrollTop || 0;\n }\n\n return window.scrollY || document.documentElement.scrollTop || 0;\n };\n\n const resetScrollBase = (scrollContainer: HTMLElement | null) => {\n scrollBase.value = readScrollOffset(scrollContainer);\n };\n\n const updateScrolled = (scrollContainer: HTMLElement | null = null) => {\n if (!(props.floating.value && props.sticky.value)) {\n if (isScrolled.value) isScrolled.value = false;\n\n return;\n }\n\n const threshold = Math.max(0, Number(props['scroll-threshold'].value) || 0);\n const currentOffset = readScrollOffset(scrollContainer);\n const delta = currentOffset - scrollBase.value;\n\n isScrolled.value = delta > threshold;\n };\n\n bind({\n attr: {\n 'data-mobile': () => (isMobile.value ? true : undefined),\n 'data-mobile-open': () => (isMobile.value && isMobileMenuOpen.value ? true : undefined),\n 'data-mode': () => computeMode() ?? null,\n 'data-mode-transitioning': () => (isModeTransitioning.value ? true : undefined),\n 'data-preview-mode': () => (isPreviewMode.value ? true : undefined),\n 'data-scrolled': () => (props.floating.value && props.sticky.value && isScrolled.value ? true : undefined),\n },\n });\n\n onMounted(() => {\n const navbarEl = el as NavbarElement;\n const scrollContainer = findScrollContainer(el);\n\n navbarEl.closeMobileMenu = closeMobileMenu;\n navbarEl.openMobileMenu = openMobileMenu;\n navbarEl.toggleMobileMenu = toggleMobileMenu;\n\n const stopScroll = listen(\n window,\n 'scroll',\n () => {\n updateScrolled(scrollContainer);\n },\n { passive: true },\n );\n const stopContainerScroll = scrollContainer\n ? listen(\n scrollContainer,\n 'scroll',\n () => {\n updateScrolled(scrollContainer);\n },\n { passive: true },\n )\n : undefined;\n const stopEscape = listen(el, 'keydown', (event: KeyboardEvent) => {\n if (event.key !== 'Escape' || !isMobileMenuOpen.value) return;\n\n closeMobileMenu();\n });\n\n let mediaCleanup: (() => void) | undefined;\n let mobileSidebarCleanup: (() => void) | undefined;\n let modeTransitionTimeout: ReturnType<typeof setTimeout> | undefined;\n let previousMode: NavbarMode | undefined;\n\n const resolveMobileSidebarTarget = () => {\n mobileSidebarCleanup?.();\n mobileSidebarCleanup = undefined;\n mobileSidebarTarget.value = null;\n isExternalMobileMode.value = false;\n isExternalMobileOpen.value = false;\n\n const target = getExternalSidebar();\n\n if (!target) return;\n\n const syncTargetState = (event?: CustomEvent<{ open: boolean }>) => {\n const hasBottomNav = target.hasAttribute('data-bottom-nav');\n const hasMobileOpen = target.hasAttribute('data-mobile-open');\n\n isExternalMobileMode.value = hasBottomNav;\n isExternalMobileOpen.value = event?.detail ? event.detail.open : hasMobileOpen;\n\n // If the sidebar is reporting it's open, it must be in bottom-nav mode\n // (either natural or forced). We honor this to avoid race conditions\n // where attributes haven't reflected yet.\n if (isExternalMobileOpen.value && !isExternalMobileMode.value) {\n isExternalMobileMode.value = true;\n }\n\n syncMobileMode();\n };\n\n const targetObserver = new MutationObserver(() => {\n syncTargetState();\n });\n\n syncTargetState();\n targetObserver.observe(target, {\n attributeFilter: ['data-bottom-nav', 'data-mobile-open'],\n attributes: true,\n });\n target.addEventListener('mobile-open-change', syncTargetState as EventListener);\n mobileSidebarCleanup = () => {\n targetObserver.disconnect();\n target.removeEventListener('mobile-open-change', syncTargetState as EventListener);\n };\n mobileSidebarTarget.value = target;\n };\n\n const triggerModeTransition = () => {\n isModeTransitioning.value = true;\n\n if (modeTransitionTimeout != null) clearTimeout(modeTransitionTimeout);\n\n modeTransitionTimeout = setTimeout(() => {\n isModeTransitioning.value = false;\n modeTransitionTimeout = undefined;\n }, 220);\n };\n\n const stopModeWatch = watch(\n computed(() => props.floating.value && props.sticky.value),\n (enabled) => {\n if (!enabled) {\n if (isScrolled.value) isScrolled.value = false;\n\n if (isModeTransitioning.value) isModeTransitioning.value = false;\n\n previousMode = undefined;\n\n if (modeTransitionTimeout != null) {\n clearTimeout(modeTransitionTimeout);\n modeTransitionTimeout = undefined;\n }\n\n return;\n }\n\n resetScrollBase(scrollContainer);\n updateScrolled(scrollContainer);\n\n const currentMode = computeMode();\n\n previousMode = currentMode;\n },\n { immediate: true },\n );\n\n const stopMobileSidebarWatch = watch(\n props['mobile-sidebar'],\n () => {\n resolveMobileSidebarTarget();\n },\n { immediate: true },\n );\n\n const stopModeTransitionWatch = watch(\n computed(() => computeMode()),\n (nextMode) => {\n const comboEnabled = props.floating.value && props.sticky.value;\n\n if (!comboEnabled) {\n previousMode = nextMode ?? undefined;\n\n return;\n }\n\n const next = nextMode ?? undefined;\n\n if (previousMode && next && previousMode !== next) {\n triggerModeTransition();\n }\n\n previousMode = next;\n },\n { immediate: true },\n );\n\n const stopMobileMenuSlotWatch = watch(\n computed(() => hasMobileMenu()),\n (hasContent) => {\n if (!hasContent && isMobileMenuOpen.value) {\n closeMobileMenu();\n }\n },\n { immediate: true },\n );\n\n watch(\n props.breakpoint,\n (query) => {\n mediaCleanup?.();\n mediaCleanup = undefined;\n\n const mediaQuery = String(query ?? '').trim();\n\n maxWidthPx.value = parseMaxWidthPx(mediaQuery);\n mediaMatches.value = false;\n\n const width = readContainerWidth(el);\n\n sizeMatches.value = width > 0 && maxWidthPx.value != null ? width <= maxWidthPx.value : false;\n syncMobileMode();\n\n if (props['container-breakpoints'].value && maxWidthPx.value != null) {\n return;\n }\n\n if (!mediaQuery) {\n return;\n }\n\n if (typeof window.matchMedia !== 'function') {\n return;\n }\n\n const mql = window.matchMedia(mediaQuery);\n const syncMedia = (next: boolean) => {\n mediaMatches.value = next;\n syncMobileMode();\n };\n const onChange = (event: MediaQueryListEvent) => {\n syncMedia(event.matches);\n };\n\n syncMedia(mql.matches);\n mql.addEventListener('change', onChange);\n\n mediaCleanup = () => {\n mql.removeEventListener('change', onChange);\n };\n },\n { immediate: true },\n );\n\n const stopResizeEffect =\n typeof ResizeObserver === 'function'\n ? (() => {\n const hostSize = resizeObserver(el);\n const wrapperEl = el.parentElement;\n const containerEl = resolveContainerElement(el);\n const wrapperSize = wrapperEl ? resizeObserver(wrapperEl) : undefined;\n const parentSize = containerEl && containerEl !== wrapperEl ? resizeObserver(containerEl) : undefined;\n\n return watch(\n computed(() => [\n hostSize.value.width,\n hostSize.value.height,\n wrapperSize?.value.width,\n wrapperSize?.value.height,\n parentSize?.value.width,\n parentSize?.value.height,\n ]),\n () => {\n const width = readContainerWidth(el);\n const parentWidth = resolveContainerElement(el)?.clientWidth ?? 0;\n\n sizeMatches.value = width > 0 && maxWidthPx.value != null ? width <= maxWidthPx.value : false;\n isPreviewMode.value = parentWidth > 0 && parentWidth < window.innerWidth;\n syncMobileMode();\n },\n );\n })()\n : undefined;\n\n return () => {\n stopEscape?.();\n stopScroll?.();\n stopContainerScroll?.();\n stopModeWatch?.dispose();\n stopModeTransitionWatch?.dispose();\n stopMobileMenuSlotWatch?.dispose();\n stopMobileSidebarWatch?.dispose();\n mediaCleanup?.();\n mobileSidebarCleanup?.();\n stopResizeEffect?.dispose();\n\n if (modeTransitionTimeout != null) {\n clearTimeout(modeTransitionTimeout);\n modeTransitionTimeout = undefined;\n }\n };\n });\n\n return html`\n <nav part=\"nav\" aria-label=\"${props.label}\">\n <div class=\"navbar\" part=\"bar\">\n <div class=\"navbar-logo\" part=\"logo\" ?hidden=${() => !hasLogo()}>\n <slot name=\"logo\"></slot>\n </div>\n\n <div class=\"navbar-start\" part=\"start\">\n <slot name=\"start\"></slot>\n </div>\n\n <div class=\"navbar-center\" part=\"center\">\n <slot></slot>\n </div>\n\n <div class=\"navbar-end\" part=\"end\">\n <slot name=\"end\"></slot>\n </div>\n\n <button\n class=\"mobile-toggle\"\n part=\"mobile-toggle\"\n type=\"button\"\n aria-label=\"${() =>\n hasMobileMenu()\n ? isMobileMenuOpen.value\n ? 'Close navigation menu'\n : 'Open navigation menu'\n : isExternalMobileOpen.value\n ? 'Close navigation menu'\n : 'Open navigation menu'}\"\n aria-controls=\"mobile-menu-panel\"\n aria-expanded=\"${() => String(hasMobileMenu() ? isMobileMenuOpen.value : isExternalMobileOpen.value)}\"\n ?hidden=${() => !isMobile.value || (!hasMobileMenu() && !mobileSidebarTarget.value)}\n @click=\"${toggleMobileMenu}\">\n <ore-icon\n name=\"${() => ((hasMobileMenu() ? isMobileMenuOpen.value : isExternalMobileOpen.value) ? 'x' : 'menu')}\"\n size=\"18\"\n stroke-width=\"2.5\"\n aria-hidden=\"true\"></ore-icon>\n </button>\n </div>\n\n <div\n id=\"mobile-menu-panel\"\n class=\"mobile-menu-panel\"\n part=\"mobile-menu\"\n role=\"navigation\"\n :aria-label=\"${() => `${props.label.value} mobile menu`}\"\n ?hidden=${() => !isMobile.value || !isMobileMenuOpen.value || !hasMobileMenu()}>\n <slot name=\"mobile-menu\"></slot>\n </div>\n </nav>\n `;\n },\n styles: [\n colorThemeMixin,\n elevationMixin,\n roundedVariantMixin,\n coarsePointerMixin,\n reducedMotionMixin,\n frostVariantMixin('.navbar'),\n navbarStyles,\n ],\n});\n\n/**\n * `ore-navbar-item` — Navigation item for navbar slots.\n *\n * Renders as an anchor when `href` is provided and item is not disabled.\n *\n * @element ore-navbar-item\n *\n * @attr {boolean} active - Marks item as the current active route\n * @attr {boolean} disabled - Disables interaction\n * @attr {string} href - Link URL; renders as `<a>` when set\n * @attr {string} rel - Anchor `rel` attribute (links only)\n * @attr {string} target - Anchor `target` attribute (links only)\n *\n * @slot - Item label\n * @slot icon - Optional icon before the label\n *\n * @part item - Root clickable element (anchor or button).\n * @part item-icon - Leading icon container.\n * @part item-label - Label text container.\n * @part item-end - Trailing content container.\n *\n * @example\n * ```html\n * <ore-navbar-item href=\"/home\">Home</ore-navbar-item>\n * <ore-navbar-item href=\"/docs\" active>Docs</ore-navbar-item>\n * <ore-navbar-item href=\"/about\" target=\"_blank\" rel=\"noopener\">About</ore-navbar-item>\n * <ore-navbar-item disabled>Disabled</ore-navbar-item>\n * ```\n */\nexport const NAVBAR_ITEM_TAG = 'ore-navbar-item' as const;\ndefine<OreNavbarItemProps>(NAVBAR_ITEM_TAG, {\n props: {\n active: prop.bool(false),\n disabled: prop.bool(false),\n href: prop.string(),\n rel: prop.string(),\n target: prop.string(),\n },\n setup(props, { bind, slots }) {\n const hasIcon = () => slots.has('icon').value;\n const hasEnd = () => slots.has('end').value;\n const navbarCtx = inject(NAVBAR_CTX);\n\n bind({\n attr: {\n 'navbar-mobile': () => (navbarCtx?.isMobile.value ? true : undefined),\n 'navbar-mobile-open': () => (navbarCtx?.mobileMenuOpen.value ? true : undefined),\n },\n });\n\n const isLink = () => Boolean(props.href.value) && !props.disabled.value;\n\n // Prevent reverse tabnapping: auto-inject noopener + noreferrer for _blank links.\n const effectiveRel = computed(() => computeSafeRel(props.rel.value, props.target.value));\n\n const renderItemContent = () => html`\n <span class=\"item-icon\" part=\"item-icon\" ?hidden=${() => !hasIcon()} aria-hidden=\"true\">\n <slot name=\"icon\"></slot>\n </span>\n <span class=\"item-label\" part=\"item-label\"><slot></slot></span>\n <span class=\"item-end\" part=\"item-end\" ?hidden=${() => !hasEnd()}>\n <slot name=\"end\"></slot>\n </span>\n `;\n\n return html`\n ${() => {\n if (isLink()) {\n return html`\n <a\n class=\"item\"\n part=\"item\"\n href=\"${props.href}\"\n :rel=\"${effectiveRel}\"\n :target=\"${props.target}\"\n aria-current=\"${() => (props.active.value ? 'page' : null)}\">\n ${renderItemContent()}\n </a>\n `;\n }\n\n if (props.disabled.value) {\n return html`<div class=\"item\" part=\"item\" tabindex=\"-1\" aria-disabled=\"true\">${renderItemContent()}</div>`;\n }\n\n return html`<button class=\"item\" part=\"item\" type=\"button\">${renderItemContent()}</button>`;\n }}\n `;\n },\n styles: [coarsePointerMixin, navbarStyles],\n});\n","/*\n * Simplified and unified sidebar-group CSS:\n * - Combined cursor and chevron logic for [collapsible] and :not([collapsible])\n * - Grouped hover/focus/active state rules\n * - Clarified collapsed mode label/chevron hiding\n */\n\n@layer refine.base {\n :host {\n display: block;\n width: 100%;\n }\n\n :host([sidebar-bottom-nav]) {\n display: none;\n }\n\n .group {\n display: block;\n }\n\n .group-header {\n all: unset;\n position: relative;\n box-sizing: border-box;\n display: flex;\n align-items: center;\n justify-content: flex-start;\n width: 100%;\n min-height: var(--size-6);\n padding: var(--size-1) var(--size-2);\n margin-bottom: var(--size-2);\n color: inherit;\n user-select: none;\n outline: none;\n border-radius: var(--rounded-lg);\n transition: background var(--transition-fast);\n }\n\n .group-header::-webkit-details-marker {\n display: none;\n }\n\n /* Collapsible group: pointer, hover/focus, show chevron */\n :host([collapsible]) .group-header {\n cursor: pointer;\n }\n\n :host([collapsible]) .group-header:hover {\n background: var(--color-contrast-100);\n }\n\n :host([collapsible]) .group-header:focus-visible {\n outline: var(--focus-ring);\n }\n\n /* Non-collapsible group: default cursor, hide chevron */\n :host(:not([collapsible])) .group-header {\n cursor: default;\n }\n\n :host(:not([collapsible])) .chevron {\n display: none !important;\n }\n\n .group-label {\n flex-grow: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n font-size: var(--text-xs);\n font-weight: var(--font-semibold);\n color: var(--color-contrast-500);\n text-transform: uppercase;\n letter-spacing: 0.06em;\n white-space: nowrap;\n transition: opacity var(--transition-fast);\n }\n\n .group-icon {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n color: var(--color-contrast-400);\n }\n\n .group-icon:empty {\n display: none;\n }\n\n .chevron {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n color: var(--color-contrast-400);\n transition: var(--_motion-transition, transform var(--transition-normal));\n }\n\n /* Chevron rotation for open group */\n :host([collapsible]) .group[open] .chevron {\n transform: rotate(90deg);\n }\n\n .group-items {\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n gap: var(--size-2);\n min-width: 0;\n }\n\n /* Collapsed-sidebar: hide label text and chevron, center icon */\n :host([sidebar-collapsed]) .group-label,\n :host([sidebar-collapsed]) .chevron {\n display: none;\n }\n\n :host([sidebar-collapsed]) .group-header {\n display: none;\n height: 0;\n min-height: 0;\n padding: 0;\n margin: 0;\n }\n\n :host([sidebar-collapsed]) .group-badge {\n position: static !important;\n display: flex !important;\n visibility: visible !important;\n width: auto !important;\n height: auto !important;\n pointer-events: auto !important;\n opacity: 1 !important;\n }\n\n /* Collapsible group closed: hide items */\n :host([collapsible]:not([open])) .group-items {\n display: none;\n }\n}\n","/*\n * Simplified and unified sidebar-item CSS:\n * - Unified badge overlay logic\n * - Grouped collapsed mode rules\n * - Combined state rules (active, disabled, hover, focus)\n * - Clarified selectors for maintainability\n */\n\n@layer refine.base {\n :host {\n display: block;\n min-width: 0;\n max-width: 100%;\n }\n\n .item {\n position: relative;\n box-sizing: border-box;\n display: flex;\n gap: var(--size-2);\n align-items: center;\n min-width: 0;\n min-height: var(--_touch-target);\n padding: var(--size-1-5) var(--size-2);\n font-size: var(--sidebar-item-font-size, var(--text-sm));\n font-weight: var(--font-medium);\n color: var(--sidebar-item-color, var(--color-contrast-700));\n text-decoration: none;\n cursor: pointer;\n user-select: none;\n outline: none;\n border-radius: var(--rounded-lg);\n transition:\n background var(--transition-fast),\n color var(--transition-fast);\n }\n\n a.item {\n text-decoration: none;\n }\n\n .item:hover,\n .item:focus-visible {\n color: var(--sidebar-item-hover-color, var(--color-contrast-900));\n outline: var(--focus-ring);\n outline-offset: 1px;\n background: var(--sidebar-item-hover-bg, var(--color-contrast-100));\n }\n\n :host([active]) .item {\n font-weight: var(--font-semibold);\n color: var(--sidebar-item-active-color, var(--color-primary));\n background: var(\n --sidebar-item-active-bg,\n var(--color-primary-100, color-mix(in oklch, var(--color-primary) 12%, transparent))\n );\n }\n\n :host([active]) .item::before {\n display: none;\n }\n\n :host([disabled]) .item,\n :host([disabled]) .item:hover,\n :host([disabled]) .item:focus-visible {\n color: var(--sidebar-item-disabled-color, var(--color-contrast-300));\n pointer-events: none;\n cursor: not-allowed;\n outline: none;\n background: none;\n opacity: 1;\n }\n\n :host([disabled]) .item-icon {\n color: var(--sidebar-item-disabled-color, var(--color-contrast-300));\n }\n\n .item-icon {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n width: var(--size-5);\n height: var(--size-5);\n margin: 0 auto;\n }\n\n .item-label {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n transition: opacity var(--transition-fast);\n }\n\n .item-end {\n display: flex;\n flex-shrink: 0;\n gap: var(--size-1);\n align-items: center;\n transition: opacity var(--transition-fast);\n }\n\n /* Collapsed sidebar: hide label text, adjust layout, overlay badge */\n :host([sidebar-collapsed]) .item,\n :host([sidebar-collapsed]) .item-icon {\n position: relative;\n }\n\n :host([sidebar-collapsed]) .item-label {\n width: 0;\n overflow: hidden;\n pointer-events: none;\n opacity: 0;\n }\n\n :host([sidebar-collapsed]) .item {\n gap: 0;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n min-height: 100%;\n padding: 0;\n }\n\n :host([sidebar-collapsed]) .item::before {\n inset-block: var(--size-2);\n }\n\n :host([sidebar-collapsed]) .item-icon {\n width: var(--size-7);\n height: var(--size-7);\n padding: var(--size-1-5);\n font-size: 1.5em;\n }\n\n :host([sidebar-collapsed][active]) .item {\n background: none;\n }\n\n :host([sidebar-collapsed]) .item:hover {\n background: none;\n }\n\n :host([sidebar-collapsed][active]) .item-icon {\n background: var(\n --sidebar-item-active-bg,\n var(--color-primary-100, color-mix(in oklch, var(--color-primary) 12%, transparent))\n );\n border-radius: var(--rounded-full);\n }\n\n :host([sidebar-collapsed]) .item-icon:hover {\n background: var(--color-contrast-100);\n border-radius: var(--rounded-full);\n }\n\n /* Unified badge overlay logic for collapsed mode */\n :host([sidebar-collapsed]) .item-end,\n :host([sidebar-collapsed]) .item-icon .group-badge,\n :host([sidebar-collapsed]) .item-icon ::slotted([slot='end']) {\n position: absolute;\n right: 0;\n bottom: calc(var(--size-2) * -1);\n z-index: 2;\n display: flex;\n align-items: center;\n justify-content: center;\n min-width: 1.25em;\n min-height: 1.25em;\n pointer-events: auto;\n opacity: 1;\n transform: translate(40%, -40%);\n }\n\n :host([dir='rtl'][sidebar-collapsed]) .item-end,\n :host([dir='rtl'][sidebar-collapsed]) .item-icon .group-badge,\n :host([dir='rtl'][sidebar-collapsed]) .item-icon ::slotted([slot='end']),\n :host(:dir(rtl)[sidebar-collapsed]) .item-end,\n :host(:dir(rtl)[sidebar-collapsed]) .item-icon .group-badge,\n :host(:dir(rtl)[sidebar-collapsed]) .item-icon ::slotted([slot='end']) {\n right: auto;\n left: 0;\n transform: translate(-40%, -40%);\n }\n\n :host([sidebar-collapsed]) .item-end .group-badge,\n :host([sidebar-collapsed]) .item-end ::slotted([slot='end']) {\n position: absolute;\n top: 50%;\n right: var(--size-2);\n z-index: 1;\n transform: translateY(-50%);\n }\n\n :host([dir='rtl'][sidebar-collapsed]) .item-end .group-badge,\n :host([dir='rtl'][sidebar-collapsed]) .item-end ::slotted([slot='end']),\n :host(:dir(rtl)[sidebar-collapsed]) .item-end .group-badge,\n :host(:dir(rtl)[sidebar-collapsed]) .item-end ::slotted([slot='end']) {\n right: auto;\n left: var(--size-2);\n }\n\n /* The bottom tab bar (`.bottom-bar` in sidebar.ts) renders its own promoted-item\n buttons from the same data — the original <ore-sidebar-item> stays inside the\n (visually off-screen while closed) <nav>, so it must be fully hidden here to\n avoid a focusable/AT-visible duplicate of the bottom-bar entry. */\n :host([sidebar-bottom-nav]) {\n display: none;\n }\n}\n",".sidebar-logo[hidden] {\n display: none !important;\n min-width: 0 !important;\n min-height: 0 !important;\n margin: 0 !important;\n}\n\n/*\n * Simplified and unified sidebar CSS:\n * - Grouped collapsed/expanded state rules\n * - Consistent use of CSS variables for spacing, color, and transitions\n * - Removed redundant or legacy rules\n * - Clarified variant handling\n */\n\n@layer refine.base {\n :host {\n --_sidebar-width: var(--sidebar-width, 16rem);\n --_sidebar-collapsed-width: var(--sidebar-collapsed-width, 3.5rem);\n --_sidebar-transition: var(--transition-normal);\n --_panel-bg: var(--sidebar-bg, var(--color-canvas));\n --_panel-blur: var(--sidebar-panel-blur, var(--blur-md));\n --_panel-border-color: var(--sidebar-border-color, var(--color-divider));\n --_panel-radius: var(--sidebar-radius, var(--rounded-lg));\n --_panel-shadow: var(--sidebar-shadow, var(--shadow-md));\n\n box-sizing: border-box;\n display: block;\n width: 100%;\n min-width: var(--size-2xs);\n max-width: var(--_sidebar-width);\n height: 100%;\n min-height: 0;\n overflow: visible;\n transition:\n max-width var(--_sidebar-transition),\n min-width var(--_sidebar-transition);\n will-change: max-width;\n }\n\n :host > nav {\n position: relative;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n min-height: 0;\n overflow: hidden;\n background: var(--_panel-bg);\n border-inline-end: var(--border) solid var(--_panel-border-color);\n backdrop-filter: blur(var(--_panel-blur));\n }\n\n .mobile-backdrop {\n position: absolute;\n inset: 0;\n z-index: calc(var(--z-sticky, 40) + 1);\n display: none;\n width: 100%;\n height: 100%;\n background: color-mix(in oklch, var(--color-contrast-950) 36%, transparent);\n border: 0;\n }\n\n :host([data-bottom-nav][data-mobile-open]) .mobile-backdrop {\n position: fixed;\n inset: 0;\n z-index: calc(var(--z-sticky, 40) + 1);\n display: block;\n width: 100vw;\n height: 100dvh;\n }\n\n :host([data-preview-mode][data-bottom-nav][data-mobile-open]) .mobile-backdrop {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n }\n\n :host([data-no-transition]),\n :host([data-no-transition]) > nav {\n transition: none !important;\n }\n\n :host([data-collapsed]) {\n min-width: var(--_sidebar-collapsed-width);\n max-width: var(--_sidebar-collapsed-width);\n }\n\n :host([data-bottom-nav]) {\n position: fixed;\n inset-block-end: 0;\n inset-inline: 0;\n z-index: calc(var(--z-sticky, 40) + 2);\n width: 100%;\n min-width: 0;\n max-width: 100%;\n height: var(--sidebar-bottom-nav-height, 3.75rem);\n pointer-events: auto;\n }\n\n /* Preview mode: constrain bottom-nav to container bounds */\n :host([data-preview-mode][data-bottom-nav]) {\n position: absolute;\n inset: 0;\n width: auto;\n height: auto;\n pointer-events: none;\n }\n\n :host([data-bottom-nav]) > nav {\n position: fixed;\n inset-block: 0;\n inset-inline-start: 0;\n z-index: calc(var(--z-sticky, 40) + 3);\n width: min(var(--_sidebar-width), 85vw);\n max-width: 85vw;\n max-height: 100dvh;\n transform: translateX(-104%);\n transition: transform var(--transition-normal);\n }\n\n /* Preview mode: use absolute positioning so drawer stays within container */\n :host([data-preview-mode][data-bottom-nav]) > nav {\n position: absolute;\n inset-block: 0;\n inset-inline-start: 0;\n z-index: calc(var(--z-sticky, 40) + 3);\n max-height: 100%;\n pointer-events: auto;\n }\n\n :host(:dir(rtl)[data-bottom-nav]) > nav {\n transform: translateX(104%);\n }\n\n :host([data-bottom-nav][data-mobile-open]) > nav {\n transform: translateX(0);\n }\n\n .bottom-bar {\n display: flex;\n gap: var(--size-1);\n align-items: stretch;\n justify-content: space-around;\n width: 100%;\n height: 100%;\n padding: var(--size-1);\n pointer-events: none;\n background: var(--_panel-bg);\n border-top: var(--border) solid var(--_panel-border-color);\n box-shadow: var(--shadow-sm);\n opacity: 0;\n backdrop-filter: blur(var(--_panel-blur));\n transform: translateY(100%);\n transition:\n opacity var(--_sidebar-transition),\n transform var(--_sidebar-transition),\n display var(--_sidebar-transition) allow-discrete;\n }\n\n :host([data-bottom-nav]) .bottom-bar {\n pointer-events: auto;\n opacity: 1;\n transform: translateY(0);\n }\n\n :host([data-preview-mode][data-bottom-nav]) .bottom-bar {\n position: absolute;\n inset-block-end: 0;\n inset-inline: 0;\n z-index: calc(var(--z-sticky, 40) + 2);\n height: var(--sidebar-bottom-nav-height, 3.75rem);\n }\n\n :host([data-bottom-nav][data-mobile-open]) .bottom-bar {\n z-index: calc(var(--z-sticky, 40) + 1);\n pointer-events: none;\n opacity: 0;\n transform: translateY(100%);\n }\n\n .bottom-tab {\n all: unset;\n position: relative;\n box-sizing: border-box;\n display: flex;\n flex: 1 1 0;\n flex-direction: column;\n gap: var(--size-0-5);\n align-items: center;\n justify-content: center;\n min-width: 0;\n padding: var(--size-1) var(--size-1-5);\n color: var(--sidebar-item-color, var(--color-contrast-700));\n text-decoration: none;\n cursor: pointer;\n border-radius: var(--rounded-md);\n transition:\n background var(--transition-fast),\n color var(--transition-fast);\n }\n\n .bottom-tab:hover,\n .bottom-tab:focus-visible {\n color: var(--sidebar-item-hover-color, var(--color-contrast-900));\n outline: var(--focus-ring);\n outline-offset: 1px;\n background: var(--sidebar-item-hover-bg, var(--color-contrast-100));\n }\n\n .bottom-tab:disabled {\n color: var(--sidebar-item-disabled-color, var(--color-contrast-400));\n cursor: not-allowed;\n opacity: 0.7;\n }\n\n .bottom-tab-active,\n .bottom-tab[data-active='true'] {\n color: var(--sidebar-item-active-color, var(--color-primary));\n background: var(\n --sidebar-item-active-bg,\n var(--color-primary-100, color-mix(in oklch, var(--color-primary) 12%, transparent))\n );\n }\n\n .bottom-tab-active::before,\n .bottom-tab[data-active='true']::before {\n display: none;\n }\n\n .bottom-tab-icon {\n display: inline-flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n width: var(--size-5);\n height: var(--size-5);\n }\n\n .bottom-tab-label {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n font-size: var(--text-xs);\n white-space: nowrap;\n }\n\n .sidebar-header {\n display: flex;\n gap: var(--size-2);\n align-items: center;\n justify-content: space-between;\n min-height: var(--size-6);\n padding: var(--size-4);\n border-bottom: var(--border) solid var(--color-contrast-200);\n }\n\n .sidebar-header .sidebar-header-content {\n display: block;\n flex: 1 1 0%;\n min-width: 0;\n overflow: hidden;\n }\n\n :host([data-collapsed]) .sidebar-header {\n flex-direction: column;\n gap: var(--size-2);\n align-items: center;\n justify-content: flex-start;\n min-height: unset;\n padding-block: var(--size-2);\n padding-inline: var(--size-2);\n }\n\n :host([data-collapsed]) .sidebar-header .sidebar-header-content {\n display: none !important;\n }\n\n .sidebar-logo {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n min-width: var(--size-8);\n min-height: var(--size-8);\n margin-inline-end: var(--size-2);\n }\n\n .sidebar-logo:empty {\n display: none !important;\n }\n\n :host([data-collapsed]) .sidebar-logo {\n margin-block: var(--size-1);\n margin-inline-end: 0;\n }\n\n .sidebar-content {\n display: grid;\n flex: 1;\n grid-template-columns: minmax(0, 1fr);\n gap: var(--size-2);\n align-content: start;\n min-width: 0;\n padding: var(--size-4);\n overflow: clip auto;\n scrollbar-width: thin;\n }\n\n .sidebar-footer {\n flex-shrink: 0;\n padding: var(--size-4);\n border-top: var(--border) solid var(--color-contrast-200);\n }\n\n .toggle-btn {\n all: unset;\n box-sizing: border-box;\n display: inline-flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n width: var(--size-8);\n height: var(--size-8);\n color: var(--color-contrast-500);\n cursor: pointer;\n border-radius: var(--rounded-sm);\n transition:\n color var(--transition-fast),\n background var(--transition-fast);\n }\n\n .toggle-btn:hover {\n color: var(--color-contrast-800);\n background: var(--color-contrast-200);\n }\n\n .toggle-btn:focus-visible {\n outline: var(--focus-ring);\n }\n\n .toggle-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n transition: var(--_motion-transition, transform var(--_sidebar-transition));\n }\n\n :host([data-collapsed]) .toggle-icon {\n transform: rotate(180deg);\n }\n\n :host([data-bottom-nav]) .toggle-btn {\n display: none;\n }\n\n :host(:not([dir='rtl'])[data-collapsed]) .toggle-icon,\n :host(:dir(ltr)[data-collapsed]) .toggle-icon {\n transform: rotate(180deg);\n }\n\n :host(:dir(rtl)) .toggle-icon {\n transform: rotate(180deg);\n }\n\n :host(:dir(rtl)[data-collapsed]) .toggle-icon {\n transform: rotate(0deg);\n }\n}\n\n@layer refine.variants {\n /* ── floating ── */\n :host([variant='floating']) {\n height: calc(100% - var(--size-6));\n margin: var(--size-3);\n\n --_panel-radius: var(--rounded-lg);\n }\n\n :host([variant='floating']) > nav {\n border: var(--border) solid var(--_panel-border-color);\n border-radius: var(--_panel-radius);\n }\n\n :host([variant='floating'][data-bottom-nav]) {\n inset-block-end: var(--size-2);\n inset-inline: var(--size-2);\n width: auto;\n max-width: none;\n }\n\n :host([variant='floating'][data-preview-mode][data-bottom-nav]) {\n inset: var(--size-2);\n }\n\n :host([variant='floating'][data-bottom-nav]) .bottom-bar {\n border: var(--border) solid var(--_panel-border-color);\n border-radius: var(--_panel-radius);\n box-shadow: var(--_panel-shadow);\n }\n\n :host([variant='floating'][data-bottom-nav]) > nav {\n inset-block-start: var(--size-2);\n inset-inline-start: var(--size-2);\n }\n\n :host([variant='floating'][data-preview-mode][data-bottom-nav]) .bottom-bar {\n inset-block-end: var(--size-2);\n inset-inline: var(--size-2);\n width: auto;\n }\n\n :host([variant='floating'][data-preview-mode][data-bottom-nav]) > nav {\n inset-block-start: var(--size-1);\n inset-inline-start: var(--size-1);\n }\n\n /* ── inset ── */\n :host([variant='inset']) {\n --_panel-bg: var(--color-contrast-50);\n --_panel-shadow: none;\n --_panel-border-color: transparent;\n }\n}\n","import { createContext, define, html, inject, prop } from '@vielzeug/ore';\nimport { resizeObserver } from '@vielzeug/ore/observers';\nimport { computed, type Readable, signal, watch } from '@vielzeug/ripple';\n\nimport '../../content/icon/icon';\nimport { coarsePointerMixin, reducedMotionMixin } from '../../styles';\nimport { computeSafeRel } from '../../utils';\nimport groupStyles from './sidebar-group.css?inline';\nimport itemStyles from './sidebar-item.css?inline';\nimport sidebarStyles from './sidebar.css?inline';\n\n// ─── Types ────────────────────────────────────────────────────────────────\n\ntype SidebarVariant = 'floating' | 'inset';\ntype SidebarCollapseSource = 'api' | 'responsive' | 'toggle';\ntype SidebarMobileSource = 'api' | 'responsive' | 'toggle';\ntype SidebarMode = 'bottom-nav' | 'collapsed' | 'default';\n\ntype BottomNavItem = {\n active: boolean;\n disabled: boolean;\n href?: string;\n iconName?: string;\n label: string;\n source: HTMLElement;\n};\n\nconst parseMaxWidthPx = (query: string | undefined): number | undefined => {\n const value = String(query ?? '').trim();\n\n if (!value) return undefined;\n\n const match = /max-width\\s*:\\s*([0-9]+(?:\\.[0-9]+)?)px/i.exec(value);\n\n if (!match) return undefined;\n\n const parsed = Number.parseFloat(match[1]);\n\n return Number.isFinite(parsed) ? parsed : undefined;\n};\n\nconst resolveContainerElement = (el: HTMLElement): HTMLElement | null => {\n let container = el.parentElement;\n\n while (container?.tagName.toLowerCase() === 'ore-grid-item') {\n container = container.parentElement;\n }\n\n return container;\n};\n\nconst readContainerWidth = (el: HTMLElement): number => {\n const parentWidth = resolveContainerElement(el)?.clientWidth ?? 0;\n\n if (parentWidth > 0) return parentWidth;\n\n return el.offsetWidth;\n};\n\n/** Context provided by `ore-sidebar` to its `ore-sidebar-group` and `ore-sidebar-item` children. */\nexport type SidebarContext = {\n collapsed: Readable<boolean>;\n mobileOpen: Readable<boolean>;\n mode: Readable<SidebarMode>;\n variant: Readable<SidebarVariant | undefined>;\n};\n\n/** Injection key for the sidebar context. */\nexport const SIDEBAR_CTX = createContext<SidebarContext>('SidebarContext');\n\n// ─── ore-sidebar styles ──────────────────────────────────────────────────────\n\n/** ore-sidebar element interface */\nexport type SidebarElement = HTMLElement &\n OreSidebarProps & {\n /** Close the drawer in bottom-nav mode. */\n closeMobile(): void;\n /** Open the drawer in bottom-nav mode. */\n openMobile(): void;\n /** Set collapsed state imperatively. */\n setCollapsed(next: boolean): void;\n /** Toggle between collapsed and expanded. */\n toggle(): void;\n /** Toggle the drawer in bottom-nav mode. */\n toggleMobile(): void;\n };\n\n/** Sidebar component properties */\n\nexport type OreSidebarEvents = {\n 'collapsed-change': { collapsed: boolean; source: SidebarCollapseSource };\n 'mobile-open-change': { open: boolean; source: SidebarMobileSource };\n};\n\nexport type OreSidebarGroupEvents = {\n 'open-change': { open: boolean };\n};\n\nexport type OreSidebarProps = {\n /** CSS media query that switches the sidebar to bottom navigation mode */\n 'bottom-nav-at'?: string;\n /** Controlled collapsed state */\n collapsed?: boolean;\n /** Whether the sidebar supports collapsing */\n collapsible?: boolean;\n /** Evaluate responsive and bottom-nav breakpoints against container width only. */\n 'container-breakpoints'?: boolean;\n /** Initial collapsed state in uncontrolled mode */\n 'default-collapsed'?: boolean;\n /**\n * Accessible label for the navigation landmark.\n * Use to distinguish multiple navigation regions on a page.\n * @default 'Sidebar navigation'\n */\n label?: string;\n /**\n * CSS media query that, when it matches, automatically collapses the sidebar.\n * Unset by default — no automatic collapse.\n * @example 'responsive=\"(max-width: 768px)\"'\n */\n responsive?: string;\n /** Visual style variant */\n variant?: SidebarVariant;\n};\n\n/**\n * `ore-sidebar` — A collapsible navigation sidebar with group and item support.\n *\n * @element ore-sidebar\n * @element ore-sidebar-group - Labelled group of navigation items\n * @element ore-sidebar-item - Individual navigation link or button\n *\n * @attr {boolean} collapsed - Controlled collapsed state\n * @attr {boolean} default-collapsed - Initial collapsed state for uncontrolled sidebars\n * @attr {boolean} collapsible - Show the collapse toggle button\n * @attr {string} variant - Visual variant: 'floating' | 'inset'\n * @attr {string} label - Accessible aria-label for the nav landmark\n *\n * @fires collapsed-change - Fired when collapsed state changes. detail: { collapsed: boolean; source: string }\n * @fires mobile-open-change - Fired when mobile overlay open state changes. detail: { open: boolean; source: string }\n *\n * @slot header - Branding or logo content above the nav\n * @slot - Navigation content (ore-sidebar-group / ore-sidebar-item)\n * @slot footer - Footer content below the nav (user info, settings, etc.)\n *\n * @cssprop --sidebar-width - Expanded sidebar width (default: 16rem)\n * @cssprop --sidebar-collapsed-width - Collapsed sidebar width (default: 3.5rem)\n * @cssprop --sidebar-bg - Sidebar background color\n * @cssprop --sidebar-border-color - Border color\n *\n * @part mobile-backdrop - Backdrop shown for mobile overlays.\n * @part nav - Navigation container.\n * @part header - Header container.\n * @part toggle-btn - Shadow part for the `toggle-btn` element.\n * @part content - Content container.\n * @part footer - Footer container.\n * @part bottom-bar - Bottom bar container.\n * @part group - Group container.\n * @part group-header - Group header container.\n * @part group-icon - Group icon container.\n * @part group-label - Group label container.\n * @part group-items - Group items container.\n * @part item-icon - Leading item icon container.\n * @part item-label - Item label container.\n * @part item-end - Trailing item content container.\n * @part item - Item root element.\n * @example\n * ```html\n * <ore-sidebar collapsible label=\"App navigation\">\n * <span slot=\"header\">My App</span>\n * <ore-sidebar-group label=\"Main\">\n * <ore-sidebar-item href=\"/dashboard\" active>Dashboard</ore-sidebar-item>\n * <ore-sidebar-item href=\"/settings\">Settings</ore-sidebar-item>\n * </ore-sidebar-group>\n * </ore-sidebar>\n *\n * <!-- Auto-collapse on mobile -->\n * <ore-sidebar collapsible responsive=\"(max-width: 768px)\">...</ore-sidebar>\n * ```\n */\nexport const SIDEBAR_TAG = 'ore-sidebar' as const;\ndefine<OreSidebarProps, OreSidebarEvents>(SIDEBAR_TAG, {\n props: {\n 'bottom-nav-at': prop.string(),\n collapsed: prop.bool(false),\n collapsible: prop.bool(false),\n 'container-breakpoints': prop.bool(false),\n 'default-collapsed': prop.bool(false),\n label: prop.string('Sidebar navigation'),\n responsive: prop.string(),\n variant: prop.string<SidebarVariant>(),\n },\n setup(props, { bind, el, emit, onMounted, provide, slots }) {\n const hasHeader = () => slots.has('header').value;\n const hasFooter = () => slots.has('footer').value;\n const hasLogo = () => slots.has('logo').value;\n\n const isControlled = signal(el.hasAttribute('collapsed'));\n const collapsedState = signal(isControlled.value ? el.hasAttribute('collapsed') : props['default-collapsed'].value);\n const isBottomNav = signal(false);\n const isMobileOpen = signal(false);\n const bottomNavItems = signal<BottomNavItem[]>([]);\n const responsiveMediaMatches = signal(false);\n const responsiveSizeMatches = signal(false);\n const responsiveMaxWidthPx = signal<number | undefined>(parseMaxWidthPx(props.responsive.value));\n const hasResponsiveQuery = signal(Boolean(String(props.responsive.value ?? '').trim()));\n const bottomNavMediaMatches = signal(false);\n const bottomNavSizeMatches = signal(false);\n const bottomNavMaxWidthPx = signal<number | undefined>(parseMaxWidthPx(props['bottom-nav-at'].value));\n const isPreviewMode = signal(false);\n\n const isCollapsed = () => collapsedState.value;\n const mode = computed<SidebarMode>(() => {\n if (isBottomNav.value) return 'bottom-nav';\n\n return collapsedState.value ? 'collapsed' : 'default';\n });\n\n const applyResponsiveState = () => {\n const useContainerBreakpoints = props['container-breakpoints'].value;\n const responsiveMatched = useContainerBreakpoints\n ? responsiveSizeMatches.value\n : responsiveMediaMatches.value || responsiveSizeMatches.value;\n const bottomMatched = useContainerBreakpoints\n ? bottomNavSizeMatches.value\n : bottomNavMediaMatches.value || bottomNavSizeMatches.value;\n\n // If the mobile drawer is currently open, stay in bottom-nav mode\n // regardless of the responsive match. This prevents the drawer from\n // disappearing mid-animation or if forced open via the API on desktop.\n if (!isMobileOpen.value) {\n isBottomNav.value = bottomMatched;\n }\n\n if (!bottomMatched && !isMobileOpen.value) {\n setMobileOpen(false, 'responsive');\n }\n\n if (hasResponsiveQuery.value) {\n setCollapsed(responsiveMatched, 'responsive');\n }\n };\n\n const readBottomNavItems = () => {\n const next = slots\n .elements()\n .value.filter(\n (el): el is HTMLElement => el instanceof HTMLElement && el.tagName.toLowerCase() === 'ore-sidebar-item',\n )\n .map((el, index) => {\n const iconSlotEl =\n (el.querySelector(':scope > [slot=\"icon\"]') as HTMLElement | null) ??\n (el.querySelector('[slot=\"icon\"]') as HTMLElement | null);\n const directIconName =\n iconSlotEl?.tagName.toLowerCase() === 'ore-icon' ? iconSlotEl.getAttribute('name') : null;\n const nestedIconName = iconSlotEl?.querySelector('ore-icon')?.getAttribute('name') ?? null;\n const rawLabel = (el.textContent ?? '').trim();\n\n return {\n active: el.hasAttribute('active'),\n disabled: el.hasAttribute('disabled'),\n href: el.getAttribute('href') ?? undefined,\n iconName: directIconName ?? nestedIconName ?? undefined,\n label: rawLabel || `Item ${index + 1}`,\n source: el,\n } satisfies BottomNavItem;\n });\n\n bottomNavItems.value = next;\n };\n\n provide(SIDEBAR_CTX, {\n collapsed: computed(() => !isBottomNav.value && collapsedState.value) as Readable<boolean>,\n mobileOpen: computed(() => isBottomNav.value && isMobileOpen.value) as Readable<boolean>,\n mode: mode as Readable<SidebarMode>,\n variant: props.variant,\n });\n\n const setCollapsed = (next: boolean, source: SidebarCollapseSource) => {\n if (isCollapsed() === next) return;\n\n if (!isControlled.value) {\n collapsedState.value = next;\n }\n\n emit('collapsed-change', { collapsed: next, source });\n };\n\n const setMobileOpen = (next: boolean, source: SidebarMobileSource) => {\n const open = Boolean(next);\n\n if (open && !isBottomNav.value) {\n isBottomNav.value = true;\n }\n\n if (!isBottomNav.value && !open) {\n if (isMobileOpen.value) {\n isMobileOpen.value = false;\n }\n\n return;\n }\n\n if (isMobileOpen.value === open) return;\n\n isMobileOpen.value = open;\n\n // If closing, re-evaluate responsive state to potentially exit forced bottom-nav mode\n if (!open) {\n applyResponsiveState();\n }\n\n emit('mobile-open-change', { open, source });\n };\n\n const doToggle = () => {\n setCollapsed(!isCollapsed(), 'toggle');\n };\n\n const sidebarEl = el as SidebarElement;\n\n sidebarEl.setCollapsed = (next) => setCollapsed(Boolean(next), 'api');\n sidebarEl.toggle = doToggle;\n sidebarEl.openMobile = () => setMobileOpen(true, 'api');\n sidebarEl.closeMobile = () => setMobileOpen(false, 'api');\n sidebarEl.toggleMobile = () => setMobileOpen(!isMobileOpen.value, 'toggle');\n\n bind({\n attr: {\n 'data-bottom-nav': () => (isBottomNav.value ? true : undefined),\n 'data-collapsed': () => (isCollapsed() && !isBottomNav.value ? true : undefined),\n 'data-mobile-open': () => (isBottomNav.value && isMobileOpen.value ? true : undefined),\n 'data-preview-mode': () => (isPreviewMode.value ? true : undefined),\n },\n });\n\n onMounted(() => {\n // Suppress transitions during initial layout so the sidebar doesn't\n // animate from a collapsed/0 state before the first ResizeObserver fires.\n el.setAttribute('data-no-transition', '');\n\n let transitionUnlocked = false;\n const unlockTransition = () => {\n if (transitionUnlocked) return;\n\n transitionUnlocked = true;\n el.removeAttribute('data-no-transition');\n };\n\n // Fallback: unlock after two frames in case ResizeObserver doesn't fire.\n requestAnimationFrame(() => requestAnimationFrame(unlockTransition));\n\n let mediaCleanup: (() => void) | undefined;\n let bottomNavCleanup: (() => void) | undefined;\n const itemObservers = new Map<HTMLElement, MutationObserver>();\n const observer = new MutationObserver(() => {\n if (!el.hasAttribute('collapsed') && !isControlled.value) return;\n\n isControlled.value = true;\n collapsedState.value = el.hasAttribute('collapsed');\n });\n\n observer.observe(el, {\n attributeFilter: ['collapsed'],\n attributes: true,\n });\n\n watch(\n props.responsive,\n (query) => {\n mediaCleanup?.();\n mediaCleanup = undefined;\n\n const mediaQuery = String(query ?? '').trim();\n\n hasResponsiveQuery.value = Boolean(mediaQuery);\n responsiveMaxWidthPx.value = parseMaxWidthPx(mediaQuery);\n responsiveMediaMatches.value = false;\n\n const width = readContainerWidth(el);\n\n responsiveSizeMatches.value =\n width > 0 && responsiveMaxWidthPx.value != null ? width <= responsiveMaxWidthPx.value : false;\n applyResponsiveState();\n\n // For parseable max-width queries, keep behavior container-driven.\n // This avoids preview viewport controls being overridden by window width.\n if (props['container-breakpoints'].value && responsiveMaxWidthPx.value != null) {\n return;\n }\n\n if (!mediaQuery) {\n return;\n }\n\n if (typeof window.matchMedia !== 'function') {\n return;\n }\n\n const mql = window.matchMedia(mediaQuery);\n const onChange = (event: MediaQueryListEvent) => {\n responsiveMediaMatches.value = event.matches;\n applyResponsiveState();\n };\n\n responsiveMediaMatches.value = mql.matches;\n applyResponsiveState();\n mql.addEventListener('change', onChange);\n\n mediaCleanup = () => {\n mql.removeEventListener('change', onChange);\n };\n },\n { immediate: true },\n );\n\n watch(\n props['bottom-nav-at'],\n (query) => {\n bottomNavCleanup?.();\n bottomNavCleanup = undefined;\n\n const mediaQuery = String(query ?? '').trim();\n\n bottomNavMaxWidthPx.value = parseMaxWidthPx(mediaQuery);\n bottomNavMediaMatches.value = false;\n\n const width = readContainerWidth(el);\n\n bottomNavSizeMatches.value =\n width > 0 && bottomNavMaxWidthPx.value != null ? width <= bottomNavMaxWidthPx.value : false;\n applyResponsiveState();\n\n // For parseable max-width queries, keep behavior container-driven.\n // This avoids preview viewport controls being overridden by window width.\n if (props['container-breakpoints'].value && bottomNavMaxWidthPx.value != null) {\n return;\n }\n\n if (!mediaQuery) {\n return;\n }\n\n if (typeof window.matchMedia !== 'function') {\n return;\n }\n\n const mql = window.matchMedia(mediaQuery);\n const onChange = (event: MediaQueryListEvent) => {\n bottomNavMediaMatches.value = event.matches;\n applyResponsiveState();\n };\n\n bottomNavMediaMatches.value = mql.matches;\n applyResponsiveState();\n\n mql.addEventListener('change', onChange);\n bottomNavCleanup = () => {\n mql.removeEventListener('change', onChange);\n };\n },\n { immediate: true },\n );\n\n const stopResizeEffect =\n typeof ResizeObserver === 'function'\n ? (() => {\n const hostSize = resizeObserver(el);\n const wrapperEl = el.parentElement;\n const containerEl = resolveContainerElement(el);\n const wrapperSize = wrapperEl ? resizeObserver(wrapperEl) : undefined;\n const parentSize = containerEl && containerEl !== wrapperEl ? resizeObserver(containerEl) : undefined;\n let rafId: number | undefined;\n\n const onResize = () => {\n if (rafId !== undefined) cancelAnimationFrame(rafId);\n\n rafId = requestAnimationFrame(() => {\n const resolvedContainer = resolveContainerElement(el);\n const width = readContainerWidth(el);\n const responsiveWasMatched = responsiveSizeMatches.value;\n const bottomNavWasMatched = bottomNavSizeMatches.value;\n const parentWidth = resolvedContainer?.clientWidth ?? 0;\n\n isPreviewMode.value = parentWidth > 0 && parentWidth < window.innerWidth;\n\n responsiveSizeMatches.value =\n width > 0 && responsiveMaxWidthPx.value != null ? width <= responsiveMaxWidthPx.value : false;\n bottomNavSizeMatches.value =\n width > 0 && bottomNavMaxWidthPx.value != null ? width <= bottomNavMaxWidthPx.value : false;\n\n if (\n responsiveWasMatched !== responsiveSizeMatches.value ||\n bottomNavWasMatched !== bottomNavSizeMatches.value\n ) {\n applyResponsiveState();\n }\n\n unlockTransition();\n });\n };\n\n return watch(\n computed(() => [\n hostSize.value.width,\n hostSize.value.height,\n wrapperSize?.value.width,\n wrapperSize?.value.height,\n parentSize?.value.width,\n parentSize?.value.height,\n ]),\n onResize,\n );\n })()\n : undefined;\n\n const bindItemObservers = (items: HTMLElement[]) => {\n const set = new Set(items);\n\n for (const [item, cleanup] of itemObservers) {\n if (set.has(item)) continue;\n\n cleanup.disconnect();\n itemObservers.delete(item);\n }\n\n for (const item of items) {\n if (itemObservers.has(item)) continue;\n\n const itemObserver = new MutationObserver(() => {\n // Only update if in bottom-nav mode to minimize re-renders\n if (isBottomNav.value) {\n readBottomNavItems();\n }\n });\n\n // Only watch attributes that affect bottom-nav rendering; skip childList/subtree/characterData\n itemObserver.observe(item, {\n attributeFilter: ['active', 'disabled', 'href'],\n attributes: true,\n });\n itemObservers.set(item, itemObserver);\n }\n };\n\n watch(\n slots.elements(),\n (elements) => {\n const directItems = elements.filter(\n (el): el is HTMLElement => el instanceof HTMLElement && el.tagName.toLowerCase() === 'ore-sidebar-item',\n );\n\n bindItemObservers(directItems);\n readBottomNavItems();\n },\n { immediate: true },\n );\n\n return () => {\n observer.disconnect();\n mediaCleanup?.();\n bottomNavCleanup?.();\n stopResizeEffect?.dispose();\n\n for (const itemObserver of itemObservers.values()) {\n itemObserver.disconnect();\n }\n\n itemObservers.clear();\n };\n });\n\n return html`\n <button\n class=\"mobile-backdrop\"\n part=\"mobile-backdrop\"\n type=\"button\"\n aria-label=\"Close sidebar\"\n ?hidden=${() => !isBottomNav.value || !isMobileOpen.value}\n @click=${() => setMobileOpen(false, 'toggle')}></button>\n <nav aria-label=\"${props.label}\" part=\"nav\">\n <div class=\"sidebar-header\" part=\"header\" ?hidden=${() => !hasHeader() && !props.collapsible.value}>\n <span class=\"sidebar-logo\" ?hidden=${() => !hasLogo()}>\n <slot name=\"logo\"></slot>\n </span>\n <span class=\"sidebar-header-content\">\n <slot name=\"header\"></slot>\n </span>\n <button\n class=\"toggle-btn\"\n part=\"toggle-btn\"\n type=\"button\"\n ?hidden=${() => !props.collapsible.value}\n aria-label=\"${() => (isCollapsed() ? 'Expand sidebar' : 'Collapse sidebar')}\"\n aria-expanded=\"${() => !isCollapsed()}\"\n @click=\"${doToggle}\">\n <span class=\"toggle-icon\" aria-hidden=\"true\">\n <ore-icon name=\"chevron-left\" size=\"16\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </span>\n </button>\n </div>\n <div class=\"sidebar-content\" part=\"content\">\n <slot></slot>\n </div>\n <div class=\"sidebar-footer\" part=\"footer\" ?hidden=${() => !hasFooter()}>\n <slot name=\"footer\"></slot>\n </div>\n </nav>\n\n <div class=\"bottom-bar\" part=\"bottom-bar\" ?hidden=${() => !isBottomNav.value}>\n ${() =>\n bottomNavItems.value.map((item) => {\n const className = `bottom-tab${item.active ? ' bottom-tab-active' : ''}`;\n\n if (item.href && !item.disabled) {\n return html`\n <a\n class=\"${className}\"\n href=\"${item.href}\"\n aria-current=\"${item.active ? 'page' : null}\"\n data-active=\"${item.active ? 'true' : null}\">\n <span class=\"bottom-tab-icon\" aria-hidden=\"true\" ?hidden=${() => !item.iconName}>\n <ore-icon :name=\"${item.iconName}\" size=\"18\" stroke-width=\"2\"></ore-icon>\n </span>\n <span class=\"bottom-tab-label\">${item.label}</span>\n </a>\n `;\n }\n\n return html`\n <button\n class=\"${className}\"\n type=\"button\"\n ?disabled=${item.disabled}\n aria-current=\"${item.active ? 'page' : null}\"\n data-active=\"${item.active ? 'true' : null}\"\n @click=${() => item.source.click()}>\n <span class=\"bottom-tab-icon\" aria-hidden=\"true\" ?hidden=${() => !item.iconName}>\n <ore-icon :name=\"${item.iconName}\" size=\"18\" stroke-width=\"2\"></ore-icon>\n </span>\n <span class=\"bottom-tab-label\">${item.label}</span>\n </button>\n `;\n })}\n </div>\n `;\n },\n styles: [coarsePointerMixin, reducedMotionMixin, sidebarStyles],\n});\n\n// ─── ore-sidebar-group styles ────────────────────────────────────────────────\n\n/** Sidebar group properties */\nexport type OreSidebarGroupProps = {\n /** Whether this group can be collapsed */\n collapsible?: boolean;\n /** Initial open state in uncontrolled mode */\n 'default-open'?: boolean;\n /** Accessible label for the group */\n label?: string;\n /** Controlled open state */\n open?: boolean;\n};\n\n/**\n * `ore-sidebar-group` — A labelled section within `ore-sidebar`.\n *\n * @element ore-sidebar-group\n *\n * @attr {string} label - Group label text\n * @attr {boolean} collapsible - Whether this group can be toggled open/closed\n * @attr {boolean} open - Controlled expanded state\n * @attr {boolean} default-open - Initial expanded state in uncontrolled mode\n *\n * @fires open-change - Fired when the group open state changes (collapsible groups only). detail: { open: boolean }\n *\n * @slot - Navigation items (`ore-sidebar-item`)\n * @slot icon - Icon displayed before the label\n *\n * @example\n * ```html\n * <ore-sidebar-group label=\"Main\" collapsible open>\n * <ore-sidebar-item href=\"/home\">Home</ore-sidebar-item>\n * </ore-sidebar-group>\n * ```\n */\nexport const SIDEBAR_GROUP_TAG = 'ore-sidebar-group' as const;\ndefine<OreSidebarGroupProps, OreSidebarGroupEvents>(SIDEBAR_GROUP_TAG, {\n props: {\n collapsible: prop.bool(false),\n 'default-open': prop.bool(true),\n label: prop.string(),\n open: {\n default: undefined as boolean | undefined,\n parse: (value: string | null) => (value == null ? undefined : value === '' || value === 'true'),\n reflect: false,\n },\n },\n setup(props, { bind, slots }) {\n const hasIcon = () => slots.has('icon').value;\n const sidebarCtx = inject(SIDEBAR_CTX);\n\n bind({\n attr: {\n 'sidebar-bottom-nav': () =>\n sidebarCtx?.mode.value === 'bottom-nav' && !sidebarCtx?.mobileOpen.value ? true : undefined,\n 'sidebar-collapsed': () => (sidebarCtx?.collapsed.value ? true : undefined),\n },\n });\n\n const isControlled = () => props.open.value !== undefined;\n const openState = signal(props['default-open'].value);\n const isOpen = computed(() => {\n if (!props.collapsible.value) return true;\n\n if (isControlled()) return props.open.value ?? false;\n\n return openState.value;\n });\n\n watch(props.open, (value) => {\n if (value === undefined) return;\n\n openState.value = value;\n });\n\n bind({\n attr: {\n open: () => (isOpen.value ? true : undefined),\n },\n });\n\n return html`\n <details class=\"group\" part=\"group\" ?open=${isOpen}>\n <summary\n class=\"group-header\"\n part=\"group-header\"\n aria-expanded=\"${() => (props.collapsible.value ? String(props.open.value) : null)}\"\n @click=${(e: MouseEvent) => {\n if (!props.collapsible.value) {\n e.preventDefault();\n }\n }}>\n <span class=\"group-icon\" part=\"group-icon\" ?hidden=${() => !hasIcon()} aria-hidden=\"true\">\n <slot name=\"icon\"></slot>\n </span>\n <span class=\"group-label\" part=\"group-label\">${props.label}</span>\n <span class=\"chevron\" ?hidden=${() => !props.collapsible.value} aria-hidden=\"true\">\n <ore-icon name=\"chevron-right\" size=\"12\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </span>\n </summary>\n <div class=\"group-items\" part=\"group-items\" role=\"list\">\n <slot></slot>\n </div>\n </details>\n `;\n },\n styles: [reducedMotionMixin, groupStyles],\n});\n\n// ─── ore-sidebar-item styles ─────────────────────────────────────────────────\n\n/** Sidebar item properties */\nexport type OreSidebarItemProps = {\n /** Whether this item represents the current page/section */\n active?: boolean;\n /** Whether this item is disabled */\n disabled?: boolean;\n /** Navigation href — renders an `<a>` when set, otherwise a `<button>` */\n href?: string;\n /**\n * Relationship of the linked URL (`rel` attribute on the inner `<a>`).\n * Only applies when `href` is set.\n */\n rel?: string;\n /**\n * Browsing context for the link (`target` attribute on the inner `<a>`).\n * Only applies when `href` is set.\n */\n target?: string;\n};\n\n/**\n * `ore-sidebar-item` — An individual navigation item in a `ore-sidebar`.\n *\n * Renders as an `<a>` when `href` is provided, otherwise as a `<button>`.\n * Marks the active page via `aria-current=\"page\"` when the `active` attribute is set.\n *\n * @element ore-sidebar-item\n *\n * @attr {string} href - Link URL; renders an anchor when set\n * @attr {boolean} active - Marks the item as the current page\n * @attr {boolean} disabled - Disables the item\n * @attr {string} rel - Anchor `rel` attribute (links only)\n * @attr {string} target - Anchor `target` attribute (links only)\n *\n * @slot - Label text\n * @slot icon - Leading icon\n * @slot end - Trailing content (badge, shortcut, arrow, etc.)\n *\n * @cssprop --sidebar-item-color - Default text color\n * @cssprop --sidebar-item-hover-bg - Hover background\n * @cssprop --sidebar-item-hover-color - Hover text color\n * @cssprop --sidebar-item-active-bg - Active background\n * @cssprop --sidebar-item-active-color - Active text color\n * @cssprop --sidebar-item-indicator - Active indicator bar color\n *\n * @part item - The inner anchor or button element\n * @part item-icon - The icon wrapper\n * @part item-label - The label wrapper\n * @part item-end - The trailing content wrapper\n *\n * @example\n * ```html\n * <ore-sidebar-item href=\"/dashboard\" active>\n * <span slot=\"icon\">🏠</span>\n * Dashboard\n * </ore-sidebar-item>\n *\n * <ore-sidebar-item href=\"/users\">\n * <span slot=\"icon\">👤</span>\n * Users\n * <ore-badge slot=\"end\" color=\"primary\">3</ore-badge>\n * </ore-sidebar-item>\n * ```\n */\nexport const SIDEBAR_ITEM_TAG = 'ore-sidebar-item' as const;\ndefine<OreSidebarItemProps>(SIDEBAR_ITEM_TAG, {\n props: {\n active: prop.bool(false),\n disabled: prop.bool(false),\n href: prop.string(),\n rel: prop.string(),\n target: prop.string(),\n },\n setup(props, { bind, slots }) {\n const hasIcon = () => slots.has('icon').value;\n const hasEnd = () => slots.has('end').value;\n const sidebarCtx = inject(SIDEBAR_CTX);\n\n bind({\n attr: {\n 'sidebar-bottom-nav': () =>\n sidebarCtx?.mode.value === 'bottom-nav' && !sidebarCtx?.mobileOpen.value ? true : undefined,\n 'sidebar-collapsed': () => (sidebarCtx?.collapsed.value ? true : undefined),\n },\n });\n\n const isLink = () => !!props.href.value && !props.disabled.value;\n\n // Prevent reverse tabnapping: auto-inject noopener + noreferrer for _blank links.\n const effectiveRel = computed(() => computeSafeRel(props.rel.value, props.target.value));\n\n const renderItemContent = () => html`\n <span class=\"item-icon\" part=\"item-icon\" ?hidden=${() => !hasIcon()} aria-hidden=\"true\">\n <slot name=\"icon\"></slot>\n </span>\n <span class=\"item-label\" part=\"item-label\"><slot></slot></span>\n <span class=\"item-end\" part=\"item-end\" ?hidden=${() => !hasEnd()}>\n <slot name=\"end\"></slot>\n </span>\n `;\n\n return html`\n ${() => {\n if (isLink()) {\n return html`\n <a\n class=\"item\"\n part=\"item\"\n href=\"${props.href}\"\n :rel=\"${effectiveRel}\"\n :target=\"${props.target}\"\n aria-current=\"${() => (props.active.value ? 'page' : null)}\">\n ${renderItemContent()}\n </a>\n `;\n }\n\n if (props.disabled.value) {\n return html`\n <div\n class=\"item\"\n part=\"item\"\n aria-disabled=\"true\"\n tabindex=\"-1\"\n aria-current=\"${() => (props.active.value ? 'page' : null)}\">\n ${renderItemContent()}\n </div>\n `;\n }\n\n return html`\n <button\n class=\"item\"\n part=\"item\"\n type=\"button\"\n ?disabled=\"${props.disabled}\"\n aria-current=\"${() => (props.active.value ? 'page' : null)}\">\n ${renderItemContent()}\n </button>\n `;\n }}\n `;\n },\n styles: [coarsePointerMixin, itemStyles],\n});\n","/**\n * Shared background-lock utility for overlay components (dialog, drawer, etc.).\n *\n * Uses a reference count so that multiple stacked overlays each call\n * lock / unlock independently without interfering with each other. The `inert`\n * attribute is applied once when the first overlay opens and removed once the\n * last one closes.\n *\n * The factory pattern (`createBackgroundLock`) provides test-isolated instances.\n * The module-level `lockBackground` / `unlockBackground` are the defaults used\n * by all runtime components.\n */\n\nexport type BackgroundLock = {\n lock(host: Element): void;\n unlock(): void;\n};\n\nexport function createBackgroundLock(): BackgroundLock {\n let lockCount = 0;\n let lockedEls: Element[] = [];\n\n return {\n lock(host: Element): void {\n if (lockCount === 0) {\n let ancestor: Element = host;\n\n while (ancestor.parentElement && ancestor.parentElement !== document.body) {\n ancestor = ancestor.parentElement;\n }\n\n lockedEls = Array.from(document.body.children).filter((el) => el !== ancestor && !el.hasAttribute('inert'));\n\n for (const el of lockedEls) el.setAttribute('inert', '');\n }\n\n lockCount++;\n },\n\n unlock(): void {\n lockCount = Math.max(0, lockCount - 1);\n\n if (lockCount === 0) {\n for (const el of lockedEls) el.removeAttribute('inert');\n lockedEls = [];\n }\n },\n };\n}\n\nconst _default = createBackgroundLock();\n\n/** Marks sibling elements as inert. Safe to call from multiple concurrent overlays. */\nexport const lockBackground = (host: Element): void => _default.lock(host);\n\n/** Releases the background lock. Removes inert when all overlays have closed. */\nexport const unlockBackground = (): void => _default.unlock();\n","import { type Readable, type Signal, signal, watch } from '@vielzeug/ripple';\n\nimport {\n lifecycleSignal,\n createOverlayControl,\n type DialogCloseReason,\n type OverlayControl,\n type OverlayOpenReason,\n} from '../../headless';\nimport { createFocusManager } from '../../headless/focus';\nimport { awaitExit } from './await-exit';\nimport { createBackgroundLock } from './background-lock';\n\n// Invoker Commands API — not yet in lib.dom.d.ts\ninterface CommandEvent extends Event {\n command: string;\n}\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport type UseDialogOptions = {\n /** Called after showModal() but before isOpen = true. Use to clear drag styles etc. */\n beforeOpen?: (dialog: HTMLDialogElement) => void;\n /** Extra properties merged into the `close-request` custom event detail. */\n closeRequestDetail?: (reason: Exclude<DialogCloseReason, 'programmatic'>) => Record<string, unknown>;\n dialogRef: { value: HTMLDialogElement | null | undefined };\n getPanelEl: () => HTMLElement | null | undefined;\n host: HTMLElement;\n initialFocus: Readable<string | undefined>;\n isPersistent: () => boolean;\n /** Cleanup registrar from the component setup ctx. Automatically called on disconnect. */\n onCleanup: (fn: () => void) => void;\n /**\n * Scoped event listener registrar from the component setup ctx.\n * Automatically removed on component disconnect.\n */\n onEvent: <K extends keyof HTMLElementEventMap>(\n target: EventTarget | null | undefined,\n event: K,\n listener: (e: HTMLElementEventMap[K]) => void,\n options?: AddEventListenerOptions,\n ) => void;\n /**\n * Called after the native `close` event fires — after background unlock,\n * isOpen reset, and focus restore. Use to emit component events.\n */\n onNativeClose?: (reason: DialogCloseReason) => void;\n /** Called by the overlay on open. Use to emit events. */\n onOpen?: (reason: OverlayOpenReason) => void;\n /** Open prop from the component — drives programmatic open/close via watch. */\n openProp: Readable<boolean | undefined>;\n /**\n * Called by the overlay when closing. Orchestrates the close animation.\n * Default: `dialog.close()`. Override in dialog.ts to add the CSS exit animation.\n */\n performClose?: (dialog: HTMLDialogElement, reason: DialogCloseReason) => void;\n returnFocus: Readable<boolean | undefined>;\n};\n\nexport type UseDialogHandle = {\n closeWithAnimation: () => void;\n /**\n * Dispatch a cancelable `close-request` event on the host. Returns true when\n * the close is allowed (event not prevented), false when it was cancelled.\n */\n dispatchCloseRequest: (reason: Exclude<DialogCloseReason, 'programmatic'>) => boolean;\n handleBackdropClick: (e: MouseEvent) => void;\n handleCancel: (e: Event) => void;\n isOpen: Signal<boolean>;\n /** The overlay control — open/close/toggle/dispose. */\n overlay: OverlayControl;\n /**\n * Dispatch `close-request`; if allowed, call `overlay.close()`.\n */\n requestClose: (reason: Exclude<DialogCloseReason, 'programmatic'>) => void;\n /**\n * Registers the open-prop watcher AND standard click/cancel event listeners on\n * the dialog element (backdrop click-to-close, Escape via the native `cancel`\n * event). Use for components that need standard dialog behavior.\n * Call inside `onMounted()`.\n */\n setupNativeListeners: () => void;\n /**\n * Registers only the open-prop watcher (without adding click/cancel listeners).\n * Use for components like drawer that register their own event handlers.\n * Call inside `onMounted()`.\n */\n watchOpenProp: () => void;\n};\n\n// ── Factory ───────────────────────────────────────────────────────────────────\n\n/**\n * Shared dialog-control composable for `ore-dialog` and `ore-drawer`.\n *\n * Owns: `isOpen`, close-reason tracking, focus management, `overlay`,\n * `requestClose`, background lock/unlock, and the `close` event handler.\n * Components supply only their unique behavior via callbacks and `onNativeClose`.\n */\nexport function useDialogControl(options: UseDialogOptions): UseDialogHandle {\n const abortSignal = lifecycleSignal(options.onCleanup);\n const isOpen = signal(false);\n // Internal close-reason: set atomically before dialog.close() fires.\n let pendingCloseReason: DialogCloseReason = 'programmatic';\n const bgLock = createBackgroundLock();\n let isClosing = false;\n\n // ── Focus management ──────────────────────────────────────────────────────\n const focus = createFocusManager({\n getInitialFocusSelector: () => options.initialFocus.value,\n getReturnFocus: () => options.returnFocus.value,\n host: options.host,\n });\n // ─────────────────────────────────────────────────────────────────────────\n\n const closeWithAnimation = (): void => {\n const dialog = options.dialogRef.value;\n\n if (!dialog?.open || isClosing) return;\n\n isClosing = true;\n dialog.classList.add('closing');\n\n const finish = () => {\n dialog.close();\n // Do NOT remove 'closing' here — removing it while the native ::backdrop is\n // still held in the top layer by the 'overlay allow-discrete' transition\n // would revert its opacity to 1 and cause a visible flash. The class is\n // cleaned up at the start of the next open cycle (see setOpen below).\n isClosing = false;\n };\n\n const panel = options.getPanelEl();\n\n if (panel) {\n awaitExit(panel, finish, 'transition');\n } else {\n finish();\n }\n };\n\n const dispatchCloseRequest = (reason: Exclude<DialogCloseReason, 'programmatic'>): boolean => {\n return options.host.dispatchEvent(\n new CustomEvent('close-request', {\n bubbles: true,\n cancelable: true,\n composed: true,\n detail: { reason, ...options.closeRequestDetail?.(reason) },\n }),\n );\n };\n\n const overlay = createOverlayControl({\n getBoundary: () => options.host,\n getPanel: () => {\n const panel = options.getPanelEl();\n\n return panel instanceof HTMLElement ? panel : null;\n },\n isOpen: () => isOpen.value,\n onOpen: options.onOpen,\n setOpen: (next, reason) => {\n const dialog = options.dialogRef.value;\n\n if (!dialog) return;\n\n if (next) {\n if (dialog.open) return;\n\n // Clean up any leftover 'closing' class from the previous close animation\n // before opening so the entry @starting-style and transition work correctly.\n dialog.classList.remove('closing');\n focus.captureReturnFocus();\n options.beforeOpen?.(dialog);\n dialog.showModal();\n bgLock.lock(options.host);\n focus.applyInitialFocus();\n isOpen.value = true;\n\n return;\n }\n\n if (dialog.open) {\n // Capture reason before calling performClose so handleNativeClose can read it.\n pendingCloseReason = reason as DialogCloseReason;\n\n const performClose = options.performClose ?? ((d) => d.close());\n\n performClose(dialog, reason as DialogCloseReason);\n\n return;\n }\n\n isOpen.value = false;\n },\n signal: abortSignal,\n });\n\n const requestClose = (reason: Exclude<DialogCloseReason, 'programmatic'>): void => {\n const allowed = dispatchCloseRequest(reason);\n\n if (!allowed) return;\n\n overlay.close(reason, false);\n };\n\n // Invoker Commands API — allows declarative open/close from outside the component:\n // <button commandfor=\"ore-dialog-id\" command=\"show-modal\">Open</button>\n // <button commandfor=\"ore-dialog-id\" command=\"close\">Close</button>\n options.host.addEventListener(\n 'command',\n (e: Event) => {\n const cmd = (e as CommandEvent).command;\n\n if (cmd === 'show-modal') overlay.open('trigger');\n else if (cmd === 'close' || cmd === 'request-close') requestClose('trigger');\n },\n { signal: abortSignal },\n );\n\n // The native `<dialog>` element auto-closes on Escape via its own close-watcher, which\n // dispatches a cancelable `cancel` event before `close`. Suppressing/redirecting that is the\n // spec-correct hook — relying on `keydown`'s `preventDefault()` to stop the close-watcher is\n // implementation-specific, not guaranteed across browsers.\n const handleCancel = (e: Event): void => {\n e.preventDefault();\n\n if (options.isPersistent()) return;\n\n requestClose('escape');\n };\n\n const handleBackdropClick = (e: MouseEvent): void => {\n if (options.isPersistent()) return;\n\n if (e.target === options.dialogRef.value) requestClose('outsideClick');\n };\n\n // ── Internal native close handler ─────────────────────────────────────────\n const handleNativeClose = (): void => {\n bgLock.unlock();\n options.host.removeAttribute('open');\n isOpen.value = false;\n focus.restoreFocus();\n\n const reason = pendingCloseReason;\n\n pendingCloseReason = 'programmatic';\n options.onNativeClose?.(reason);\n };\n\n const watchOpenProp = (): void => {\n const dialog = options.dialogRef.value;\n\n if (dialog) options.onEvent(dialog, 'close', handleNativeClose);\n\n watch(\n options.openProp,\n (open) => {\n if (open) {\n overlay.open('programmatic');\n } else {\n overlay.close('programmatic', false);\n }\n },\n { immediate: true },\n );\n };\n\n const setupNativeListeners = (): void => {\n const dialog = options.dialogRef.value;\n\n if (!dialog) return;\n\n watchOpenProp();\n options.onEvent(dialog, 'click', handleBackdropClick);\n options.onEvent(dialog, 'cancel', handleCancel);\n };\n\n return {\n closeWithAnimation,\n dispatchCloseRequest,\n handleBackdropClick,\n handleCancel,\n isOpen,\n overlay,\n requestClose,\n setupNativeListeners,\n watchOpenProp,\n };\n}\n","@layer refine.base {\n :host {\n --_radius: var(--dialog-radius, var(--rounded-lg));\n --_padding: var(--dialog-padding, var(--size-4));\n --_gap: var(--dialog-gap, var(--size-4));\n --_max-width: var(--dialog-max-width, 32rem);\n --_elevation: var(--shadow-xl);\n --_backdrop-filter: none;\n --_backdrop-bg: var(--dialog-backdrop, color-mix(in oklch, var(--color-canvas) 40%, transparent));\n --_panel-bg: var(--dialog-bg, var(--color-canvas));\n --_panel-blur: var(--dialog-panel-blur, var(--blur-md));\n --_panel-border-color: var(--dialog-border-color, var(--color-divider));\n\n display: contents;\n }\n\n /* =====================\n Native <dialog> resets\n ===================== */\n\n dialog {\n all: unset;\n position: fixed;\n inset: 0;\n box-sizing: border-box;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n max-width: 100%;\n height: 100%;\n max-height: 100%;\n padding: 0;\n margin: 0;\n overflow: hidden;\n pointer-events: none;\n background: transparent;\n border: none;\n\n /* display + overlay allow-discrete hold the element in the top layer during exit\n and let @starting-style fire on entry via showModal().\n Use fixed 200ms — --transition-normal resolves to 'none' under reduced-motion\n which makes the entire declaration syntactically invalid if used here. */\n transition:\n display 200ms allow-discrete,\n overlay 200ms allow-discrete;\n }\n\n /* all:unset removes the UA stylesheet's dialog:not([open]){display:none} — restore it */\n dialog:not([open]) {\n display: none;\n }\n\n dialog:not([open]) .panel {\n display: none;\n }\n\n dialog[open] {\n pointer-events: auto;\n }\n\n dialog::backdrop {\n background: var(--_backdrop-bg);\n opacity: 1;\n backdrop-filter: var(--_backdrop-filter);\n transition:\n opacity var(--transition-normal),\n overlay var(--transition-normal) allow-discrete,\n display var(--transition-normal) allow-discrete;\n\n @starting-style {\n opacity: 0;\n }\n }\n\n dialog.closing::backdrop {\n opacity: 0;\n transition:\n opacity 150ms var(--ease-in-out),\n overlay 150ms allow-discrete,\n display 150ms allow-discrete;\n }\n\n /* =====================\n Panel (the visible dialog box)\n ===================== */\n\n .panel {\n position: relative;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n width: var(--_max-width);\n max-width: calc(100vw - var(--size-8));\n max-height: calc(100dvh - var(--size-8));\n overflow: hidden;\n background: var(--_panel-bg);\n border: var(--border) solid var(--_panel-border-color);\n border-radius: var(--_radius);\n box-shadow: var(--dialog-shadow, var(--_elevation));\n opacity: 1;\n backdrop-filter: blur(var(--_panel-blur));\n transform: scale(1) translateY(0);\n transition:\n opacity 200ms var(--ease-spring),\n transform 200ms var(--ease-spring);\n\n @starting-style {\n opacity: 0;\n transform: scale(var(--overlay-enter-scale-dialog)) translateY(4px);\n }\n }\n\n dialog.closing .panel {\n opacity: 0;\n transform: scale(var(--overlay-enter-scale-dialog)) translateY(4px);\n transition:\n opacity 150ms var(--ease-spring),\n transform 150ms var(--ease-spring);\n }\n\n /* =====================\n Sizes\n ===================== */\n\n .panel[data-size='sm'] {\n --_max-width: var(--dialog-max-width, 22rem);\n }\n\n .panel[data-size='md'] {\n --_max-width: var(--dialog-max-width, 32rem);\n }\n\n .panel[data-size='lg'] {\n --_max-width: var(--dialog-max-width, 48rem);\n }\n\n .panel[data-size='xl'] {\n --_max-width: var(--dialog-max-width, 64rem);\n }\n\n .panel[data-size='full'] {\n width: calc(100vw - var(--size-8));\n max-width: calc(100vw - var(--size-8));\n max-height: calc(100dvh - var(--size-8));\n }\n\n /* =====================\n Header\n ===================== */\n\n .header {\n display: flex;\n flex-shrink: 0;\n gap: var(--size-2);\n align-items: center;\n padding: var(--_padding);\n padding-bottom: 0;\n }\n\n .header[hidden] {\n display: none;\n }\n\n .title {\n flex: 1;\n font-size: var(--text-lg);\n font-weight: var(--font-semibold);\n line-height: var(--leading-tight);\n color: var(--color-contrast-900);\n }\n\n .close {\n display: inline-flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n width: var(--size-8);\n min-width: var(--_touch-target);\n height: var(--size-8);\n min-height: var(--_touch-target);\n padding: 0;\n margin-inline-start: auto;\n color: var(--color-contrast-500);\n cursor: pointer;\n background: transparent;\n border: none;\n border-radius: var(--rounded-md);\n transition:\n background var(--transition-fast),\n color var(--transition-fast);\n }\n\n .close:hover {\n color: var(--color-contrast-900);\n background: var(--color-contrast-200);\n }\n\n .close:focus-visible {\n outline: var(--border-2) solid var(--color-focus);\n outline-offset: var(--border-2);\n }\n\n .close[hidden] {\n display: none;\n }\n\n /* =====================\n Body\n ===================== */\n\n .body {\n flex: 1;\n padding: var(--_padding);\n overflow-y: auto;\n overscroll-behavior: contain;\n font-size: var(--text-sm);\n line-height: var(--leading-relaxed);\n color: var(--color-contrast-700);\n }\n\n /* =====================\n Footer\n ===================== */\n\n .footer {\n display: flex;\n flex-shrink: 0;\n flex-wrap: wrap;\n gap: var(--_gap);\n align-items: center;\n justify-content: flex-end;\n padding: var(--_padding);\n padding-top: 0;\n }\n\n .footer[hidden] {\n display: none;\n }\n\n /* =====================\n Dividers when header/footer present\n ===================== */\n\n .header:not([hidden]) + .body {\n padding-top: var(--size-4);\n }\n\n .body + .footer:not([hidden]) {\n padding-top: var(--size-4);\n border-top: var(--border) solid var(--color-contrast-100);\n }\n\n @media (width <= 640px) {\n .panel,\n .panel[data-size='sm'],\n .panel[data-size='md'],\n .panel[data-size='lg'],\n .panel[data-size='xl'] {\n width: calc(100vw - var(--size-4));\n max-width: calc(100vw - var(--size-4));\n max-height: calc(100dvh - var(--size-4));\n }\n\n .header,\n .body,\n .footer {\n padding-inline: var(--size-3);\n }\n }\n}\n\n@layer refine.config {\n :host([backdrop='blur']) {\n --_backdrop-filter: blur(var(--blur-xs));\n }\n\n :host([backdrop='transparent']) {\n --_backdrop-bg: transparent;\n }\n\n /* Panel elevation / shadow scale */\n :host([elevation='none']) {\n --_elevation: var(--shadow-none);\n }\n\n :host([elevation='sm']) {\n --_elevation: var(--shadow-sm);\n }\n\n :host([elevation='md']) {\n --_elevation: var(--shadow-md);\n }\n\n :host([elevation='lg']) {\n --_elevation: var(--shadow-lg);\n }\n\n :host([elevation='xl']) {\n --_elevation: var(--shadow-xl);\n }\n\n :host([elevation='2xl']) {\n --_elevation: var(--shadow-2xl);\n }\n\n /* Padding scale */\n :host([padding='none']) {\n --_padding: var(--size-0);\n }\n\n :host([padding='sm']) {\n --_padding: var(--size-3);\n }\n\n :host([padding='md']) {\n --_padding: var(--size-4);\n }\n\n :host([padding='lg']) {\n --_padding: var(--size-6);\n }\n\n :host([padding='xl']) {\n --_padding: var(--size-8);\n }\n}\n","import { define, html, prop, ref } from '@vielzeug/ore';\n\nimport type { OverlayCloseDetail, OverlayOpenDetail } from '../../headless';\nimport type { PaddingSize, RoundedSize } from '../../types';\n\nimport { coarsePointerMixin, roundedVariantMixin } from '../../styles';\nimport { useDialogControl } from '../shared/use-dialog';\nimport '../../content/icon/icon';\nimport componentStyles from './dialog.css?inline';\n\ntype DialogSize = 'sm' | 'md' | 'lg' | 'xl' | 'full';\ntype DialogBackdrop = 'opaque' | 'blur' | 'transparent';\ntype DialogElevation = 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n\n/** Dialog component properties */\n\nexport type OreDialogEvents = {\n close: OverlayCloseDetail;\n open: OverlayOpenDetail;\n};\n\nexport type OreDialogProps = {\n /** Backdrop style — 'blur' (default): dark overlay + blur; 'opaque': dark overlay only; 'transparent': no overlay */\n backdrop?: DialogBackdrop;\n /** Show a close (×) button in the header */\n dismissible?: boolean;\n /** Panel shadow elevation — defaults to 'xl' */\n elevation?: DialogElevation;\n /**\n * CSS selector for the element inside the dialog that should receive focus when the dialog opens.\n * Defaults to the first focusable element (browser default).\n * @example 'input[name=\"email\"]' | '#confirm-btn'\n */\n 'initial-focus'?: string;\n /** Dialog title shown in the header (used as aria-label when no header slot) */\n label?: string;\n /** Controls the open state of the dialog */\n open?: boolean;\n /** Internal padding size */\n padding?: PaddingSize;\n /** When true, clicking the backdrop does not close the dialog */\n persistent?: boolean;\n /**\n * When true (default), the focus returns to the element that triggered the dialog after it closes.\n * Set to false if you want to manage focus manually.\n */\n 'return-focus'?: boolean;\n /** Border radius */\n rounded?: RoundedSize | '';\n /** Dialog size */\n size?: DialogSize;\n};\n\n/**\n * A modal dialog that traps focus, blocks page interaction, and dismisses on\n * `Escape`. Built on the native `<dialog>` element for correct top-layer stacking\n * and browser-managed accessibility.\n *\n * @element ore-dialog\n *\n * @attr {boolean} open - Open/close the dialog\n * @attr {string} label - Dialog title (also used as aria-label)\n * @attr {string} size - Size: 'sm' | 'md' | 'lg' | 'xl' | 'full'\n * @attr {boolean} dismissible - Show a close (×) button in the header\n * @attr {boolean} persistent - Prevent backdrop-click from closing\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n * @attr {string} backdrop - Backdrop style: 'opaque' (default) | 'blur' | 'transparent'\n * @attr {string} elevation - Panel shadow: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'\n * @attr {string} padding - Padding: 'none' | 'sm' | 'md' | 'lg' | 'xl'\n *\n * @fires open - Fired when the dialog opens with detail: { reason }\n * @fires close - Fired when the dialog closes with detail: { reason }\n *\n * @slot - Dialog body content\n * @slot header - Custom header content (replaces the default title + close layout)\n * @slot footer - Action buttons or additional content at the bottom\n *\n * @cssprop --dialog-bg - Panel background color\n * @cssprop --dialog-border-color - Panel border color\n * @cssprop --dialog-radius - Panel border radius\n * @cssprop --dialog-shadow - Panel drop shadow\n * @cssprop --dialog-padding - Padding for header, body, and footer sections\n * @cssprop --dialog-gap - Gap between footer action buttons\n * @cssprop --dialog-backdrop - Backdrop overlay color\n * @cssprop --dialog-max-width - Maximum panel width (overridden by size prop)\n *\n * @part dialog - Dialog root container.\n * @part overlay - Overlay backdrop element.\n * @part panel - Panel container.\n * @part header - Header container.\n * @part title - Title text element.\n * @part close - Close action control.\n * @part body - Body content container.\n * @part footer - Footer container.\n * @example\n * ```html\n * <ore-dialog label=\"Confirm action\" dismissible>\n * <p>Are you sure you want to delete this item?</p>\n * <div slot=\"footer\">\n * <ore-button variant=\"ghost\" id=\"cancel\">Cancel</ore-button>\n * <ore-button color=\"error\" id=\"confirm\">Delete</ore-button>\n * </div>\n * </ore-dialog>\n *\n * <script type=\"module\">\n * import '@vielzeug/refine/dialog';\n * const dialog = document.querySelector('ore-dialog');\n * document.querySelector('#open-btn').addEventListener('click', () => {\n * dialog.setAttribute('open', '');\n * });\n * document.querySelector('#cancel').addEventListener('click', () => {\n * dialog.removeAttribute('open');\n * });\n * </script>\n * ```\n */\n\nexport const DIALOG_TAG = 'ore-dialog' as const;\ndefine<OreDialogProps, OreDialogEvents>(DIALOG_TAG, {\n props: {\n backdrop: prop.string<DialogBackdrop>(),\n dismissible: prop.bool(false),\n elevation: prop.string<DialogElevation>(),\n 'initial-focus': prop.string(),\n label: prop.string(),\n open: prop.bool(false),\n padding: prop.string<PaddingSize>(),\n persistent: prop.bool(false),\n 'return-focus': prop.bool(true),\n rounded: prop.string<RoundedSize | ''>(),\n size: prop.oneOf(['sm', 'md', 'lg', 'xl', 'full'] as const, 'md'),\n },\n setup(props, { el, emit, onCleanup, onEvent, onMounted, slots }) {\n const dialogRef = ref<HTMLDialogElement>();\n const hasHeader = () => slots.has('header').value || !!props.label.value || props.dismissible.value;\n const hasFooter = () => slots.has('footer').value;\n\n const { closeWithAnimation, overlay, requestClose, setupNativeListeners } = useDialogControl({\n dialogRef,\n getPanelEl: () => dialogRef.value?.querySelector<HTMLElement>('.panel'),\n host: el,\n initialFocus: props['initial-focus'],\n isPersistent: () => Boolean(props.persistent.value),\n onCleanup,\n onEvent,\n onNativeClose: (reason) => emit('close', { reason }),\n onOpen: (reason) => emit('open', { reason }),\n openProp: props.open,\n performClose: () => {\n closeWithAnimation();\n },\n returnFocus: props['return-focus'],\n });\n\n const handleDismiss = () => {\n requestClose('trigger');\n };\n\n onMounted(() => {\n const dialog = dialogRef.value;\n\n if (!dialog) return;\n\n setupNativeListeners();\n\n return () => {\n overlay.dispose();\n };\n });\n\n return html`\n <dialog ref=${dialogRef} class=\"dialog\" part=\"dialog\" aria-label=\"${props.label}\" aria-modal=\"true\">\n <div class=\"overlay\" part=\"overlay\" aria-hidden=\"true\"></div>\n <div class=\"panel\" part=\"panel\" :data-size=\"${props.size}\">\n <div class=\"header\" part=\"header\" ?hidden=${() => !hasHeader()}>\n <slot name=\"header\">\n <span class=\"title\" part=\"title\">${props.label}</span>\n </slot>\n <button\n class=\"close\"\n part=\"close\"\n type=\"button\"\n aria-label=\"Close dialog\"\n ?hidden=${() => !props.dismissible.value}\n @click=${handleDismiss}>\n <ore-icon name=\"x\" size=\"16\" stroke-width=\"2.5\" aria-hidden=\"true\"></ore-icon>\n </button>\n </div>\n <div class=\"body\" part=\"body\">\n <slot></slot>\n </div>\n <div class=\"footer\" part=\"footer\" ?hidden=${() => !hasFooter()}>\n <slot name=\"footer\"></slot>\n </div>\n </div>\n </dialog>\n `;\n },\n styles: [roundedVariantMixin, coarsePointerMixin, componentStyles],\n});\n","@layer refine.base {\n :host {\n --_backdrop-bg: var(--drawer-backdrop-bg, color-mix(in oklch, var(--color-canvas) 40%, transparent));\n --_backdrop-filter: none;\n --_panel-bg: var(--drawer-bg, var(--color-canvas));\n --_panel-blur: var(--drawer-panel-blur, var(--blur-md));\n --_panel-shadow: var(--drawer-shadow, var(--shadow-xl));\n --_panel-border-color: var(--color-divider);\n --_panel-bleed: var(--size-8);\n --_drag-handle-inset: calc(var(--size-1) * -1);\n\n display: contents;\n }\n\n dialog {\n all: unset;\n position: fixed;\n inset: 0;\n box-sizing: border-box;\n display: flex;\n width: 100%;\n max-width: 100%;\n height: 100%;\n max-height: 100%;\n pointer-events: none;\n transition:\n display 200ms allow-discrete,\n overlay 200ms allow-discrete;\n }\n\n dialog:not([open]) {\n display: none;\n }\n\n dialog:not([open]) .panel {\n display: none;\n }\n\n dialog[open] {\n display: flex;\n pointer-events: auto;\n }\n\n dialog::backdrop {\n background: var(--_backdrop-bg);\n opacity: 1;\n backdrop-filter: var(--_backdrop-filter);\n transition:\n display 200ms allow-discrete,\n overlay 200ms allow-discrete,\n opacity var(--transition-normal),\n backdrop-filter var(--transition-normal);\n\n @starting-style {\n opacity: 0;\n backdrop-filter: blur(0);\n }\n }\n\n dialog.closing::backdrop {\n opacity: 0;\n backdrop-filter: blur(0);\n transition:\n opacity 300ms var(--ease-in-out),\n backdrop-filter 300ms var(--ease-in-out),\n overlay 300ms allow-discrete,\n display 300ms allow-discrete;\n }\n\n .panel {\n position: absolute;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n overflow: visible;\n background: var(--_panel-bg);\n border: var(--border) solid var(--_panel-border-color);\n box-shadow: var(--_panel-shadow);\n opacity: 1;\n backdrop-filter: blur(var(--_panel-blur));\n transform: translate3d(0, 0, 0);\n transition:\n opacity var(--transition-normal),\n transform 300ms var(--ease-move);\n\n @starting-style {\n opacity: 0;\n transform: var(--_panel-exit-transform, translate3d(0, 0, 0));\n }\n }\n\n dialog.closing .panel {\n opacity: 0;\n transform: var(--_panel-exit-transform, translate3d(0, 0, 0));\n }\n\n /* left */\n :host([placement='left']) .panel {\n --_panel-exit-transform: translateX(calc(-100% - var(--_panel-bleed)));\n\n inset-block: 0;\n inset-inline-start: 0;\n width: calc(var(--drawer-size, 20rem) + var(--_panel-bleed));\n max-width: calc(100dvw + var(--_panel-bleed));\n padding-inline-start: var(--_panel-bleed);\n margin-inline-start: calc(var(--_panel-bleed) * -1);\n border-block: none;\n border-inline-start: none;\n }\n\n /* right (default) */\n :host(:not([placement])) .panel,\n :host([placement='right']) .panel {\n --_panel-exit-transform: translateX(calc(100% + var(--_panel-bleed)));\n\n inset-block: 0;\n inset-inline-end: 0;\n width: calc(var(--drawer-size, 20rem) + var(--_panel-bleed));\n max-width: calc(100dvw + var(--_panel-bleed));\n padding-inline-end: var(--_panel-bleed);\n margin-inline-end: calc(var(--_panel-bleed) * -1);\n border-block: none;\n border-inline-end: none;\n }\n\n /* top */\n :host([placement='top']) .panel {\n --_panel-exit-transform: translateY(calc(-100% - var(--_panel-bleed)));\n\n inset-block-start: 0;\n inset-inline: 0;\n height: calc(var(--drawer-size, 16rem) + var(--_panel-bleed));\n max-height: calc(100dvh + var(--_panel-bleed));\n padding-block-start: var(--_panel-bleed);\n margin-block-start: calc(var(--_panel-bleed) * -1);\n border-block-start: none;\n border-inline: none;\n }\n\n /* bottom */\n :host([placement='bottom']) .panel {\n --_panel-exit-transform: translateY(calc(100% + var(--_panel-bleed)));\n\n inset-block-end: 0;\n inset-inline: 0;\n height: calc(var(--drawer-size, 16rem) + var(--_panel-bleed));\n max-height: calc(100dvh + var(--_panel-bleed));\n padding-block-end: var(--_panel-bleed);\n margin-block-end: calc(var(--_panel-bleed) * -1);\n border-block-end: none;\n border-inline: none;\n }\n\n /* RTL overrides */\n :host(:dir(rtl)[placement='left']) .panel {\n --_panel-exit-transform: translateX(calc(100% + var(--_panel-bleed)));\n }\n\n :host(:dir(rtl)[placement='right']) .panel,\n :host(:dir(rtl):not([placement])) .panel {\n --_panel-exit-transform: translateX(calc(-100% - var(--_panel-bleed)));\n }\n\n /* Size utilities */\n :host([size='sm']) {\n --drawer-size: 14rem;\n }\n\n :host([size='lg']) {\n --drawer-size: 32rem;\n }\n\n :host([size='full']) {\n --drawer-size: 100%;\n }\n\n :host([size='full']) .panel {\n width: calc(100% + var(--_panel-bleed));\n max-width: none;\n height: calc(100% + var(--_panel-bleed));\n max-height: none;\n border: none;\n }\n\n /* Header / Body / Footer */\n .header {\n display: flex;\n flex-shrink: 0;\n gap: var(--size-2);\n align-items: center;\n padding: var(--size-4);\n border-bottom: var(--border) solid var(--color-contrast-200);\n }\n\n .header-title {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n font-size: var(--text-lg);\n font-weight: var(--font-semibold);\n white-space: nowrap;\n }\n\n .body {\n flex: 1;\n padding: var(--size-4);\n overflow-y: auto;\n }\n\n .footer {\n display: flex;\n flex-shrink: 0;\n gap: var(--size-2);\n justify-content: flex-end;\n padding: var(--size-4);\n border-top: var(--border) solid var(--color-contrast-200);\n }\n\n .header[hidden],\n .footer[hidden],\n .close-btn[hidden] {\n display: none;\n }\n\n .close-btn {\n all: unset;\n box-sizing: border-box;\n display: inline-flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n width: var(--size-8);\n height: var(--size-8);\n margin-inline-start: auto;\n color: var(--color-contrast-500);\n cursor: pointer;\n border-radius: var(--rounded-sm);\n transition:\n background var(--transition-fast),\n color var(--transition-fast);\n }\n\n .close-btn:hover {\n color: var(--color-contrast-800);\n background: var(--color-contrast-200);\n }\n\n .close-btn:active {\n opacity: 0.8;\n }\n\n /* Drag handle for mobile/touch swipe-to-close */\n .drag-handle {\n position: absolute;\n z-index: 10;\n pointer-events: all;\n touch-action: none;\n cursor: grab;\n }\n\n .drag-handle:active {\n cursor: grabbing;\n }\n\n /* Horizontal drawers (left/right) — drag handle on the opposite edge */\n :host([placement='left']) .drag-handle,\n :host(:not([placement])) .drag-handle,\n :host([placement='right']) .drag-handle {\n top: 50%;\n width: var(--_panel-bleed);\n height: 3.5rem;\n translate: 0 -50%;\n }\n\n /* Left drawer — handle on the right (opposite side) */\n :host([placement='left']) .drag-handle {\n right: calc(var(--_panel-bleed) * -1);\n }\n\n /* Right drawer (default) — handle on the left (opposite side) */\n :host([placement='right']) .drag-handle,\n :host(:not([placement])) .drag-handle {\n left: calc(var(--_panel-bleed) * -1);\n }\n\n /* Vertical drawers (top/bottom) — drag handle on the opposite edge */\n :host([placement='top']) .drag-handle,\n :host([placement='bottom']) .drag-handle {\n left: 50%;\n width: 3.5rem;\n height: var(--_panel-bleed);\n translate: -50% 0;\n }\n\n /* Top drawer — handle at bottom (opposite side) */\n :host([placement='top']) .drag-handle {\n bottom: calc(var(--_panel-bleed) * -1);\n }\n\n /* Bottom drawer — handle at top (opposite side) */\n :host([placement='bottom']) .drag-handle {\n top: calc(var(--_panel-bleed) * -1);\n }\n\n /* Inset drag-handle placement keeps the handle fully inside the panel. */\n :host([drag-handle-placement='inset'][placement='left']) .drag-handle {\n right: var(--_drag-handle-inset);\n }\n\n :host([drag-handle-placement='inset'][placement='right']) .drag-handle,\n :host([drag-handle-placement='inset']:not([placement])) .drag-handle {\n left: var(--_drag-handle-inset);\n }\n\n :host([drag-handle-placement='inset'][placement='top']) .drag-handle {\n bottom: var(--_drag-handle-inset);\n }\n\n :host([drag-handle-placement='inset'][placement='bottom']) .drag-handle {\n top: var(--_drag-handle-inset);\n }\n\n /* Visual indicator — subtle bar in the center */\n .drag-handle::before {\n position: absolute;\n inset: 50%;\n content: '';\n background: var(--color-contrast-400);\n border-radius: var(--rounded-full);\n opacity: 0.6;\n translate: -50% -50%;\n transition:\n background var(--transition-fast),\n opacity var(--transition-fast),\n transform var(--transition-fast);\n }\n\n :host([placement='left']) .drag-handle::before,\n :host([placement='right']) .drag-handle::before,\n :host(:not([placement])) .drag-handle::before {\n width: 5px;\n height: 2.5rem;\n }\n\n :host([placement='top']) .drag-handle::before,\n :host([placement='bottom']) .drag-handle::before {\n width: 2.5rem;\n height: 5px;\n }\n\n .drag-handle:hover::before {\n background: var(--color-contrast-600);\n opacity: 0.9;\n transform: scale(1.15);\n }\n\n .close-btn:focus-visible {\n outline: var(--focus-ring);\n }\n\n @media (width <= 640px) {\n :host([placement='left']) .panel,\n :host(:not([placement])) .panel,\n :host([placement='right']) .panel {\n width: calc(min(var(--drawer-size, 20rem), calc(100vw - var(--size-2))) + var(--_panel-bleed));\n max-width: calc(100vw - var(--size-2) + var(--_panel-bleed));\n }\n\n :host([placement='top']) .panel,\n :host([placement='bottom']) .panel {\n height: calc(min(var(--drawer-size, 16rem), calc(100dvh - var(--size-2))) + var(--_panel-bleed));\n max-height: calc(100dvh - var(--size-2) + var(--_panel-bleed));\n }\n\n .header,\n .body,\n .footer {\n padding: var(--size-3);\n }\n }\n}\n\n@layer refine.config {\n :host([backdrop='blur']) {\n --_backdrop-filter: blur(var(--blur-xs));\n }\n\n :host([backdrop='transparent']) {\n --_backdrop-bg: transparent;\n }\n}\n","import { createStableId, define, html, prop, ref } from '@vielzeug/ore';\nimport { signal } from '@vielzeug/ripple';\n\nimport type { OverlayCloseDetail, OverlayOpenDetail, SwipeAxis } from '../../headless';\n\nimport { createSwipeControl } from '../../headless';\nimport '../../content/icon/icon';\nimport { coarsePointerMixin, elevationMixin, forcedColorsMixin, reducedMotionMixin } from '../../styles';\nimport { useDialogControl } from '../shared/use-dialog';\nimport styles from './drawer.css?inline';\n\ntype DrawerPlacement = 'left' | 'right' | 'top' | 'bottom';\ntype DrawerSize = 'sm' | 'lg' | 'full';\ntype DrawerBackdrop = 'opaque' | 'blur' | 'transparent';\ntype DrawerDragHandlePlacement = 'outside' | 'inset';\ntype DrawerSwipeConfig = {\n axis: SwipeAxis;\n closingDistance: (distance: number) => number;\n translate: (distance: number) => string;\n};\n\nconst drawerSwipeConfig: Record<DrawerPlacement, DrawerSwipeConfig> = {\n bottom: {\n axis: 'y',\n closingDistance: (distance) => Math.max(0, distance),\n translate: (distance) => `translateY(${distance}px)`,\n },\n left: {\n axis: 'x',\n closingDistance: (distance) => Math.max(0, -distance),\n translate: (distance) => `translateX(${distance}px)`,\n },\n right: {\n axis: 'x',\n closingDistance: (distance) => Math.max(0, distance),\n translate: (distance) => `translateX(${distance}px)`,\n },\n top: {\n axis: 'y',\n closingDistance: (distance) => Math.max(0, -distance),\n translate: (distance) => `translateY(${distance}px)`,\n },\n};\n\n/** Element interface exposing the imperative API for `ore-drawer`. */\nexport interface DrawerElement extends HTMLElement, Omit<OreDrawerProps, 'title'> {\n /** Programmatically open the drawer. Equivalent to setting `open`. */\n show(): void;\n /** Programmatically close the drawer with the exit animation. */\n hide(): void;\n}\n\n/** Drawer component properties */\n\nexport type OreDrawerEvents = {\n close: OverlayCloseDetail & { placement: DrawerPlacement };\n open: OverlayOpenDetail & { placement: DrawerPlacement };\n};\n\nexport type OreDrawerProps = {\n /** Backdrop style — 'opaque' (default), 'blur', or 'transparent' */\n backdrop?: DrawerBackdrop;\n /** Show the close (×) button in the header (default: true) */\n dismissible?: boolean;\n /** Drag handle position used for swipe-to-close gestures */\n 'drag-handle-placement'?: DrawerDragHandlePlacement;\n /**\n * CSS selector for the element inside the drawer that should receive focus on open.\n * Defaults to native dialog focus management (first focusable element).\n * @example '#submit-btn' | 'input[name=\"email\"]'\n */\n 'initial-focus'?: string;\n /**\n * Invisible accessible label for the dialog (`aria-label`).\n * Use when the drawer has no visible title (e.g. image-only content).\n * When omitted, `aria-labelledby` points to the visible header title instead.\n */\n label?: string;\n /** Controlled open state */\n open?: boolean;\n /** When true, backdrop clicks do not close the drawer (default: false) */\n persistent?: boolean;\n /** Side from which the drawer slides in */\n placement?: DrawerPlacement;\n /**\n * When true (default), focus returns to the triggering element after the drawer closes.\n * Set to false to manage focus manually.\n */\n 'return-focus'?: boolean;\n /** Drawer width/height preset */\n size?: DrawerSize;\n /**\n * Visible title text rendered inside the header.\n * Used as the dialog's accessible label via `aria-labelledby` when `label` is not set.\n */\n title?: string;\n};\n\n/**\n * A panel that slides in from any edge of the screen, built on the native `<dialog>` element.\n *\n * @element ore-drawer\n *\n * @attr {boolean} open - Controlled open/close state\n * @attr {string} placement - 'left' | 'right' (default) | 'top' | 'bottom'\n * @attr {string} size - 'sm' | 'lg' | 'full'\n * @attr {string} title - Visible header title text\n * @attr {string} label - Invisible aria-label (for drawers without a visible title)\n * @attr {boolean} dismissible - Show the close (×) button (default: true)\n * @attr {string} drag-handle-placement - 'outside' (default) | 'inset'\n * @attr {string} backdrop - Backdrop style: 'opaque' (default) | 'blur' | 'transparent'\n * @attr {boolean} persistent - Prevent backdrop-click from closing (default: false)\n *\n * @fires open - When the drawer opens with detail: { placement, reason }\n * @fires close - When the drawer closes with detail: { placement, reason }\n *\n * @slot header - Drawer header content\n * @slot - Main body content\n * @slot footer - Drawer footer content\n *\n * @cssprop --drawer-backdrop-bg - Backdrop background color\n * @cssprop --drawer-bg - Panel background color\n * @cssprop --drawer-size - Panel width (horizontal) or height (vertical)\n * @cssprop --drawer-shadow - Panel box-shadow\n * @cssprop --drawer-panel-blur - Panel backdrop blur amount\n *\n * @part drag-handle - Drawer drag handle.\n * @part panel - Panel container.\n * @part header - Header container.\n * @part close-btn - Close button.\n * @part body - Body content container.\n * @part footer - Footer container.\n * @example\n * ```html\n * <!-- With visible title -->\n * <ore-drawer open title=\"Settings\" placement=\"right\">\n * <p>Settings content here.</p>\n * </ore-drawer>\n *\n * <!-- With custom header slot -->\n * <ore-drawer open placement=\"right\">\n * <span slot=\"header\">Settings</span>\n * <p>Settings content here.</p>\n * </ore-drawer>\n * ```\n */\n\nexport const DRAWER_TAG = 'ore-drawer' as const;\ndefine<OreDrawerProps, OreDrawerEvents>(DRAWER_TAG, {\n props: {\n backdrop: prop.string<DrawerBackdrop>(),\n dismissible: prop.bool(true),\n 'drag-handle-placement': prop.oneOf(['outside', 'inset'] as const, 'outside'),\n 'initial-focus': prop.string(),\n label: prop.string(),\n open: prop.bool(false),\n persistent: prop.bool(false),\n placement: prop.oneOf(['left', 'right', 'top', 'bottom'] as const, 'right'),\n 'return-focus': prop.bool(true),\n size: prop.string<DrawerSize>(),\n title: prop.string(),\n },\n setup(props, { el, emit, onCleanup, onEvent, onMounted, slots }) {\n const drawerLabelId = createStableId('drawer-label');\n const dialogRef = ref<HTMLDialogElement>();\n const panelRef = ref<HTMLDivElement>();\n\n // Drag-to-close state\n const isSwipeClosing = signal(false);\n let swipeCloseTimer: ReturnType<typeof setTimeout> | undefined;\n\n const getHeaderText = () => props.label.value ?? props.title.value ?? '';\n const hasHeaderTitle = () => slots.has('header').value || !!getHeaderText();\n\n // Header is visible when there is slot content, a text label, or a close button.\n const hasHeader = () => hasHeaderTitle() || props.dismissible.value;\n const hasFooter = () => slots.has('footer').value;\n\n const getPlacement = (): DrawerPlacement => props.placement.value || 'right';\n\n const getSwipeConfig = (): DrawerSwipeConfig => drawerSwipeConfig[getPlacement()];\n\n const getSnapThreshold = (panel: HTMLElement, axis: SwipeAxis) => {\n const panelSize = axis === 'x' ? panel.offsetWidth : panel.offsetHeight;\n\n return Math.min(96, Math.max(36, panelSize * 0.18));\n };\n\n const shouldCommitSwipeClose = (distance: number, threshold: number) => {\n return getSwipeConfig().closingDistance(distance) >= threshold;\n };\n\n const finalizeSwipeClose = (panel: HTMLElement) => {\n if (!isSwipeClosing.value) return;\n\n if (swipeCloseTimer) {\n clearTimeout(swipeCloseTimer);\n swipeCloseTimer = undefined;\n }\n\n const dialog = dialogRef.value;\n\n if (!dialog) {\n isSwipeClosing.value = false;\n\n return;\n }\n\n dialog.style.transition = 'none';\n panel.style.opacity = '0';\n panel.style.visibility = 'hidden';\n void dialog.offsetWidth;\n\n requestClose('swipe');\n };\n\n const startSwipeClose = (panel: HTMLElement, swipe: DrawerSwipeConfig, committedDistance: number) => {\n if (isSwipeClosing.value) return;\n\n isSwipeClosing.value = true;\n\n const panelSize = swipe.axis === 'x' ? panel.offsetWidth : panel.offsetHeight;\n // Preserve overshoot so closing continues from the dragged position instead of snapping back.\n const exitDistance =\n committedDistance >= 0 ? Math.max(committedDistance, panelSize) : Math.min(committedDistance, -panelSize);\n const exitTransform = swipe.translate(exitDistance);\n\n // Commit the current drag position first so the magnetic snap continues\n // from the finger instead of jumping back to rest.\n panel.style.transition = 'transform 180ms cubic-bezier(0.2, 0.9, 0.2, 1), opacity 180ms ease-out';\n void panel.offsetWidth;\n\n const onExitTransitionEnd = (ev: TransitionEvent) => {\n if (ev.target !== panel || ev.propertyName !== 'transform') return;\n\n panel.removeEventListener('transitionend', onExitTransitionEnd);\n finalizeSwipeClose(panel);\n };\n\n panel.addEventListener('transitionend', onExitTransitionEnd);\n\n const durationMs = parseFloat(getComputedStyle(panel).transitionDuration) * 1000;\n\n swipeCloseTimer = setTimeout(() => {\n panel.removeEventListener('transitionend', onExitTransitionEnd);\n finalizeSwipeClose(panel);\n }, durationMs + 50);\n\n panel.style.transform = exitTransform;\n panel.style.opacity = '0.2';\n };\n\n const resetPanelDragStyles = (panel: HTMLElement) => {\n if (swipeCloseTimer) {\n clearTimeout(swipeCloseTimer);\n swipeCloseTimer = undefined;\n }\n\n // Re-enable transitions so the snap-back or exit animates.\n panel.style.transition = '';\n panel.style.transform = '';\n panel.style.opacity = '';\n panel.style.visibility = '';\n isSwipeClosing.value = false;\n };\n\n // Same \"snap back or commit close\" decision whether the swipe was\n // interrupted by the platform (onCancel) or simply released without an\n // intervening move event crossing the threshold (onRelease).\n const handleSwipeRelease = ({ distance, threshold }: { distance: number; threshold: number }): void => {\n const panel = panelRef.value;\n\n if (!panel) return;\n\n // If the release event crosses the threshold (without an intervening\n // move event), commit close instead of snapping back to rest first.\n if (shouldCommitSwipeClose(distance, threshold)) {\n startSwipeClose(panel, getSwipeConfig(), distance);\n\n return;\n }\n\n resetPanelDragStyles(panel);\n };\n\n const swipe = createSwipeControl({\n axis: () => getSwipeConfig().axis,\n disabled: isSwipeClosing,\n onCancel: handleSwipeRelease,\n onCommit: ({ distance }) => {\n const panel = panelRef.value;\n\n if (!panel) return;\n\n startSwipeClose(panel, getSwipeConfig(), distance);\n },\n onMove: ({ distance, threshold }) => {\n const panel = panelRef.value;\n\n if (!panel) return;\n\n const swipeConfig = getSwipeConfig();\n const closingDistance = swipeConfig.closingDistance(distance);\n const progress = Math.min(closingDistance / threshold, 1);\n\n // Kill CSS transitions so the panel tracks the finger instantly.\n panel.style.transition = 'none';\n panel.style.transform = swipeConfig.translate(distance);\n panel.style.opacity = String(1 - progress * 0.4);\n },\n onRelease: handleSwipeRelease,\n shouldCommit: ({ distance, threshold }) => shouldCommitSwipeClose(distance, threshold),\n threshold: () => {\n const panel = panelRef.value;\n\n if (!panel) return 48;\n\n return getSnapThreshold(panel, getSwipeConfig().axis);\n },\n });\n\n // ────────────────────────────────────────────────────────────────\n // Overlay State Management\n // ────────────────────────────────────────────────────────────────\n\n const { closeWithAnimation, handleCancel, overlay, requestClose, watchOpenProp } = useDialogControl({\n beforeOpen: (dialog) => {\n // Clear any inline drag styles from a previous swipe-close so the CSS\n // entry animation starts from the correct base state.\n const panel = panelRef.value;\n\n if (panel) resetPanelDragStyles(panel);\n\n void dialog;\n },\n closeRequestDetail: (_reason) => ({ placement: props.placement.value ?? 'right' }),\n dialogRef,\n getPanelEl: () => panelRef.value,\n host: el,\n initialFocus: props['initial-focus'],\n isPersistent: () => Boolean(props.persistent.value),\n onCleanup,\n onEvent,\n onNativeClose: (reason) => {\n const panelEl = panelRef.value;\n\n // For swipe-close, keep the panel hidden and off-screen until the next\n // open cycle — resetting inline styles during native close can produce\n // a visible frame at the rest position on some browsers.\n if (panelEl && reason !== 'swipe') resetPanelDragStyles(panelEl);\n\n const dialog = dialogRef.value;\n\n if (dialog) dialog.style.transition = '';\n\n emit('close', { placement: props.placement.value ?? 'right', reason });\n },\n onOpen: (reason) => emit('open', { placement: props.placement.value ?? 'right', reason }),\n openProp: props.open,\n performClose: (dialog, reason) => {\n if (reason === 'swipe') {\n dialog.close();\n } else {\n closeWithAnimation();\n }\n },\n returnFocus: props['return-focus'],\n });\n\n const handleCloseButtonClick = () => {\n requestClose('trigger');\n };\n\n // ────────────────────────────────────────────────────────────────\n // Lifecycle: Setup Drawer Integration\n // ────────────────────────────────────────────────────────────────\n\n onMounted(() => {\n const dialog = dialogRef.value;\n\n if (!dialog) return;\n\n // Expose imperative API\n const drawerEl = el as DrawerElement;\n\n drawerEl.show = () => {\n overlay.open('programmatic');\n };\n\n drawerEl.hide = () => {\n overlay.close('programmatic', false);\n };\n\n // ────────────────────────────────────────────────────────────\n // Event Handlers: Cancel, Backdrop Click\n // ────────────────────────────────────────────────────────────\n // `handleCancel` (Escape via the native `cancel` event) is provided by\n // `useDialogControl` above — drawer only needs its own backdrop-click\n // handler since it has swipe-to-dismiss logic the shared dialog helper\n // doesn't know about.\n\n const handleBackdropClick = (e: MouseEvent) => {\n if (props.persistent.value) return;\n\n if (swipe.isActive() || isSwipeClosing.value) return;\n\n if (e.target !== dialog) return; // Click inside panel\n\n requestClose('outsideClick');\n };\n\n watchOpenProp();\n\n onEvent(dialog, 'cancel', handleCancel);\n onEvent(dialog, 'click', handleBackdropClick);\n\n // Drag-to-close handlers — scoped to the handle element only so interactions\n // with panel content don't accidentally start a drag.\n const panel = panelRef.value;\n const dragHandleEl = panel?.querySelector<HTMLElement>('[part=\"drag-handle\"]');\n\n if (dragHandleEl) {\n onEvent(dragHandleEl, 'pointerdown', swipe.handlePointerDown);\n onEvent(dragHandleEl, 'pointermove', swipe.handlePointerMove);\n onEvent(dragHandleEl, 'pointerup', swipe.handlePointerUp);\n onEvent(dragHandleEl, 'pointercancel', swipe.handlePointerCancel);\n }\n\n return () => {\n overlay.dispose();\n };\n });\n\n return html`\n <dialog\n ref=${dialogRef}\n aria-modal=\"true\"\n :aria-label=\"${() => props.label.value ?? null}\"\n :aria-labelledby=\"${() => (!props.label.value ? drawerLabelId : null)}\">\n <div class=\"panel\" part=\"panel\" ref=${panelRef}>\n <div class=\"drag-handle\" part=\"drag-handle\" aria-label=\"Drag to close\" role=\"button\"></div>\n <div class=\"header\" part=\"header\" ?hidden=${() => !hasHeader()}>\n <span class=\"header-title\" id=\"${drawerLabelId}\" ?hidden=${() => !hasHeaderTitle()}>\n <slot name=\"header\">${() => getHeaderText()}</slot>\n </span>\n <button\n class=\"close-btn\"\n part=\"close-btn\"\n type=\"button\"\n aria-label=\"Close\"\n ?hidden=${() => !props.dismissible.value}\n @click=${handleCloseButtonClick}>\n <ore-icon name=\"x\" size=\"16\" stroke-width=\"2.5\" aria-hidden=\"true\"></ore-icon>\n </button>\n </div>\n <div class=\"body\" part=\"body\">\n <slot></slot>\n </div>\n <div class=\"footer\" part=\"footer\" ?hidden=${() => !hasFooter()}>\n <slot name=\"footer\"></slot>\n </div>\n </div>\n </dialog>\n `;\n },\n styles: [elevationMixin, forcedColorsMixin, coarsePointerMixin, reducedMotionMixin, styles],\n});\n","@layer refine.base {\n :host {\n --_menu-color: var(--menu-item-color, var(--_theme-base, var(--color-primary)));\n --_hover-bg: var(--menu-item-hover-bg, var(--color-contrast-100));\n --_focus-color: var(--menu-item-focus-color, var(--_menu-color));\n --_focus-bg: var(--menu-item-focus-bg, color-mix(in oklch, var(--_menu-color) 12%, var(--color-contrast-100)));\n --_selection-bg: var(\n --menu-item-selection-bg,\n color-mix(in oklch, var(--color-contrast-900) 5%, var(--color-canvas))\n );\n --_checked-color: var(--menu-item-checked-color, var(--_menu-color));\n --_checked-bg: var(--menu-item-checked-bg, color-mix(in oklch, var(--_menu-color) 18%, var(--color-canvas)));\n\n display: block;\n outline: none;\n }\n\n .item {\n display: flex;\n gap: var(--size-2);\n align-items: center;\n padding: var(--size-1-5) var(--size-3);\n font-size: var(--text-sm);\n line-height: var(--leading-normal);\n white-space: nowrap;\n cursor: pointer;\n user-select: none;\n border-radius: 0;\n transition:\n background var(--transition-fast),\n color var(--transition-fast);\n }\n\n :host(:first-of-type) .item {\n border-radius: var(--rounded-sm) var(--rounded-sm) 0 0;\n }\n\n :host(:last-child) .item {\n border-radius: 0 0 var(--rounded-sm) var(--rounded-sm);\n }\n\n :host(:first-of-type:last-child) .item {\n border-radius: var(--rounded-sm);\n }\n\n :host(:not([disabled])) .item:hover {\n background: var(--_hover-bg);\n }\n\n :host(:focus-visible) .item {\n color: var(--_focus-color);\n background: var(--_focus-bg);\n }\n\n .item.is-checked {\n font-weight: var(--font-medium);\n color: var(--_checked-color);\n }\n\n :host([disabled]) .item {\n color: var(--color-contrast-400);\n pointer-events: none;\n cursor: not-allowed;\n opacity: 0.6;\n }\n\n .icon-slot {\n display: contents;\n }\n\n .item-check {\n display: inline-flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n width: 1.25rem;\n color: currentcolor;\n }\n\n /* CSS-based check/radio indicator — no Unicode characters */\n .item-check::before {\n display: block;\n width: 0.875rem;\n height: 0.875rem;\n content: '';\n border: 1.5px solid currentcolor;\n transition:\n background var(--transition-fast),\n border-color var(--transition-fast);\n }\n\n .item.is-checkbox .item-check::before {\n border-radius: 2px;\n }\n\n .item.is-radio .item-check::before {\n border-radius: 50%;\n }\n\n .item.is-checked .item-check::before {\n background: currentcolor;\n }\n\n /* Radio checked: filled dot via inset box-shadow */\n .item.is-radio.is-checked .item-check::before {\n background: transparent;\n box-shadow: inset 0 0 0 3px currentcolor;\n }\n\n .item-label {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n}\n\n@media (pointer: coarse) {\n .item {\n padding: var(--size-2-5) var(--size-3);\n }\n}\n","@layer refine.base {\n :host {\n display: block;\n margin: var(--size-1) 0;\n border-top: var(--border) solid var(--color-contrast-200);\n }\n}\n","@layer refine.base {\n :host {\n --_menu-panel-bg: var(--menu-panel-bg, var(--color-canvas));\n --_menu-panel-border-color: var(--menu-panel-border-color, var(--color-divider));\n --_menu-panel-blur: var(--menu-panel-blur, var(--blur-md));\n --_menu-panel-shadow: var(--menu-panel-shadow, var(--shadow-xl));\n\n position: relative;\n display: inline-block;\n }\n\n /* ========================================\n Menu Panel\n ======================================== */\n\n .menu-panel {\n position: fixed;\n inset-inline-start: 0;\n top: 0;\n z-index: calc(var(--z-popover, 1000) + 1);\n box-sizing: border-box;\n min-width: var(--menu-panel-min-width, 10rem);\n max-height: var(--menu-panel-max-height, min(70vh, 32rem));\n padding: var(--size-1);\n margin: 0;\n overflow-y: auto;\n pointer-events: none;\n background: var(--_menu-panel-bg);\n border: var(--border) solid var(--_menu-panel-border-color);\n border-radius: var(--menu-panel-radius, var(--rounded-lg));\n box-shadow: var(--_menu-panel-shadow);\n opacity: 0;\n backdrop-filter: blur(var(--_menu-panel-blur));\n transform: translateY(var(--overlay-enter-translate-y)) scale(var(--overlay-enter-scale));\n transform-origin: top left;\n transition:\n opacity 100ms var(--ease-spring),\n transform 100ms var(--ease-spring),\n display 100ms allow-discrete,\n overlay 100ms allow-discrete;\n }\n\n .menu-panel[data-placement='top-start'],\n .menu-panel[data-placement='top'],\n .menu-panel[data-placement='top-end'] {\n transform-origin: bottom left;\n }\n\n .menu-panel[data-placement='bottom-end'],\n .menu-panel[data-placement='right-start'],\n .menu-panel[data-placement='right'] {\n transform-origin: top right;\n }\n\n .menu-panel[data-open] {\n pointer-events: auto;\n opacity: 1;\n transform: translateY(0) scale(1);\n transition:\n opacity 150ms var(--ease-spring),\n transform 150ms var(--ease-spring),\n display 150ms allow-discrete,\n overlay 150ms allow-discrete;\n\n @starting-style {\n opacity: 0;\n transform: translateY(var(--overlay-enter-translate-y)) scale(var(--overlay-enter-scale));\n }\n }\n\n /* ========================================\n Menu Items (slotted ore-menu-item)\n ======================================== */\n\n ::slotted(ore-menu-item) {\n display: block;\n }\n\n ::slotted(ore-menu-separator) {\n display: block;\n }\n}\n","import type { Placement } from '@vielzeug/orbit';\n\nimport { createStableId, define, html, prop } from '@vielzeug/ore';\nimport { computed, watch as rippleWatch } from '@vielzeug/ripple';\n\nimport type { ComponentSize } from '../../types';\n\nimport {\n lifecycleSignal,\n createInteraction,\n createOptionList,\n type DropdownCloseReason,\n type OverlayOpenDetail,\n} from '../../headless';\nimport { disablableBundle, sizableBundle } from '../../shared';\nimport { forcedColorsMixin, sizeVariantMixin } from '../../styles';\nimport menuItemStyles from './menu-item.css?inline';\nimport menuSeparatorStyles from './menu-separator.css?inline';\nimport componentStyles from './menu.css?inline';\n\n// ── Types ─────────────────────────────────────────────────────────────\n\nexport interface MenuSelectDetail {\n value: string;\n checked?: boolean;\n}\n\nexport type OreMenuItemType = 'checkbox' | 'radio';\n\nexport type OreMenuEvents = {\n close: { reason: DropdownCloseReason };\n open: OverlayOpenDetail;\n select: MenuSelectDetail;\n};\n\nexport type OreMenuItemProps = {\n checked?: boolean;\n disabled?: boolean;\n type?: OreMenuItemType;\n value?: string;\n};\n\nexport type OreMenuProps = {\n disabled?: boolean;\n placement?: 'bottom' | 'bottom-start' | 'bottom-end' | 'top' | 'top-start' | 'top-end';\n size?: ComponentSize;\n};\n\n// ── Styles ─────────────────────────────────────────────────────────────\n\n// ── Menu Item Component ─────────────────────────────────────────────────────────────\n\n/**\n * A selectable action item used inside `<ore-menu>`.\n *\n * @element ore-menu-item\n *\n * @attr {boolean} checked - Checked state for `checkbox` and `radio` item types\n * @attr {boolean} disabled - Disables selection and pointer interaction\n * @attr {'checkbox'|'radio'} type - Optional checkable menu item mode\n * @attr {string} value - Value emitted by parent menu on selection\n *\n * @slot - Item label/content\n * @slot icon - Optional leading icon content\n *\n * @cssprop --menu-item-hover-bg - Background on hover\n * @cssprop --menu-item-focus-color - Text color when keyboard-focused\n * @cssprop --menu-item-focus-bg - Background when keyboard-focused\n * @cssprop --menu-item-selection-bg - Background for checkbox/radio items (unselected)\n * @cssprop --menu-item-checked-color - Text color when checked\n * @cssprop --menu-item-checked-bg - Background when checked\n *\n * @part item - Root item container element.\n * @part item-label - Label text container.\n * @part icon-slot - Leading icon slot container.\n *\n * @example\n * ```html\n * <ore-menu-item value=\"edit\">Edit</ore-menu-item>\n * <ore-menu-item value=\"delete\" disabled>Delete</ore-menu-item>\n * <ore-menu-item type=\"checkbox\" value=\"wrap\" checked>Word wrap</ore-menu-item>\n * <ore-menu-item type=\"radio\" value=\"left\">Align left</ore-menu-item>\n * ```\n */\nexport const MENU_ITEM_TAG = 'ore-menu-item' as const;\ndefine<OreMenuItemProps>(MENU_ITEM_TAG, {\n props: {\n checked: prop.bool(false),\n disabled: prop.bool(false),\n type: prop.string<OreMenuItemType>(),\n value: prop.string(),\n },\n setup(props) {\n const isCheckable = () => props.type.value === 'checkbox' || props.type.value === 'radio';\n const isChecked = () => isCheckable() && props.checked.value;\n const itemRole = () => {\n if (props.type.value === 'checkbox') return 'menuitemcheckbox';\n\n if (props.type.value === 'radio') return 'menuitemradio';\n\n return 'menuitem';\n };\n const itemClass = () => {\n const type = props.type.value;\n\n return [\n 'item',\n type === 'checkbox' ? 'is-checkbox' : '',\n type === 'radio' ? 'is-radio' : '',\n isChecked() ? 'is-checked' : '',\n ]\n .filter(Boolean)\n .join(' ');\n };\n\n return isCheckable()\n ? html`\n <div\n class=\"${itemClass}\"\n tabindex=\"-1\"\n role=\"${itemRole}\"\n aria-checked=\"${() => String(isChecked())}\"\n aria-disabled=\"${props.disabled}\">\n <span class=\"item-check\" aria-hidden=\"true\"></span>\n <span class=\"icon-slot\"><slot name=\"icon\"></slot></span>\n <span class=\"item-label\"><slot></slot></span>\n </div>\n `\n : html`\n <div class=\"item\" tabindex=\"-1\" role=\"menuitem\" aria-disabled=\"${props.disabled}\">\n <span class=\"icon-slot\"><slot name=\"icon\"></slot></span>\n <span class=\"item-label\"><slot></slot></span>\n </div>\n `;\n },\n styles: [menuItemStyles],\n});\n\n// ── Menu Separator ─────────────────────────────────────────────────────────────\n\n/**\n * Visual separator used to group menu items inside `<ore-menu>`.\n *\n * @element ore-menu-separator\n *\n * @example\n * ```html\n * <ore-menu-item value=\"cut\">Cut</ore-menu-item>\n * <ore-menu-separator></ore-menu-separator>\n * <ore-menu-item value=\"paste\">Paste</ore-menu-item>\n * ```\n */\nexport const SEPARATOR_TAG = 'ore-menu-separator' as const;\ndefine(SEPARATOR_TAG, {\n setup() {\n return html``;\n },\n styles: [menuSeparatorStyles],\n});\n\n// ── Menu Component ─────────────────────────────────────────────────────────────\n\nconst isCheckableItemType = (value: string | null): value is OreMenuItemType =>\n value === 'checkbox' || value === 'radio';\n\n/**\n * Action dropdown menu triggered by a slotted trigger element.\n *\n * @element ore-menu\n * @element ore-menu-item - Clickable menu option (place in default slot)\n * @element ore-menu-separator - Visual divider between menu groups\n *\n * @attr {boolean} disabled - Disables opening and keyboard interaction\n * @attr {string} placement - Panel placement: 'bottom' | 'bottom-start' | 'bottom-end' | 'top' | 'top-start' | 'top-end' (default: 'bottom-start')\n * @attr {string} size - Size: 'sm' | 'md' | 'lg'\n *\n * @fires open - Fired when the menu opens. detail: { reason: 'trigger' | 'programmatic' }\n * @fires close - Fired when the menu closes. detail: { reason: 'escape' | 'outsideClick' | 'programmatic' | 'trigger' }\n * @fires select - Fired when an item is selected. detail: { value: string, checked?: boolean }\n *\n * @slot trigger - Trigger element that toggles menu visibility\n * @slot - Menu content (`<ore-menu-item>` and `<ore-menu-separator>`)\n *\n * @part panel - Floating menu panel container\n *\n * @cssprop --menu-panel-bg - Background of the floating panel\n * @cssprop --menu-panel-border-color - Border color of the floating panel\n * @cssprop --menu-panel-shadow - Box shadow of the floating panel\n * @cssprop --menu-panel-blur - Backdrop blur amount for the floating panel\n * @cssprop --menu-panel-min-width - Minimum width of the floating panel\n * @cssprop --menu-panel-max-height - Maximum height of the floating panel before it scrolls\n * @cssprop --menu-panel-radius - Border radius of the floating panel\n *\n * @example\n * ```html\n * <ore-menu>\n * <button slot=\"trigger\">Actions</button>\n * <ore-menu-item value=\"edit\">Edit</ore-menu-item>\n * <ore-menu-item value=\"delete\">Delete</ore-menu-item>\n * </ore-menu>\n * ```\n */\nexport const MENU_TAG = 'ore-menu' as const;\ndefine<OreMenuProps, OreMenuEvents>(MENU_TAG, {\n props: {\n ...sizableBundle,\n ...disablableBundle,\n placement: prop.oneOf(\n ['bottom', 'bottom-start', 'bottom-end', 'top', 'top-start', 'top-end'] as const,\n 'bottom-start',\n ),\n },\n setup(props, { aria, bind, el, emit, onCleanup, onMounted, slots, watch }) {\n const menuId = createStableId('menu');\n const isDisabled = computed(() => Boolean(props.disabled.value));\n const abortSignal = lifecycleSignal(onCleanup);\n let triggerEl: HTMLElement | null = null;\n let panelEl: HTMLElement | null = null;\n let cleanupTrigger: (() => void) | null = null;\n\n // ── Helpers ───────────────────────────────────────────────────────────────\n function getItems(): HTMLElement[] {\n return Array.from(el.querySelectorAll<HTMLElement>('ore-menu-item:not([disabled])'));\n }\n\n function getItemFocusable(item: HTMLElement | null | undefined): HTMLElement | null {\n if (!item) return null;\n\n return item.shadowRoot?.querySelector<HTMLElement>('[role^=\"menuitem\"]') ?? item;\n }\n\n function getFocusedItemIndex(): number {\n const items = getItems();\n\n return items.findIndex((item) => {\n const focusable = getItemFocusable(item);\n\n return item === document.activeElement || focusable === document.activeElement;\n });\n }\n\n const optionList = createOptionList<HTMLElement>({\n getBoundary: () => el,\n getItems: getItems,\n getPanel: () => panelEl,\n getReference: () => triggerEl,\n getTrigger: () => triggerEl,\n isDisabled: () => isDisabled.value,\n isItemDisabled: (item) => item.hasAttribute('disabled'),\n onClose: (reason) => emit('close', { reason }),\n onNavigate: (_action, index) => {\n const nextItem = getItems()[index];\n\n getItemFocusable(nextItem)?.focus();\n },\n onOpen: (reason) => emit('open', { reason }),\n positioning: {\n getPlacement: () => (props.placement.value ?? 'bottom-start') as Placement,\n matchWidth: false,\n offsetPx: 4,\n padding: 6,\n },\n signal: abortSignal,\n });\n const { isOpen: isOpenSignal } = optionList;\n\n const activateItem = (item: HTMLElement): void => {\n const type = item.getAttribute('type');\n const isCheckable = isCheckableItemType(type);\n\n if (type === 'checkbox') {\n item.toggleAttribute('checked', !item.hasAttribute('checked'));\n } else if (type === 'radio') {\n for (const radio of el.querySelectorAll<HTMLElement>('ore-menu-item[type=\"radio\"]')) {\n radio.toggleAttribute('checked', radio === item);\n }\n }\n\n const value = item.getAttribute('value') ?? '';\n const checked = isCheckable ? item.hasAttribute('checked') : undefined;\n\n emit('select', { checked, value });\n\n if (!isCheckable) {\n optionList.close('programmatic');\n }\n };\n\n const openFromKeyboardPress = createInteraction({\n keys: ['Enter', ' ', 'ArrowDown'],\n onPress: () => {\n optionList.open('keyboard');\n requestAnimationFrame(() => optionList.set(0));\n },\n });\n\n const activateFocusedFromKeyboardPress = createInteraction({\n onPress: () => {\n const focused = optionList.getActiveItem();\n\n if (focused) activateItem(focused);\n },\n });\n\n // ── Keyboard Navigation ───────────────────────────────────────────────────\n function handleMenuKeydown(e: KeyboardEvent) {\n if (isDisabled.value) return;\n\n const open = isOpenSignal.value;\n\n // When closed: open on Enter / Space / ArrowDown\n if (!open) {\n openFromKeyboardPress.handleKeydown(e);\n\n return;\n }\n\n const currentFocusedIndex = getFocusedItemIndex();\n\n if (currentFocusedIndex >= 0) optionList.set(currentFocusedIndex);\n\n if (optionList.handleKeydown(e)) return;\n\n // When open: navigate and activate\n if (e.key === ' ' || e.key === 'Enter') {\n activateFocusedFromKeyboardPress.handleKeydown(e);\n\n return;\n }\n\n if (e.key === 'Tab') {\n optionList.close('programmatic');\n }\n }\n\n // ── Lifecycle ─────────────────────────────────────────────────────────────\n bind({\n on: {\n click: (e: MouseEvent) => {\n const path = e.composedPath();\n\n if (!isOpenSignal.value) return;\n\n const itemFromPath = path.find(\n (node): node is HTMLElement => node instanceof HTMLElement && node.tagName === 'ORE-MENU-ITEM',\n );\n const item = itemFromPath ?? (e.target as HTMLElement | null)?.closest<HTMLElement>('ore-menu-item') ?? null;\n\n if (!item || item.hasAttribute('disabled')) return;\n\n activateItem(item);\n },\n },\n });\n\n watch(() => {\n const open = isOpenSignal.value;\n\n if (!panelEl) return;\n\n panelEl.toggleAttribute('data-open', open);\n });\n\n function resolveTrigger() {\n cleanupTrigger?.();\n cleanupTrigger = null;\n\n const assigned = slots.elements('trigger').value;\n\n triggerEl = (assigned?.[0] as HTMLElement | undefined) ?? null;\n\n if (!triggerEl) return;\n\n const cleanups: Array<() => void> = [];\n const removeAria = aria(triggerEl, {\n controls: () => menuId,\n disabled: () => isDisabled.value,\n expanded: () => String(isOpenSignal.value),\n haspopup: 'menu',\n });\n\n const onTriggerClick = (event: MouseEvent) => {\n event.stopPropagation();\n\n if (isDisabled.value) return;\n\n optionList.toggle();\n };\n const onTriggerKeydown = (event: KeyboardEvent) => {\n handleMenuKeydown(event);\n };\n\n triggerEl.addEventListener('click', onTriggerClick);\n triggerEl.addEventListener('keydown', onTriggerKeydown);\n cleanups.push(() => triggerEl?.removeEventListener('click', onTriggerClick));\n cleanups.push(() => triggerEl?.removeEventListener('keydown', onTriggerKeydown));\n\n cleanupTrigger = () => {\n removeAria();\n\n for (const cleanup of cleanups) cleanup();\n };\n }\n\n rippleWatch(slots.elements('trigger'), resolveTrigger, { immediate: true });\n\n onMounted(() => {\n return () => {\n cleanupTrigger?.();\n cleanupTrigger = null;\n };\n });\n\n return html`\n <slot name=\"trigger\"></slot>\n <div\n class=\"menu-panel\"\n part=\"panel\"\n id=\"${menuId}\"\n role=\"menu\"\n aria-orientation=\"vertical\"\n @keydown=\"${handleMenuKeydown}\"\n ref=\"${(el: HTMLElement | null) => {\n panelEl = el;\n }}\">\n <slot></slot>\n </div>\n `;\n },\n styles: [componentStyles, sizeVariantMixin(), forcedColorsMixin],\n});\n","/* ========================================\n Popover UA resets — unlayered so they unconditionally beat\n the browser's [popover] UA stylesheet (padding / inset / border / margin).\n Must NOT be inside @layer; unlayered author rules win over every layer and\n every UA default.\n ======================================== */\n.tooltip {\n inset: unset;\n padding: calc(var(--size-0-5) / 2) var(--size-2) var(--size-0-5);\n margin: 0;\n overflow: visible;\n border: var(--_tooltip-border-width, var(--border-0)) solid var(--_tooltip-border-color, transparent);\n transform-origin: center;\n}\n\n@layer refine.base {\n :host {\n position: relative;\n display: inline-block;\n }\n\n .tooltip {\n --_tooltip-fg: var(--color-contrast-100);\n --_tooltip-bg: color-mix(in oklch, var(--color-contrast-900) 80%, transparent);\n --_tooltip-border-width: var(--border);\n --_tooltip-border-color: color-mix(in oklch, var(--color-contrast-100) 12%, transparent);\n --_tooltip-shadow: var(--shadow-md);\n --_tooltip-closed-transform: translateY(4px) scale(0.98);\n\n /* Positioning — JS sets top/left inline */\n position: fixed;\n max-width: var(--tooltip-max-width, var(--size-72));\n font-size: var(--text-xs);\n font-weight: var(--font-medium);\n line-height: var(--leading-normal);\n color: var(--_tooltip-fg);\n word-break: auto-phrase;\n white-space: normal;\n pointer-events: none;\n background: var(--_tooltip-bg);\n border-radius: var(--tooltip-radius, var(--rounded-lg));\n box-shadow: var(--_tooltip-shadow);\n\n /* Hidden by default (also serves as exit state) */\n opacity: 0;\n backdrop-filter: blur(var(--blur-sm));\n transform: var(--_tooltip-closed-transform);\n transition:\n opacity var(--transition-fast),\n transform var(--transition-fast),\n display var(--transition-fast) allow-discrete,\n overlay var(--transition-fast) allow-discrete;\n }\n\n @media (prefers-color-scheme: dark) {\n .tooltip {\n --_tooltip-fg: var(--color-contrast-900);\n --_tooltip-bg: color-mix(in oklch, var(--color-contrast-100) 80%, transparent);\n --_tooltip-border-color: color-mix(in oklch, var(--color-contrast-900) 12%, transparent);\n }\n }\n\n .tooltip-text {\n display: block;\n white-space: pre-line;\n }\n\n .tooltip[data-placement='top'] {\n --_tooltip-closed-transform: translateY(4px) scale(var(--overlay-enter-scale-dialog));\n }\n\n .tooltip[data-placement='bottom'] {\n --_tooltip-closed-transform: translateY(-4px) scale(var(--overlay-enter-scale-dialog));\n }\n\n .tooltip[data-placement='left'] {\n --_tooltip-closed-transform: translateX(4px) scale(var(--overlay-enter-scale-dialog));\n }\n\n .tooltip[data-placement='right'] {\n --_tooltip-closed-transform: translateX(-4px) scale(var(--overlay-enter-scale-dialog));\n }\n\n .tooltip[data-open] {\n display: block;\n }\n\n /* Entry animation via @starting-style */\n .tooltip:popover-open,\n .tooltip[data-open] {\n opacity: 1;\n transform: translate(0, 0) scale(1);\n transition:\n opacity var(--transition-normal),\n transform var(--transition-spring),\n display var(--transition-normal) allow-discrete,\n overlay var(--transition-normal) allow-discrete;\n will-change: opacity, transform;\n\n @starting-style {\n opacity: 0;\n transform: var(--_tooltip-closed-transform);\n }\n }\n}\n\n@layer refine.variants {\n /* Light tooltip */\n :host([variant='light']) .tooltip {\n --_tooltip-fg: var(--color-contrast-900);\n --_tooltip-bg: color-mix(in oklch, var(--color-contrast-100) 80%, transparent);\n --_tooltip-border-color: color-mix(in oklch, var(--color-contrast-900) 12%, transparent);\n --_tooltip-shadow: var(--shadow-md);\n }\n\n @media (prefers-color-scheme: dark) {\n :host([variant='light']) .tooltip {\n --_tooltip-fg: var(--color-contrast-100);\n --_tooltip-bg: color-mix(in oklch, var(--color-contrast-900) 80%, transparent);\n --_tooltip-border-color: color-mix(in oklch, var(--color-contrast-100) 12%, transparent);\n }\n }\n}\n\n@layer refine.utilities {\n :host([size='sm']) .tooltip {\n font-size: var(--text-xs);\n }\n\n :host([size='lg']) .tooltip {\n font-size: var(--text-base);\n }\n}\n","import type { Placement } from '@vielzeug/orbit';\n\nimport { createStableId, define, html, prop } from '@vielzeug/ore';\nimport { computed, signal } from '@vielzeug/ripple';\n\nimport type { ComponentSize } from '../../types';\n\nimport { parseStringTriggers } from '../../headless';\nimport { disablableBundle, sizableBundle } from '../../shared';\nimport { forcedColorsMixin } from '../../styles';\nimport { useFloatingTrigger } from '../shared/use-floating-trigger';\nimport styles from './tooltip.css?inline';\n\ntype TooltipPlacement = 'top' | 'bottom' | 'left' | 'right';\ntype TooltipTrigger = 'click' | 'focus' | 'hover';\n\nconst LEFT_GAP_COMPENSATION = 4;\nconst DEFAULT_TOOLTIP_TRIGGERS: TooltipTrigger[] = ['hover', 'focus'];\nconst VALID_TOOLTIP_TRIGGERS = new Set<TooltipTrigger>(['click', 'focus', 'hover']);\n\nconst parseDelayMs = (value: string | null): number => {\n if (value == null || value.trim() === '') return 0;\n\n const parsed = Number(value);\n\n return Number.isFinite(parsed) && parsed >= 0 ? parsed : 0;\n};\n\nconst parseOptionalBool = (value: string | null): boolean | undefined =>\n value == null ? undefined : value === '' || value === 'true';\n\nconst normalizeTriggers = (value: string | null | undefined): TooltipTrigger[] =>\n parseStringTriggers(value, VALID_TOOLTIP_TRIGGERS, DEFAULT_TOOLTIP_TRIGGERS);\n\n/** Tooltip component properties */\nexport type OreTooltipProps = {\n /** Hide delay in ms */\n 'close-delay'?: number;\n /** Tooltip text content */\n content?: string;\n /** Show delay in ms */\n delay?: number;\n /** Disable the tooltip */\n disabled?: boolean;\n /** Controlled open state */\n open?: boolean;\n /** Preferred placement relative to trigger */\n placement?: TooltipPlacement;\n /** Tooltip size */\n size?: ComponentSize;\n /** Which trigger(s) show/hide the tooltip */\n trigger?: string;\n /** Visual variant */\n variant?: 'dark' | 'light';\n};\n\n/**\n * A lightweight tooltip shown on hover/focus/click relative to the slotted trigger.\n *\n * @element ore-tooltip\n *\n * @attr {string} content - Tooltip text content\n * @attr {string} placement - 'top' | 'bottom' | 'left' | 'right' (default: 'top')\n * @attr {string} trigger - 'hover' | 'focus' | 'click' or comma-separated combination\n * @attr {number} delay - Show delay in milliseconds (default: 0)\n * @attr {string} size - Size: 'sm' | 'md' | 'lg'\n * @attr {string} variant - 'dark' (default) | 'light'\n * @attr {boolean} disabled - Disable the tooltip\n *\n * @slot - Trigger element that the tooltip is anchored to\n * @slot content - Complex tooltip content (overrides the `content` attribute)\n *\n * @cssprop --tooltip-max-width - Max width of the tooltip bubble\n *\n * @part tooltip - Tooltip container.\n * @example\n * ```html\n * <!-- Simple text tooltip -->\n * <ore-tooltip content=\"Copy to clipboard\">\n * <button>Copy</button>\n * </ore-tooltip>\n *\n * <!-- Placement and delay -->\n * <ore-tooltip content=\"Save your work\" placement=\"right\" delay=\"300\">\n * <ore-icon name=\"save\"></ore-icon>\n * </ore-tooltip>\n *\n * <!-- Hover + focus trigger -->\n * <ore-tooltip content=\"Required field\" trigger=\"hover,focus\" placement=\"top\">\n * <ore-input label=\"Email\" type=\"email\"></ore-input>\n * </ore-tooltip>\n *\n * <!-- Rich content slot -->\n * <ore-tooltip>\n * <ore-button>Help</ore-button>\n * <div slot=\"content\">\n * <strong>Keyboard shortcuts</strong>\n * <p>Press Ctrl+S to save.</p>\n * </div>\n * </ore-tooltip>\n * ```\n */\nexport const TOOLTIP_TAG = 'ore-tooltip' as const;\ndefine<OreTooltipProps>(TOOLTIP_TAG, {\n props: {\n ...sizableBundle,\n ...disablableBundle,\n 'close-delay': { default: 0, parse: parseDelayMs },\n content: prop.string(),\n delay: { default: 0, parse: parseDelayMs },\n open: { default: undefined as boolean | undefined, parse: parseOptionalBool },\n placement: prop.oneOf(['top', 'bottom', 'left', 'right'] as const, 'top'),\n trigger: prop.string('hover,focus'),\n variant: prop.string<'dark' | 'light'>(),\n },\n setup(props, { aria, el, onCleanup, onMounted, slots }) {\n const shadowRoot = el.shadowRoot;\n const isDisabled = computed(() => Boolean(props.disabled.value));\n const isControlled = computed(() => props.open.value !== undefined);\n const activePlacement = signal<TooltipPlacement>('top');\n const tooltipId = createStableId('tooltip');\n const triggers = computed<TooltipTrigger[]>(() => normalizeTriggers(props.trigger.value));\n let tooltipEl: HTMLElement | null = null;\n let showTimer: ReturnType<typeof setTimeout> | null = null;\n let hideTimer: ReturnType<typeof setTimeout> | null = null;\n\n const clearShowTimer = (): void => {\n if (!showTimer) return;\n\n clearTimeout(showTimer);\n showTimer = null;\n };\n const clearHideTimer = (): void => {\n if (!hideTimer) return;\n\n clearTimeout(hideTimer);\n hideTimer = null;\n };\n\n const floating = useFloatingTrigger({\n bindTriggerAria: (triggerEl) => aria(triggerEl, { describedby: () => tooltipId }),\n disabled: isDisabled,\n getPanel: () => tooltipEl,\n offset: 8,\n onCleanup,\n onPlacementChange: (p) => {\n const side = p.split('-')[0] as TooltipPlacement;\n\n activePlacement.value = side;\n\n if (side === 'left' && tooltipEl) {\n tooltipEl.style.left = `${parseFloat(tooltipEl.style.left) - LEFT_GAP_COMPENSATION}px`;\n }\n },\n openProp: props.open as typeof props.open & { value: boolean | undefined },\n placement: computed(() => props.placement.value as Placement),\n slot: () => shadowRoot?.querySelector<HTMLSlotElement>('slot:not([name])') ?? null,\n slotElements: slots.elements(),\n triggers: computed(() => [] as TooltipTrigger[]),\n });\n\n function show(): void {\n if (isControlled.value) return;\n\n if (isDisabled.value || (!props.content.value && !slots.has('content').value)) return;\n\n clearHideTimer();\n clearShowTimer();\n\n const delay = Number(props.delay.value) || 0;\n\n if (delay > 0) {\n showTimer = setTimeout(() => {\n showTimer = null;\n floating.open('hover');\n floating.updatePosition();\n }, delay);\n } else {\n floating.open('hover');\n floating.updatePosition();\n }\n }\n\n function hide(): void {\n if (isControlled.value) return;\n\n clearShowTimer();\n\n const closeDelay = Number(props['close-delay'].value) || 0;\n\n if (closeDelay > 0) {\n clearHideTimer();\n hideTimer = setTimeout(() => {\n hideTimer = null;\n floating.close('trigger');\n }, closeDelay);\n } else {\n floating.close('trigger');\n }\n }\n\n onMounted(() => {\n // Manually bind trigger events so we can wrap show/hide with delay timers.\n // useFloatingTrigger handles ARIA, positioning, controlled mode, and keyboard dismiss.\n const triggerSlot = shadowRoot?.querySelector<HTMLSlotElement>('slot:not([name])');\n let eventCleanups: Array<() => void> = [];\n\n const addEvent = (target: EventTarget, event: string, handler: EventListener): void => {\n target.addEventListener(event, handler);\n eventCleanups.push(() => target.removeEventListener(event, handler));\n };\n\n const bindTriggerEvents = (): void => {\n for (const cleanup of eventCleanups) cleanup();\n eventCleanups = [];\n\n const triggerEl = triggerSlot?.assignedElements({ flatten: true })[0] as HTMLElement | undefined;\n\n if (!triggerEl) return;\n\n const t = triggers.value;\n\n if (t.includes('hover')) {\n addEvent(triggerEl, 'pointerenter', show);\n addEvent(triggerEl, 'pointerleave', hide);\n }\n\n if (t.includes('focus')) {\n addEvent(triggerEl, 'focusin', show);\n addEvent(triggerEl, 'focusout', hide);\n }\n\n if (t.includes('click')) {\n addEvent(triggerEl, 'click', () => (floating.visible.value ? hide() : show()));\n }\n };\n\n triggerSlot?.addEventListener('slotchange', bindTriggerEvents);\n bindTriggerEvents();\n\n const destroyFloating = floating.mount();\n\n return () => {\n triggerSlot?.removeEventListener('slotchange', bindTriggerEvents);\n for (const cleanup of eventCleanups) cleanup();\n clearShowTimer();\n clearHideTimer();\n destroyFloating();\n };\n });\n\n return html`\n <slot></slot>\n <div\n class=\"tooltip\"\n part=\"tooltip\"\n id=\"${tooltipId}\"\n role=\"tooltip\"\n popover=\"manual\"\n ref=${(ref: HTMLElement) => {\n tooltipEl = ref;\n }}\n :data-placement=\"${activePlacement}\"\n :aria-hidden=\"${() => String(!floating.visible.value)}\">\n <slot name=\"content\"><span class=\"tooltip-text\">${props.content}</span></slot>\n </div>\n `;\n },\n styles: [forcedColorsMixin, styles],\n});\n"],"mappings":"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"}
|