@vielzeug/refine 26.10.0 → 26.10.5
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 +1 -1
- package/dist/accordion-item.cjs.map +1 -1
- package/dist/accordion-item.js.map +1 -1
- package/dist/accordion.cjs.map +1 -1
- package/dist/accordion.js.map +1 -1
- package/dist/async.cjs.map +1 -1
- package/dist/async.js.map +1 -1
- package/dist/badge.cjs.map +1 -1
- package/dist/badge.js.map +1 -1
- package/dist/box.cjs.map +1 -1
- package/dist/box.js.map +1 -1
- package/dist/button.cjs +3 -3
- package/dist/button.cjs.map +1 -1
- package/dist/button.js +3 -3
- package/dist/button.js.map +1 -1
- package/dist/calendar.cjs.map +1 -1
- package/dist/calendar.js.map +1 -1
- package/dist/carousel.cjs.map +1 -1
- package/dist/carousel.js.map +1 -1
- package/dist/chat-message.cjs.map +1 -1
- package/dist/chat-message.js.map +1 -1
- package/dist/chat-panel.cjs.map +1 -1
- package/dist/chat-panel.js.map +1 -1
- package/dist/checkbox-group.cjs.map +1 -1
- package/dist/checkbox-group.js.map +1 -1
- package/dist/chip.cjs.map +1 -1
- package/dist/chip.js.map +1 -1
- package/dist/code-window.cjs.map +1 -1
- package/dist/code-window.js.map +1 -1
- package/dist/combobox.cjs.map +1 -1
- package/dist/combobox.js.map +1 -1
- package/dist/command-palette.cjs +9 -1
- package/dist/command-palette.cjs.map +1 -1
- package/dist/command-palette.js +9 -1
- package/dist/command-palette.js.map +1 -1
- package/dist/content/card/card.css.cjs.map +1 -1
- package/dist/content/card/card.css.js.map +1 -1
- package/dist/content/carousel/carousel-slide.css.cjs.map +1 -1
- package/dist/content/carousel/carousel-slide.css.js.map +1 -1
- package/dist/content/carousel/carousel.css.cjs.map +1 -1
- package/dist/content/carousel/carousel.css.js.map +1 -1
- package/dist/content/carousel/carousel.d.ts +5 -5
- package/dist/content/chat-message/chat-message.css.cjs +1 -1
- package/dist/content/chat-message/chat-message.css.cjs.map +1 -1
- package/dist/content/chat-message/chat-message.css.js +1 -1
- package/dist/content/chat-message/chat-message.css.js.map +1 -1
- package/dist/content/chat-message/chat-message.d.ts +4 -4
- package/dist/content/chat-message/chat-message.d.ts.map +1 -1
- package/dist/content/chat-panel/chat-panel.d.ts +1 -1
- package/dist/content/code-window/code-window.css.cjs.map +1 -1
- package/dist/content/code-window/code-window.css.js.map +1 -1
- package/dist/content/code-window/code-window.d.ts +4 -4
- package/dist/content/index.d.ts +4 -0
- package/dist/content/index.d.ts.map +1 -1
- package/dist/content/list/_list-item-reveal.cjs.map +1 -1
- package/dist/content/list/_list-item-reveal.d.ts +4 -4
- package/dist/content/list/_list-item-reveal.d.ts.map +1 -1
- package/dist/content/list/_list-item-reveal.js.map +1 -1
- package/dist/content/list/list-item.css.cjs.map +1 -1
- package/dist/content/list/list-item.css.js.map +1 -1
- package/dist/content/list/list-item.d.ts +8 -8
- package/dist/content/list/list-item.d.ts.map +1 -1
- package/dist/content/list/list.d.ts +8 -8
- package/dist/content/list/list.d.ts.map +1 -1
- package/dist/content/qr-code/qr-code.d.ts +1 -1
- package/dist/content/rank-list/rank-item.css.cjs +2 -0
- package/dist/content/rank-list/rank-item.css.cjs.map +1 -0
- package/dist/content/rank-list/rank-item.css.js +2 -0
- package/dist/content/rank-list/rank-item.css.js.map +1 -0
- package/dist/content/rank-list/rank-item.d.ts +68 -0
- package/dist/content/rank-list/rank-item.d.ts.map +1 -0
- package/dist/content/rank-list/rank-list.css.cjs +2 -0
- package/dist/content/rank-list/rank-list.css.cjs.map +1 -0
- package/dist/content/rank-list/rank-list.css.js +2 -0
- package/dist/content/rank-list/rank-list.css.js.map +1 -0
- package/dist/content/rank-list/rank-list.d.ts +44 -0
- package/dist/content/rank-list/rank-list.d.ts.map +1 -0
- package/dist/content/separator/separator.d.ts +1 -1
- package/dist/content/separator/separator.d.ts.map +1 -1
- package/dist/content/speech-player/speech-player.css.cjs.map +1 -1
- package/dist/content/speech-player/speech-player.css.js.map +1 -1
- package/dist/content/speech-player/speech-player.d.ts +12 -12
- package/dist/content/speech-player/speech-player.d.ts.map +1 -1
- package/dist/content/stepper/step.css.cjs.map +1 -1
- package/dist/content/stepper/step.css.js.map +1 -1
- package/dist/content/stepper/step.d.ts +3 -3
- package/dist/content/stepper/step.d.ts.map +1 -1
- package/dist/content/stepper/stepper.css.cjs.map +1 -1
- package/dist/content/stepper/stepper.css.js.map +1 -1
- package/dist/content/stepper/stepper.d.ts +3 -3
- package/dist/content/stepper/stepper.d.ts.map +1 -1
- package/dist/content/table/table.css.cjs.map +1 -1
- package/dist/content/table/table.css.js.map +1 -1
- package/dist/content/table/table.d.ts +3 -3
- package/dist/content/table/table.d.ts.map +1 -1
- package/dist/content/text/text.css.cjs.map +1 -1
- package/dist/content/text/text.css.js.map +1 -1
- package/dist/content/text/text.d.ts +2 -2
- package/dist/content/text/text.d.ts.map +1 -1
- package/dist/cookie-banner.cjs.map +1 -1
- package/dist/cookie-banner.js.map +1 -1
- package/dist/copy-command.cjs +1 -1
- package/dist/copy-command.cjs.map +1 -1
- package/dist/copy-command.js +1 -1
- package/dist/copy-command.js.map +1 -1
- package/dist/core/announcer.cjs.map +1 -1
- package/dist/core/announcer.d.ts +2 -2
- package/dist/core/announcer.js.map +1 -1
- package/dist/core/aria-reflection.cjs.map +1 -1
- package/dist/core/aria-reflection.d.ts +3 -3
- package/dist/core/aria-reflection.js.map +1 -1
- package/dist/core/auto-resize.cjs.map +1 -1
- package/dist/core/auto-resize.d.ts +1 -1
- package/dist/core/auto-resize.js.map +1 -1
- package/dist/core/checkable.cjs.map +1 -1
- package/dist/core/checkable.d.ts +2 -2
- package/dist/core/checkable.d.ts.map +1 -1
- package/dist/core/checkable.js.map +1 -1
- package/dist/core/choice-field.cjs.map +1 -1
- package/dist/core/choice-field.d.ts +3 -3
- package/dist/core/choice-field.d.ts.map +1 -1
- package/dist/core/choice-field.js.map +1 -1
- package/dist/core/composer.cjs.map +1 -1
- package/dist/core/composer.d.ts +4 -4
- package/dist/core/composer.d.ts.map +1 -1
- package/dist/core/composer.js.map +1 -1
- package/dist/core/date-picker.cjs.map +1 -1
- package/dist/core/date-picker.d.ts +5 -5
- package/dist/core/date-picker.d.ts.map +1 -1
- package/dist/core/date-picker.js.map +1 -1
- package/dist/core/direction.cjs.map +1 -1
- package/dist/core/direction.d.ts +1 -1
- package/dist/core/direction.js.map +1 -1
- package/dist/core/field-base.cjs.map +1 -1
- package/dist/core/field-base.d.ts +9 -9
- package/dist/core/field-base.d.ts.map +1 -1
- package/dist/core/field-base.js.map +1 -1
- package/dist/core/focus.cjs.map +1 -1
- package/dist/core/focus.d.ts +1 -1
- package/dist/core/focus.js.map +1 -1
- package/dist/core/icon-registry.cjs.map +1 -1
- package/dist/core/icon-registry.d.ts +1 -1
- package/dist/core/icon-registry.js.map +1 -1
- package/dist/core/icons.cjs.map +1 -1
- package/dist/core/icons.js.map +1 -1
- package/dist/core/keyboard.cjs.map +1 -1
- package/dist/core/keyboard.d.ts +1 -1
- package/dist/core/keyboard.js.map +1 -1
- package/dist/core/numbers.cjs.map +1 -1
- package/dist/core/numbers.d.ts +1 -1
- package/dist/core/numbers.js.map +1 -1
- package/dist/core/overlay.cjs.map +1 -1
- package/dist/core/overlay.d.ts +6 -6
- package/dist/core/overlay.js.map +1 -1
- package/dist/core/parse.cjs.map +1 -1
- package/dist/core/parse.d.ts +1 -1
- package/dist/core/parse.js.map +1 -1
- package/dist/core/positioner.cjs.map +1 -1
- package/dist/core/positioner.d.ts +3 -3
- package/dist/core/positioner.js.map +1 -1
- package/dist/core/ref-callback.cjs.map +1 -1
- package/dist/core/ref-callback.d.ts +2 -2
- package/dist/core/ref-callback.d.ts.map +1 -1
- package/dist/core/ref-callback.js.map +1 -1
- package/dist/core/text-field.cjs.map +1 -1
- package/dist/core/text-field.d.ts +6 -6
- package/dist/core/text-field.d.ts.map +1 -1
- package/dist/core/text-field.js.map +1 -1
- package/dist/counter.cjs +1 -0
- package/dist/counter.cjs.map +1 -1
- package/dist/counter.js +1 -0
- package/dist/counter.js.map +1 -1
- package/dist/custom-elements.json +334 -87
- package/dist/datagrid.cjs.map +1 -1
- package/dist/datagrid.js.map +1 -1
- package/dist/date-picker.cjs +1 -1
- package/dist/date-picker.cjs.map +1 -1
- package/dist/date-picker.js +1 -1
- package/dist/date-picker.js.map +1 -1
- package/dist/dialog.cjs.map +1 -1
- package/dist/dialog.js.map +1 -1
- package/dist/disclosure/accordion-item/accordion-item.css.cjs +1 -1
- package/dist/disclosure/accordion-item/accordion-item.css.cjs.map +1 -1
- package/dist/disclosure/accordion-item/accordion-item.css.js +1 -1
- package/dist/disclosure/accordion-item/accordion-item.css.js.map +1 -1
- package/dist/disclosure/tab-item/tab-item.d.ts +1 -1
- package/dist/disclosure/tab-item/tab-item.d.ts.map +1 -1
- package/dist/drawer.cjs.map +1 -1
- package/dist/drawer.js.map +1 -1
- package/dist/feedback/alert/alert.css.cjs.map +1 -1
- package/dist/feedback/alert/alert.css.js.map +1 -1
- package/dist/feedback/badge/badge.css.cjs.map +1 -1
- package/dist/feedback/badge/badge.css.js.map +1 -1
- package/dist/feedback/badge/badge.d.ts +1 -1
- package/dist/feedback/badge/badge.d.ts.map +1 -1
- package/dist/feedback/chip/chip.css.cjs.map +1 -1
- package/dist/feedback/chip/chip.css.js.map +1 -1
- package/dist/feedback/chip/chip.d.ts +3 -3
- package/dist/feedback/chip/chip.d.ts.map +1 -1
- package/dist/feedback/cookie-banner/cookie-banner.css.cjs.map +1 -1
- package/dist/feedback/cookie-banner/cookie-banner.css.js.map +1 -1
- package/dist/feedback/cookie-banner/cookie-banner.d.ts +8 -8
- package/dist/feedback/cookie-banner/cookie-banner.d.ts.map +1 -1
- package/dist/feedback/progress/progress.css.cjs.map +1 -1
- package/dist/feedback/progress/progress.css.js.map +1 -1
- package/dist/feedback/progress/progress.d.ts +1 -1
- package/dist/feedback/progress/progress.d.ts.map +1 -1
- package/dist/feedback/skeleton/skeleton.css.cjs.map +1 -1
- package/dist/feedback/skeleton/skeleton.css.js.map +1 -1
- package/dist/feedback/skeleton/skeleton.d.ts +1 -1
- package/dist/feedback/skeleton/skeleton.d.ts.map +1 -1
- package/dist/feedback/toast/toast.css.cjs +1 -1
- package/dist/feedback/toast/toast.css.cjs.map +1 -1
- package/dist/feedback/toast/toast.css.js +1 -1
- package/dist/feedback/toast/toast.css.js.map +1 -1
- package/dist/feedback/toast/toast.d.ts +1 -1
- package/dist/feedback/toast/toast.d.ts.map +1 -1
- package/dist/feedback/typing-indicator/typing-indicator.d.ts +2 -2
- package/dist/file-input.cjs +1 -1
- package/dist/file-input.cjs.map +1 -1
- package/dist/file-input.js +1 -1
- package/dist/file-input.js.map +1 -1
- package/dist/frameworks/elements.d.ts +1 -1
- package/dist/grid-item.cjs.map +1 -1
- package/dist/grid-item.js.map +1 -1
- package/dist/grid.cjs.map +1 -1
- package/dist/grid.js.map +1 -1
- package/dist/icon.cjs.map +1 -1
- package/dist/icon.js.map +1 -1
- package/dist/input.cjs.map +1 -1
- package/dist/input.js.map +1 -1
- package/dist/inputs/button/button.css.cjs.map +1 -1
- package/dist/inputs/button/button.css.js.map +1 -1
- package/dist/inputs/button/button.d.ts +3 -3
- package/dist/inputs/button/button.d.ts.map +1 -1
- package/dist/inputs/calendar/calendar.css.cjs.map +1 -1
- package/dist/inputs/calendar/calendar.css.js.map +1 -1
- package/dist/inputs/calendar/calendar.d.ts +2 -2
- package/dist/inputs/checkbox-group/checkbox-group.d.ts +2 -2
- package/dist/inputs/checkbox-group/checkbox-group.d.ts.map +1 -1
- package/dist/inputs/combobox/combobox.css.cjs.map +1 -1
- package/dist/inputs/combobox/combobox.css.js.map +1 -1
- package/dist/inputs/counter/counter.css.cjs +1 -1
- package/dist/inputs/counter/counter.css.cjs.map +1 -1
- package/dist/inputs/counter/counter.css.js +1 -1
- package/dist/inputs/counter/counter.css.js.map +1 -1
- package/dist/inputs/counter/counter.d.ts +2 -1
- package/dist/inputs/counter/counter.d.ts.map +1 -1
- package/dist/inputs/datagrid/datagrid.css.cjs.map +1 -1
- package/dist/inputs/datagrid/datagrid.css.js.map +1 -1
- package/dist/inputs/datagrid/datagrid.d.ts +5 -5
- package/dist/inputs/date-picker/date-picker.css.cjs.map +1 -1
- package/dist/inputs/date-picker/date-picker.css.js.map +1 -1
- package/dist/inputs/date-picker/date-picker.d.ts +1 -1
- package/dist/inputs/file-input/file-input-upload.cjs.map +1 -1
- package/dist/inputs/file-input/file-input-upload.d.ts +6 -6
- package/dist/inputs/file-input/file-input-upload.js.map +1 -1
- package/dist/inputs/file-input/file-input.css.cjs.map +1 -1
- package/dist/inputs/file-input/file-input.css.js.map +1 -1
- package/dist/inputs/file-input/file-input.d.ts +6 -6
- package/dist/inputs/input/input.css.cjs +1 -1
- package/dist/inputs/input/input.css.cjs.map +1 -1
- package/dist/inputs/input/input.css.js +1 -1
- package/dist/inputs/input/input.css.js.map +1 -1
- package/dist/inputs/input/input.d.ts +6 -6
- package/dist/inputs/input/input.d.ts.map +1 -1
- package/dist/inputs/message-composer/message-composer.css.cjs.map +1 -1
- package/dist/inputs/message-composer/message-composer.css.js.map +1 -1
- package/dist/inputs/message-composer/message-composer.d.ts +7 -7
- package/dist/inputs/message-composer/message-composer.d.ts.map +1 -1
- package/dist/inputs/number-input/number-input.css.cjs.map +1 -1
- package/dist/inputs/number-input/number-input.css.js.map +1 -1
- package/dist/inputs/number-input/number-input.d.ts +2 -2
- package/dist/inputs/otp-input/otp-input.css.cjs.map +1 -1
- package/dist/inputs/otp-input/otp-input.css.js.map +1 -1
- package/dist/inputs/qr-scanner/qr-scanner.d.ts +1 -1
- package/dist/inputs/qr-scanner/qr-scanner.d.ts.map +1 -1
- package/dist/inputs/rating/rating.d.ts +1 -1
- package/dist/inputs/rating/rating.d.ts.map +1 -1
- package/dist/inputs/select/select.css.cjs +1 -1
- package/dist/inputs/select/select.css.cjs.map +1 -1
- package/dist/inputs/select/select.css.js +1 -1
- package/dist/inputs/select/select.css.js.map +1 -1
- package/dist/inputs/select/select.d.ts +1 -1
- package/dist/inputs/select/select.d.ts.map +1 -1
- package/dist/inputs/shared/field-binding.cjs.map +1 -1
- package/dist/inputs/shared/field-binding.d.ts +2 -2
- package/dist/inputs/shared/field-binding.d.ts.map +1 -1
- package/dist/inputs/shared/field-binding.js.map +1 -1
- package/dist/inputs/shared/native-field-event.cjs.map +1 -1
- package/dist/inputs/shared/native-field-event.d.ts +1 -1
- package/dist/inputs/shared/native-field-event.js.map +1 -1
- package/dist/inputs/shared/templates.cjs.map +1 -1
- package/dist/inputs/shared/templates.d.ts +3 -3
- package/dist/inputs/shared/templates.js.map +1 -1
- package/dist/inputs/slider/slider.css.cjs.map +1 -1
- package/dist/inputs/slider/slider.css.js.map +1 -1
- package/dist/inputs/slider/slider.d.ts +1 -1
- package/dist/inputs/slider/slider.d.ts.map +1 -1
- package/dist/inputs/textarea/textarea.css.cjs.map +1 -1
- package/dist/inputs/textarea/textarea.css.js.map +1 -1
- package/dist/inputs/textarea/textarea.d.ts +1 -1
- package/dist/inputs/time-picker/time-picker.css.cjs.map +1 -1
- package/dist/inputs/time-picker/time-picker.css.js.map +1 -1
- package/dist/inputs/time-picker/time-picker.d.ts +1 -1
- package/dist/layout/box/box.css.cjs.map +1 -1
- package/dist/layout/box/box.css.js.map +1 -1
- package/dist/layout/box/box.d.ts +1 -1
- package/dist/layout/grid/grid.d.ts +1 -1
- package/dist/layout/grid-item/grid-item.d.ts +3 -3
- package/dist/layout/grid-item/grid-item.d.ts.map +1 -1
- package/dist/layout/navbar/navbar.css.cjs +1 -1
- package/dist/layout/navbar/navbar.css.cjs.map +1 -1
- package/dist/layout/navbar/navbar.css.js +1 -1
- package/dist/layout/navbar/navbar.css.js.map +1 -1
- package/dist/layout/navbar/navbar.d.ts +3 -3
- package/dist/layout/sidebar/sidebar-item.css.cjs.map +1 -1
- package/dist/layout/sidebar/sidebar-item.css.js.map +1 -1
- package/dist/layout/sidebar/sidebar.d.ts +5 -5
- package/dist/layout/sidebar/sidebar.d.ts.map +1 -1
- package/dist/list-item.cjs.map +1 -1
- package/dist/list-item.js.map +1 -1
- package/dist/list.cjs.map +1 -1
- package/dist/list.js.map +1 -1
- package/dist/menu.cjs +6 -5
- package/dist/menu.cjs.map +1 -1
- package/dist/menu.js +6 -5
- package/dist/menu.js.map +1 -1
- package/dist/message-composer.cjs.map +1 -1
- package/dist/message-composer.js.map +1 -1
- package/dist/navbar.cjs.map +1 -1
- package/dist/navbar.js.map +1 -1
- package/dist/number-input.cjs.map +1 -1
- package/dist/number-input.js.map +1 -1
- package/dist/otp-input.cjs.map +1 -1
- package/dist/otp-input.js.map +1 -1
- package/dist/overlay/command-palette/command-palette-items.cjs.map +1 -1
- package/dist/overlay/command-palette/command-palette-items.d.ts +1 -1
- package/dist/overlay/command-palette/command-palette-items.js.map +1 -1
- package/dist/overlay/command-palette/command-palette.css.cjs +1 -1
- package/dist/overlay/command-palette/command-palette.css.cjs.map +1 -1
- package/dist/overlay/command-palette/command-palette.css.js +1 -1
- package/dist/overlay/command-palette/command-palette.css.js.map +1 -1
- package/dist/overlay/command-palette/command-palette.d.ts +7 -3
- package/dist/overlay/command-palette/command-palette.d.ts.map +1 -1
- package/dist/overlay/command-palette/command-palette.types.d.ts +16 -6
- package/dist/overlay/command-palette/command-palette.types.d.ts.map +1 -1
- package/dist/overlay/dialog/dialog.css.cjs +1 -1
- package/dist/overlay/dialog/dialog.css.cjs.map +1 -1
- package/dist/overlay/dialog/dialog.css.js +1 -1
- package/dist/overlay/dialog/dialog.css.js.map +1 -1
- package/dist/overlay/dialog/dialog.d.ts +2 -2
- package/dist/overlay/dialog/dialog.d.ts.map +1 -1
- package/dist/overlay/drawer/drawer.css.cjs.map +1 -1
- package/dist/overlay/drawer/drawer.css.js.map +1 -1
- package/dist/overlay/drawer/drawer.d.ts +1 -1
- package/dist/overlay/drawer/drawer.d.ts.map +1 -1
- package/dist/overlay/menu/menu-item.css.cjs.map +1 -1
- package/dist/overlay/menu/menu-item.css.js.map +1 -1
- package/dist/overlay/menu/menu.d.ts.map +1 -1
- package/dist/overlay/shared/use-dialog.cjs.map +1 -1
- package/dist/overlay/shared/use-dialog.d.ts +6 -6
- package/dist/overlay/shared/use-dialog.d.ts.map +1 -1
- package/dist/overlay/shared/use-dialog.js.map +1 -1
- package/dist/overlay/shared/use-floating-trigger.cjs.map +1 -1
- package/dist/overlay/shared/use-floating-trigger.d.ts +1 -1
- package/dist/overlay/shared/use-floating-trigger.d.ts.map +1 -1
- package/dist/overlay/shared/use-floating-trigger.js.map +1 -1
- package/dist/overlay/tooltip/tooltip.css.cjs.map +1 -1
- package/dist/overlay/tooltip/tooltip.css.js.map +1 -1
- package/dist/progress.cjs.map +1 -1
- package/dist/progress.js.map +1 -1
- package/dist/qr-code.cjs.map +1 -1
- package/dist/qr-code.js.map +1 -1
- package/dist/qr-scanner.cjs.map +1 -1
- package/dist/qr-scanner.js.map +1 -1
- package/dist/radio-group.cjs.map +1 -1
- package/dist/radio-group.js.map +1 -1
- package/dist/radio.cjs.map +1 -1
- package/dist/radio.js.map +1 -1
- package/dist/rank-item.cjs +21 -0
- package/dist/rank-item.cjs.map +1 -0
- package/dist/rank-item.js +21 -0
- package/dist/rank-item.js.map +1 -0
- package/dist/rank-list.cjs +4 -0
- package/dist/rank-list.cjs.map +1 -0
- package/dist/rank-list.js +4 -0
- package/dist/rank-list.js.map +1 -0
- package/dist/rating.cjs.map +1 -1
- package/dist/rating.js.map +1 -1
- package/dist/refine.cjs +111 -80
- package/dist/refine.cjs.map +1 -1
- package/dist/refine.iife.js +111 -80
- package/dist/refine.iife.js.map +1 -1
- package/dist/refine.js +112 -81
- package/dist/refine.js.map +1 -1
- package/dist/select.cjs.map +1 -1
- package/dist/select.js.map +1 -1
- package/dist/separator.cjs.map +1 -1
- package/dist/separator.js.map +1 -1
- package/dist/shared/index.d.ts +3 -3
- package/dist/shared/size-presets.cjs.map +1 -1
- package/dist/shared/size-presets.d.ts +4 -4
- package/dist/shared/size-presets.js.map +1 -1
- package/dist/shared/types.d.ts +1 -1
- package/dist/sidebar.cjs.map +1 -1
- package/dist/sidebar.js.map +1 -1
- package/dist/skeleton.cjs.map +1 -1
- package/dist/skeleton.js.map +1 -1
- package/dist/slider.cjs.map +1 -1
- package/dist/slider.js.map +1 -1
- package/dist/speech-player.cjs.map +1 -1
- package/dist/speech-player.js.map +1 -1
- package/dist/step.cjs.map +1 -1
- package/dist/step.js.map +1 -1
- package/dist/stepper.cjs.map +1 -1
- package/dist/stepper.js.map +1 -1
- package/dist/styles/fouc.css +2 -2
- package/dist/styles/mixins/accessibility.css.cjs.map +1 -1
- package/dist/styles/mixins/accessibility.css.d.ts +4 -4
- package/dist/styles/mixins/accessibility.css.js.map +1 -1
- package/dist/styles/mixins/animation.css.cjs +2 -2
- package/dist/styles/mixins/animation.css.cjs.map +1 -1
- package/dist/styles/mixins/animation.css.d.ts +4 -4
- package/dist/styles/mixins/animation.css.js +2 -2
- package/dist/styles/mixins/animation.css.js.map +1 -1
- package/dist/styles/mixins/field-variants.css.cjs +2 -2
- package/dist/styles/mixins/field-variants.css.cjs.map +1 -1
- package/dist/styles/mixins/field-variants.css.d.ts +6 -6
- package/dist/styles/mixins/field-variants.css.d.ts.map +1 -1
- package/dist/styles/mixins/field-variants.css.js +2 -2
- package/dist/styles/mixins/field-variants.css.js.map +1 -1
- package/dist/styles/mixins/shape.css.cjs.map +1 -1
- package/dist/styles/mixins/shape.css.d.ts +9 -9
- package/dist/styles/mixins/shape.css.d.ts.map +1 -1
- package/dist/styles/mixins/shape.css.js.map +1 -1
- package/dist/styles/mixins/variants.css.cjs.map +1 -1
- package/dist/styles/mixins/variants.css.d.ts +1 -1
- package/dist/styles/mixins/variants.css.js.map +1 -1
- package/dist/styles/theme.css +36 -28
- package/dist/tab-item.cjs.map +1 -1
- package/dist/tab-item.js.map +1 -1
- package/dist/tab-panel.cjs.map +1 -1
- package/dist/tab-panel.js.map +1 -1
- package/dist/table.cjs.map +1 -1
- package/dist/table.js.map +1 -1
- package/dist/text.cjs.map +1 -1
- package/dist/text.js.map +1 -1
- package/dist/textarea.cjs.map +1 -1
- package/dist/textarea.js.map +1 -1
- package/dist/theme.cjs.map +1 -1
- package/dist/theme.d.ts +2 -2
- package/dist/theme.js.map +1 -1
- package/dist/time-picker.cjs +1 -1
- package/dist/time-picker.cjs.map +1 -1
- package/dist/time-picker.js +1 -1
- package/dist/time-picker.js.map +1 -1
- package/dist/toast.cjs.map +1 -1
- package/dist/toast.js.map +1 -1
- package/dist/types/elements.d.ts +6 -2
- package/dist/typing-indicator.cjs.map +1 -1
- package/dist/typing-indicator.js.map +1 -1
- package/dist/utils/css.cjs.map +1 -1
- package/dist/utils/css.js.map +1 -1
- package/dist/utils/link.cjs.map +1 -1
- package/dist/utils/link.d.ts +2 -2
- package/dist/utils/link.js.map +1 -1
- package/package.json +31 -14
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icon-registry.cjs","names":[],"sources":["../../src/core/icon-registry.ts"],"sourcesContent":["/**\n * The synchronous icon registry `ore-icon` resolves names from. Kept as a leaf\n * module (no component imports) so both `icon.ts` and icon-set modules can\n * import it without cycles. It starts with the icons refine's own components\n * render (`core/icons.ts`) and grows through `registerIcons()`.\n */\n\n/** One icon: SVG child tags with their attributes, in render order. */\nexport type IconNode = Array<[string, Record<string, string | number | undefined>]>;\n\nconst registry = new Map<string, IconNode>();\n\n/**\n * Register icons (or override existing ones) by name. Keys may be kebab-case or\n * PascalCase
|
|
1
|
+
{"version":3,"file":"icon-registry.cjs","names":[],"sources":["../../src/core/icon-registry.ts"],"sourcesContent":["/**\n * The synchronous icon registry `ore-icon` resolves names from. Kept as a leaf\n * module (no component imports) so both `icon.ts` and icon-set modules can\n * import it without cycles. It starts with the icons refine's own components\n * render (`core/icons.ts`) and grows through `registerIcons()`.\n */\n\n/** One icon: SVG child tags with their attributes, in render order. */\nexport type IconNode = Array<[string, Record<string, string | number | undefined>]>;\n\nconst registry = new Map<string, IconNode>();\n\n/**\n * Register icons (or override existing ones) by name. Keys may be kebab-case or\n * PascalCase: both resolve.\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 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\nexport const resolveIcon = (name: string): IconNode | undefined =>\n registry.get(name) ?? registry.get(toPascalCase(name));\n"],"mappings":"AAUA,IAAM,EAAW,IAAI,IAMrB,SAAgB,cAAc,EAAuC,CACnE,IAAK,GAAM,CAAC,EAAM,KAAS,OAAO,QAAQ,CAAK,EAC7C,EAAS,IAAI,EAAM,CAAI,CAE3B,CAEA,IAAM,aAAgB,GACpB,EACG,QAAQ,qBAAsB,OAAO,CAAC,CACtC,MAAM,eAAe,CAAC,CACtB,OAAO,OAAO,CAAC,CACf,IAAK,GAAM,EAAE,OAAO,CAAC,CAAC,CAAC,YAAY,EAAI,EAAE,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAChE,KAAK,EAAE,EAEC,YAAe,GAC1B,EAAS,IAAI,CAAI,GAAK,EAAS,IAAI,aAAa,CAAI,CAAC"}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
export type IconNode = Array<[string, Record<string, string | number | undefined>]>;
|
|
9
9
|
/**
|
|
10
10
|
* Register icons (or override existing ones) by name. Keys may be kebab-case or
|
|
11
|
-
* PascalCase
|
|
11
|
+
* PascalCase: both resolve.
|
|
12
12
|
*/
|
|
13
13
|
export declare function registerIcons(icons: Record<string, IconNode>): void;
|
|
14
14
|
export declare const resolveIcon: (name: string) => IconNode | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icon-registry.js","names":[],"sources":["../../src/core/icon-registry.ts"],"sourcesContent":["/**\n * The synchronous icon registry `ore-icon` resolves names from. Kept as a leaf\n * module (no component imports) so both `icon.ts` and icon-set modules can\n * import it without cycles. It starts with the icons refine's own components\n * render (`core/icons.ts`) and grows through `registerIcons()`.\n */\n\n/** One icon: SVG child tags with their attributes, in render order. */\nexport type IconNode = Array<[string, Record<string, string | number | undefined>]>;\n\nconst registry = new Map<string, IconNode>();\n\n/**\n * Register icons (or override existing ones) by name. Keys may be kebab-case or\n * PascalCase
|
|
1
|
+
{"version":3,"file":"icon-registry.js","names":[],"sources":["../../src/core/icon-registry.ts"],"sourcesContent":["/**\n * The synchronous icon registry `ore-icon` resolves names from. Kept as a leaf\n * module (no component imports) so both `icon.ts` and icon-set modules can\n * import it without cycles. It starts with the icons refine's own components\n * render (`core/icons.ts`) and grows through `registerIcons()`.\n */\n\n/** One icon: SVG child tags with their attributes, in render order. */\nexport type IconNode = Array<[string, Record<string, string | number | undefined>]>;\n\nconst registry = new Map<string, IconNode>();\n\n/**\n * Register icons (or override existing ones) by name. Keys may be kebab-case or\n * PascalCase: both resolve.\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 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\nexport const resolveIcon = (name: string): IconNode | undefined =>\n registry.get(name) ?? registry.get(toPascalCase(name));\n"],"mappings":"AAUA,IAAM,EAAW,IAAI,IAMrB,SAAgB,cAAc,EAAuC,CACnE,IAAK,GAAM,CAAC,EAAM,KAAS,OAAO,QAAQ,CAAK,EAC7C,EAAS,IAAI,EAAM,CAAI,CAE3B,CAEA,IAAM,aAAgB,GACpB,EACG,QAAQ,qBAAsB,OAAO,CAAC,CACtC,MAAM,eAAe,CAAC,CACtB,OAAO,OAAO,CAAC,CACf,IAAK,GAAM,EAAE,OAAO,CAAC,CAAC,CAAC,YAAY,EAAI,EAAE,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAChE,KAAK,EAAE,EAEC,YAAe,GAC1B,EAAS,IAAI,CAAI,GAAK,EAAS,IAAI,aAAa,CAAI,CAAC"}
|
package/dist/core/icons.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icons.cjs","names":[],"sources":["../../src/core/icons.ts"],"sourcesContent":["/**\n * The icons refine's own components render
|
|
1
|
+
{"version":3,"file":"icons.cjs","names":[],"sources":["../../src/core/icons.ts"],"sourcesContent":["/**\n * The icons refine's own components render: chevrons, close marks, spinners,\n * the icons inputs and overlays label themselves with. Imported by `icon.ts`\n * so they resolve wherever `ore-icon` is used. Apps needing more than this set\n * register their own via `registerIcons()` or import `@vielzeug/refine/icon-lucide`\n * for the complete Lucide library.\n */\nimport {\n AlertCircle,\n ArrowRight,\n ArrowUpDown,\n Calendar,\n Camera,\n ChartLine,\n Check,\n ChevronDown,\n ChevronLeft,\n ChevronRight,\n ChevronsLeft,\n ChevronsRight,\n CircleAlert,\n Clock,\n Columns2,\n Copy,\n Eye,\n EyeOff,\n File,\n Filter,\n Gauge,\n Loader2,\n Mail,\n Menu,\n Minus,\n Package,\n Pause,\n Play,\n Plus,\n RefreshCw,\n Save,\n Search,\n Square,\n Star,\n Trash2,\n TriangleAlert,\n Upload,\n User,\n X,\n Zap,\n} from 'lucide';\nimport { registerIcons } from './icon-registry';\n\nregisterIcons({\n AlertCircle: AlertCircle,\n ArrowRight: ArrowRight,\n ArrowUpDown: ArrowUpDown,\n Calendar: Calendar,\n Camera: Camera,\n ChartLine: ChartLine,\n Check: Check,\n ChevronDown: ChevronDown,\n ChevronLeft: ChevronLeft,\n ChevronRight: ChevronRight,\n ChevronsLeft: ChevronsLeft,\n ChevronsRight: ChevronsRight,\n CircleAlert: CircleAlert,\n Clock: Clock,\n Columns2: Columns2,\n Copy: Copy,\n Eye: Eye,\n EyeOff: EyeOff,\n File: File,\n Filter: Filter,\n Gauge: Gauge,\n Loader2: Loader2,\n Mail: Mail,\n Menu: Menu,\n Minus: Minus,\n Package: Package,\n Pause: Pause,\n Play: Play,\n Plus: Plus,\n RefreshCw: RefreshCw,\n Save: Save,\n Search: Search,\n Square: Square,\n Star: Star,\n Trash2: Trash2,\n TriangleAlert: TriangleAlert,\n Upload: Upload,\n User: User,\n X: X,\n Zap: Zap,\n});\n"],"mappings":"+DAmDA,EAAA,cAAc,CACC,YAAA,EAAA,YACD,WAAA,EAAA,WACC,YAAA,EAAA,YACH,SAAA,EAAA,SACF,OAAA,EAAA,OACG,UAAA,EAAA,UACJ,MAAA,EAAA,MACM,YAAA,EAAA,YACA,YAAA,EAAA,YACC,aAAA,EAAA,aACA,aAAA,EAAA,aACC,cAAA,EAAA,cACF,YAAA,EAAA,YACN,MAAA,EAAA,MACG,SAAA,EAAA,SACJ,KAAA,EAAA,KACD,IAAA,EAAA,IACG,OAAA,EAAA,OACF,KAAA,EAAA,KACE,OAAA,EAAA,OACD,MAAA,EAAA,MACE,QAAA,EAAA,QACH,KAAA,EAAA,KACA,KAAA,EAAA,KACC,MAAA,EAAA,MACE,QAAA,EAAA,QACF,MAAA,EAAA,MACD,KAAA,EAAA,KACA,KAAA,EAAA,KACK,UAAA,EAAA,UACL,KAAA,EAAA,KACE,OAAA,EAAA,OACA,OAAA,EAAA,OACF,KAAA,EAAA,KACE,OAAA,EAAA,OACO,cAAA,EAAA,cACP,OAAA,EAAA,OACF,KAAA,EAAA,KACH,EAAA,EAAA,EACE,IAAA,EAAA,GACP,CAAC"}
|
package/dist/core/icons.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icons.js","names":[],"sources":["../../src/core/icons.ts"],"sourcesContent":["/**\n * The icons refine's own components render
|
|
1
|
+
{"version":3,"file":"icons.js","names":[],"sources":["../../src/core/icons.ts"],"sourcesContent":["/**\n * The icons refine's own components render: chevrons, close marks, spinners,\n * the icons inputs and overlays label themselves with. Imported by `icon.ts`\n * so they resolve wherever `ore-icon` is used. Apps needing more than this set\n * register their own via `registerIcons()` or import `@vielzeug/refine/icon-lucide`\n * for the complete Lucide library.\n */\nimport {\n AlertCircle,\n ArrowRight,\n ArrowUpDown,\n Calendar,\n Camera,\n ChartLine,\n Check,\n ChevronDown,\n ChevronLeft,\n ChevronRight,\n ChevronsLeft,\n ChevronsRight,\n CircleAlert,\n Clock,\n Columns2,\n Copy,\n Eye,\n EyeOff,\n File,\n Filter,\n Gauge,\n Loader2,\n Mail,\n Menu,\n Minus,\n Package,\n Pause,\n Play,\n Plus,\n RefreshCw,\n Save,\n Search,\n Square,\n Star,\n Trash2,\n TriangleAlert,\n Upload,\n User,\n X,\n Zap,\n} from 'lucide';\nimport { registerIcons } from './icon-registry';\n\nregisterIcons({\n AlertCircle: AlertCircle,\n ArrowRight: ArrowRight,\n ArrowUpDown: ArrowUpDown,\n Calendar: Calendar,\n Camera: Camera,\n ChartLine: ChartLine,\n Check: Check,\n ChevronDown: ChevronDown,\n ChevronLeft: ChevronLeft,\n ChevronRight: ChevronRight,\n ChevronsLeft: ChevronsLeft,\n ChevronsRight: ChevronsRight,\n CircleAlert: CircleAlert,\n Clock: Clock,\n Columns2: Columns2,\n Copy: Copy,\n Eye: Eye,\n EyeOff: EyeOff,\n File: File,\n Filter: Filter,\n Gauge: Gauge,\n Loader2: Loader2,\n Mail: Mail,\n Menu: Menu,\n Minus: Minus,\n Package: Package,\n Pause: Pause,\n Play: Play,\n Plus: Plus,\n RefreshCw: RefreshCw,\n Save: Save,\n Search: Search,\n Square: Square,\n Star: Star,\n Trash2: Trash2,\n TriangleAlert: TriangleAlert,\n Upload: Upload,\n User: User,\n X: X,\n Zap: Zap,\n});\n"],"mappings":"wkBAmDA,EAAc,CACC,cACD,aACC,cACH,WACF,SACG,YACJ,QACM,cACA,cACC,eACA,eACC,gBACF,cACN,QACG,WACJ,OACD,MACG,SACF,OACE,SACD,QACE,UACH,OACA,OACC,QACE,UACF,QACD,OACA,OACK,YACL,OACE,SACA,SACF,OACE,SACO,gBACP,SACF,OACH,IACE,KACP,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyboard.cjs","names":[],"sources":["../../src/core/keyboard.ts"],"sourcesContent":["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
|
|
1
|
+
{"version":3,"file":"keyboard.cjs","names":[],"sources":["../../src/core/keyboard.ts"],"sourcesContent":["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"],"mappings":"AAUA,IAAa,wBAA0B,EAAsB,IAA8C,CACzG,GAAI,EAAQ,UAAU,MAAO,MAAO,GAMpC,IAAM,EAAS,OAAO,OAAO,EAAQ,OAAQ,EAAM,GAAG,EAAI,EAAQ,OAAO,EAAM,KAAO,IAAA,GAEtF,GAAI,CAAC,EAAQ,MAAO,GAEpB,IAAM,EAAqB,EAAQ,gBAAkB,SAEjD,IAAuB,UAAU,EAAM,eAAe,EAE1D,IAAM,EAAU,EAAO,CAAK,IAAM,GAIlC,OAFI,IAAuB,SAAW,GAAS,EAAM,eAAe,EAE7D,CACT,EAkDa,kBAAqB,GAA6C,CAC7E,IAAM,eAA4B,EAAQ,EAAQ,UAAU,MACtD,EAAe,EAAQ,MAAQ,CAAC,QAAS,GAAG,EAC5C,EAAS,OAAO,YACpB,EAAa,IAAK,GAAQ,CAAC,EAAM,GAAiC,EAAQ,UAAU,EAAe,UAAU,CAAC,CAAC,CACjH,EAEA,MAAO,CACL,WAAa,GAA4B,CAClC,WAAW,GAAG,EAAQ,SAAS,CAAK,CAC3C,EACA,YAAc,GACZ,CAAI,WAAW,IAEf,EAAQ,UAAU,EAAO,SAAS,EAE3B,IAET,YAAc,GAA4B,CACnC,WAAW,GAAG,EAAQ,UAAU,CAAK,CAC5C,EACA,cAAgB,GACd,uBAAuB,EAAO,CAAE,SAAU,EAAQ,SAAU,QAAO,CAAC,CACxE,CACF"}
|
package/dist/core/keyboard.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export type KeyboardDispatchOptions = {
|
|
|
7
7
|
export declare const dispatchKeyboardAction: (event: KeyboardEvent, options: KeyboardDispatchOptions) => boolean;
|
|
8
8
|
export type PressTrigger = 'keyboard' | 'pointer';
|
|
9
9
|
/**
|
|
10
|
-
* Options for `createInteraction
|
|
10
|
+
* Options for `createInteraction`: a unified press + focus/blur interaction
|
|
11
11
|
* handler for accessible interactive elements.
|
|
12
12
|
*/
|
|
13
13
|
export type InteractionOptions = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyboard.js","names":[],"sources":["../../src/core/keyboard.ts"],"sourcesContent":["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
|
|
1
|
+
{"version":3,"file":"keyboard.js","names":[],"sources":["../../src/core/keyboard.ts"],"sourcesContent":["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"],"mappings":"AAUA,IAAa,wBAA0B,EAAsB,IAA8C,CACzG,GAAI,EAAQ,UAAU,MAAO,MAAO,GAMpC,IAAM,EAAS,OAAO,OAAO,EAAQ,OAAQ,EAAM,GAAG,EAAI,EAAQ,OAAO,EAAM,KAAO,IAAA,GAEtF,GAAI,CAAC,EAAQ,MAAO,GAEpB,IAAM,EAAqB,EAAQ,gBAAkB,SAEjD,IAAuB,UAAU,EAAM,eAAe,EAE1D,IAAM,EAAU,EAAO,CAAK,IAAM,GAIlC,OAFI,IAAuB,SAAW,GAAS,EAAM,eAAe,EAE7D,CACT,EAkDa,kBAAqB,GAA6C,CAC7E,IAAM,eAA4B,EAAQ,EAAQ,UAAU,MACtD,EAAe,EAAQ,MAAQ,CAAC,QAAS,GAAG,EAC5C,EAAS,OAAO,YACpB,EAAa,IAAK,GAAQ,CAAC,EAAM,GAAiC,EAAQ,UAAU,EAAe,UAAU,CAAC,CAAC,CACjH,EAEA,MAAO,CACL,WAAa,GAA4B,CAClC,WAAW,GAAG,EAAQ,SAAS,CAAK,CAC3C,EACA,YAAc,GACZ,CAAI,WAAW,IAEf,EAAQ,UAAU,EAAO,SAAS,EAE3B,IAET,YAAc,GAA4B,CACnC,WAAW,GAAG,EAAQ,UAAU,CAAK,CAC5C,EACA,cAAgB,GACd,uBAAuB,EAAO,CAAE,SAAU,EAAQ,SAAU,QAAO,CAAC,CACxE,CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"numbers.cjs","names":[],"sources":["../../src/core/numbers.ts"],"sourcesContent":["// ── 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
|
|
1
|
+
{"version":3,"file":"numbers.cjs","names":[],"sources":["../../src/core/numbers.ts"],"sourcesContent":["// ── 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"],"mappings":"AAYA,IAAa,eAAkB,GAAuC,CACpE,IAAM,EAAS,OAAO,CAAK,EAE3B,OAAO,OAAO,SAAS,CAAM,EAAI,EAAS,IAAA,EAC5C,EAEa,kBAAoB,EAAgB,IACxC,eAAe,CAAK,GAAK,EAGrB,gBAAkB,EAAgB,IACtC,KAAK,IAAI,iBAAiB,EAAO,CAAQ,CAAC,GAAK"}
|
package/dist/core/numbers.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Caveat: `null` and `''` both coerce to `0` in JavaScript (`Number(null) === 0`,
|
|
5
5
|
* `Number('') === 0`) and are therefore returned as the finite number `0`, not
|
|
6
|
-
* `undefined
|
|
6
|
+
* `undefined`: this function does not treat "absent" values specially. Only
|
|
7
7
|
* genuinely non-numeric input (`undefined`, `NaN`, non-numeric strings) yields
|
|
8
8
|
* `undefined`. Callers that mean "no bound set" should pass `undefined`
|
|
9
9
|
* explicitly rather than `null` or `''`.
|
package/dist/core/numbers.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"numbers.js","names":[],"sources":["../../src/core/numbers.ts"],"sourcesContent":["// ── 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
|
|
1
|
+
{"version":3,"file":"numbers.js","names":[],"sources":["../../src/core/numbers.ts"],"sourcesContent":["// ── 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"],"mappings":"AAYA,IAAa,eAAkB,GAAuC,CACpE,IAAM,EAAS,OAAO,CAAK,EAE3B,OAAO,OAAO,SAAS,CAAM,EAAI,EAAS,IAAA,EAC5C,EAEa,kBAAoB,EAAgB,IACxC,eAAe,CAAK,GAAK,EAGrB,gBAAkB,EAAgB,IACtC,KAAK,IAAI,iBAAiB,EAAO,CAAQ,CAAC,GAAK"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"overlay.cjs","names":[],"sources":["../../src/core/overlay.ts"],"sourcesContent":["/**\n * Why an overlay was opened.\n * - `'click'
|
|
1
|
+
{"version":3,"file":"overlay.cjs","names":[],"sources":["../../src/core/overlay.ts"],"sourcesContent":["/**\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'> | 'select';\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/** Detail shape for state changes emitted by overlay components. */\nexport type OverlayOpenChangeDetail = {\n open: boolean;\n reason: DialogCloseReason | DropdownCloseReason | OverlayOpenReason;\n};\n\nexport type OutsidePointerDismissalOptions = {\n getTargets: () => Array<Element | null | undefined>;\n isActive: () => boolean;\n onDismiss: () => void;\n signal: AbortSignal;\n};\n\n/**\n * Dismisses an active floating surface when a pointer begins outside all of its\n * supplied boundary elements. Components retain ownership of their open state.\n */\nexport const createOutsidePointerDismissal = (options: OutsidePointerDismissalOptions): (() => void) => {\n const onPointerDown = (event: PointerEvent): void => {\n if (!options.isActive()) return;\n\n const path = event.composedPath();\n const target = path[0] instanceof Node ? path[0] : event.target instanceof Node ? event.target : null;\n const inside = options.getTargets().some((element) => {\n return (\n element !== null &&\n element !== undefined &&\n (path.includes(element) || Boolean(target && element.contains(target)))\n );\n });\n\n if (!inside) options.onDismiss();\n };\n\n const dispose = (): void => {\n document.removeEventListener('pointerdown', onPointerDown, { capture: true });\n };\n\n document.addEventListener('pointerdown', onPointerDown, { capture: true });\n options.signal.addEventListener('abort', dispose, { once: true });\n\n return dispose;\n};\n"],"mappings":"AAqCA,IAAa,8BAAiC,GAA0D,CACtG,IAAM,cAAiB,GAA8B,CACnD,GAAI,CAAC,EAAQ,SAAS,EAAG,OAEzB,IAAM,EAAO,EAAM,aAAa,EAC1B,EAAS,EAAK,aAAc,KAAO,EAAK,GAAK,EAAM,kBAAkB,KAAO,EAAM,OAAS,KAClF,EAAQ,WAAW,CAAC,CAAC,KAAM,GAEtC,GAAY,OAEX,EAAK,SAAS,CAAO,GAAK,GAAQ,GAAU,EAAQ,SAAS,CAAM,GAInE,GAAQ,EAAQ,UAAU,CACjC,EAEM,YAAsB,CAC1B,SAAS,oBAAoB,cAAe,cAAe,CAAE,QAAS,EAAK,CAAC,CAC9E,EAKA,OAHA,SAAS,iBAAiB,cAAe,cAAe,CAAE,QAAS,EAAK,CAAC,EACzE,EAAQ,OAAO,iBAAiB,QAAS,QAAS,CAAE,KAAM,EAAK,CAAC,EAEzD,OACT"}
|
package/dist/core/overlay.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Why an overlay was opened.
|
|
3
|
-
* - `'click'
|
|
4
|
-
* - `'focus'
|
|
5
|
-
* - `'hover'
|
|
6
|
-
* - `'keyboard'
|
|
7
|
-
* - `'programmatic'
|
|
8
|
-
* - `'trigger'
|
|
3
|
+
* - `'click'`: user clicked the trigger element
|
|
4
|
+
* - `'focus'`: focus entered the trigger (tooltip, popover)
|
|
5
|
+
* - `'hover'`: pointer entered the trigger (tooltip)
|
|
6
|
+
* - `'keyboard'`: keyboard shortcut or Enter/Space on a trigger
|
|
7
|
+
* - `'programmatic'`: opened via the JS API without a user gesture
|
|
8
|
+
* - `'trigger'`: opened via the Invoker Commands API (`command="show-modal"`)
|
|
9
9
|
*/
|
|
10
10
|
export type OverlayOpenReason = 'click' | 'focus' | 'hover' | 'keyboard' | 'programmatic' | 'trigger';
|
|
11
11
|
/** Close reasons valid for modal dialogs (includes 'swipe' for drawer). */
|
package/dist/core/overlay.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"overlay.js","names":[],"sources":["../../src/core/overlay.ts"],"sourcesContent":["/**\n * Why an overlay was opened.\n * - `'click'
|
|
1
|
+
{"version":3,"file":"overlay.js","names":[],"sources":["../../src/core/overlay.ts"],"sourcesContent":["/**\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'> | 'select';\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/** Detail shape for state changes emitted by overlay components. */\nexport type OverlayOpenChangeDetail = {\n open: boolean;\n reason: DialogCloseReason | DropdownCloseReason | OverlayOpenReason;\n};\n\nexport type OutsidePointerDismissalOptions = {\n getTargets: () => Array<Element | null | undefined>;\n isActive: () => boolean;\n onDismiss: () => void;\n signal: AbortSignal;\n};\n\n/**\n * Dismisses an active floating surface when a pointer begins outside all of its\n * supplied boundary elements. Components retain ownership of their open state.\n */\nexport const createOutsidePointerDismissal = (options: OutsidePointerDismissalOptions): (() => void) => {\n const onPointerDown = (event: PointerEvent): void => {\n if (!options.isActive()) return;\n\n const path = event.composedPath();\n const target = path[0] instanceof Node ? path[0] : event.target instanceof Node ? event.target : null;\n const inside = options.getTargets().some((element) => {\n return (\n element !== null &&\n element !== undefined &&\n (path.includes(element) || Boolean(target && element.contains(target)))\n );\n });\n\n if (!inside) options.onDismiss();\n };\n\n const dispose = (): void => {\n document.removeEventListener('pointerdown', onPointerDown, { capture: true });\n };\n\n document.addEventListener('pointerdown', onPointerDown, { capture: true });\n options.signal.addEventListener('abort', dispose, { once: true });\n\n return dispose;\n};\n"],"mappings":"AAqCA,IAAa,8BAAiC,GAA0D,CACtG,IAAM,cAAiB,GAA8B,CACnD,GAAI,CAAC,EAAQ,SAAS,EAAG,OAEzB,IAAM,EAAO,EAAM,aAAa,EAC1B,EAAS,EAAK,aAAc,KAAO,EAAK,GAAK,EAAM,kBAAkB,KAAO,EAAM,OAAS,KAClF,EAAQ,WAAW,CAAC,CAAC,KAAM,GAEtC,GAAY,OAEX,EAAK,SAAS,CAAO,GAAK,GAAQ,GAAU,EAAQ,SAAS,CAAM,GAInE,GAAQ,EAAQ,UAAU,CACjC,EAEM,YAAsB,CAC1B,SAAS,oBAAoB,cAAe,cAAe,CAAE,QAAS,EAAK,CAAC,CAC9E,EAKA,OAHA,SAAS,iBAAiB,cAAe,cAAe,CAAE,QAAS,EAAK,CAAC,EACzE,EAAQ,OAAO,iBAAiB,QAAS,QAAS,CAAE,KAAM,EAAK,CAAC,EAEzD,OACT"}
|
package/dist/core/parse.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse.cjs","names":[],"sources":["../../src/core/parse.ts"],"sourcesContent":["// ── 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\n// ── Boolean attribute parser ──────────────────────────────────────────────────\n\n/**\n * Parses a boolean HTML attribute value into `true | false | undefined`, where\n * `undefined` means \"attribute absent\"
|
|
1
|
+
{"version":3,"file":"parse.cjs","names":[],"sources":["../../src/core/parse.ts"],"sourcesContent":["// ── 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\n// ── Boolean attribute parser ──────────────────────────────────────────────────\n\n/**\n * Parses a boolean HTML attribute value into `true | false | undefined`, where\n * `undefined` means \"attribute absent\": the signal controlled components (`open`)\n * use to distinguish uncontrolled from controlled mode.\n *\n * The grammar is the standard attribute one: presence with no value (`open`) or\n * the literal `\"true\"` is true; anything else, including `\"false\"`, is false.\n * Every controlled overlay (dialog, drawer, menu, popover, tooltip,\n * command-palette) parses its `open` prop with this exact contract.\n */\nexport const parseOptionalBool = (value: string | null): boolean | undefined =>\n value == null ? undefined : value === '' || value === 'true';\n"],"mappings":"AAeA,IAAa,qBACX,EACA,EACA,IACQ,CACR,IAAM,EAAS,OAAO,GAAS,EAAE,CAAC,CAC/B,MAAM,GAAG,CAAC,CACV,IAAK,GAAM,EAAE,KAAK,CAAC,CAAC,CACpB,OAAQ,GAAc,EAAM,IAAI,CAAM,CAAC,EAE1C,OAAO,EAAO,OAAS,EAAI,EAAS,CAAC,GAAG,CAAQ,CAClD,EAca,kBAAqB,GAChC,GAAS,KAAO,IAAA,GAAY,IAAU,IAAM,IAAU"}
|
package/dist/core/parse.d.ts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
export declare const parseStringTriggers: <T extends string>(value: string | null | undefined, valid: ReadonlySet<T>, defaults: T[]) => T[];
|
|
15
15
|
/**
|
|
16
16
|
* Parses a boolean HTML attribute value into `true | false | undefined`, where
|
|
17
|
-
* `undefined` means "attribute absent"
|
|
17
|
+
* `undefined` means "attribute absent": the signal controlled components (`open`)
|
|
18
18
|
* use to distinguish uncontrolled from controlled mode.
|
|
19
19
|
*
|
|
20
20
|
* The grammar is the standard attribute one: presence with no value (`open`) or
|
package/dist/core/parse.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse.js","names":[],"sources":["../../src/core/parse.ts"],"sourcesContent":["// ── 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\n// ── Boolean attribute parser ──────────────────────────────────────────────────\n\n/**\n * Parses a boolean HTML attribute value into `true | false | undefined`, where\n * `undefined` means \"attribute absent\"
|
|
1
|
+
{"version":3,"file":"parse.js","names":[],"sources":["../../src/core/parse.ts"],"sourcesContent":["// ── 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\n// ── Boolean attribute parser ──────────────────────────────────────────────────\n\n/**\n * Parses a boolean HTML attribute value into `true | false | undefined`, where\n * `undefined` means \"attribute absent\": the signal controlled components (`open`)\n * use to distinguish uncontrolled from controlled mode.\n *\n * The grammar is the standard attribute one: presence with no value (`open`) or\n * the literal `\"true\"` is true; anything else, including `\"false\"`, is false.\n * Every controlled overlay (dialog, drawer, menu, popover, tooltip,\n * command-palette) parses its `open` prop with this exact contract.\n */\nexport const parseOptionalBool = (value: string | null): boolean | undefined =>\n value == null ? undefined : value === '' || value === 'true';\n"],"mappings":"AAeA,IAAa,qBACX,EACA,EACA,IACQ,CACR,IAAM,EAAS,OAAO,GAAS,EAAE,CAAC,CAC/B,MAAM,GAAG,CAAC,CACV,IAAK,GAAM,EAAE,KAAK,CAAC,CAAC,CACpB,OAAQ,GAAc,EAAM,IAAI,CAAM,CAAC,EAE1C,OAAO,EAAO,OAAS,EAAI,EAAS,CAAC,GAAG,CAAQ,CAClD,EAca,kBAAqB,GAChC,GAAS,KAAO,IAAA,GAAY,IAAU,IAAM,IAAU"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"positioner.cjs","names":[],"sources":["../../src/core/positioner.ts"],"sourcesContent":["import {\n autoUpdate,\n computePosition,\n flip,\n getBoundaryRect,\n getClippingAncestorRect,\n offset,\n type Placement,\n type Rect,\n type SizeData,\n shift,\n size,\n} 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 * Clipping boundary for flip/shift/size — the edges the dropdown must stay within.\n * Defaults to the nearest ancestor that actually clips content (`overflow:\n * hidden|auto|scroll|clip`, e.g. a dialog panel), auto-detected per update via\n * `getClippingAncestorRect()`, intersected with the viewport. Without this, flip/shift only\n * avoid the full page viewport — a dropdown can be \"in view\" by that measure while still\n * visibly overhanging a much smaller container it's actually nested in. Pass an explicit\n * boundary to override auto-detection.\n */\n boundary?: Element | Rect;\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 /**\n * Whether to size the floating element from the reference: at least as wide as the reference,\n * growing to fit its own content, capped by the boundary. Default: true\n */\n matchWidth?: boolean;\n /**\n * Returns the offset in pixels between reference and floating element, read on every update so a\n * reactive offset prop is honored. Default: 0.\n */\n getOffsetPx?: () => number;\n /**\n * Called after each update with the resolved placement (after RTL mirroring and flip). The\n * positioner also writes it to the floating element's `data-placement` attribute itself, so this\n * is only needed to react to placement changes (e.g. tooltip's per-side closed transform).\n */\n onPlacementChange?: (placement: Placement) => void;\n /** Padding (px) used by flip, shift, and size middleware. Default: 6 */\n padding?: number;\n /**\n * Whether to constrain placement to a clipping ancestor when `boundary` is unset. Default:\n * true. Disable for native Popover API panels, which render in the top layer.\n */\n useClippingAncestor?: boolean;\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 boundary,\n getDir,\n getFloating,\n getOffsetPx = () => 0,\n getPlacement,\n getReference,\n matchWidth = true,\n onPlacementChange,\n padding = 6,\n useClippingAncestor = true,\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 // Defaults to `undefined` (meaning \"auto-detect\"), not the detected value itself —\n // re-running the detection on every update (rather than once, at positioner-creation time)\n // matters because the dialog/scroll-container an instance is rendered into can change\n // across opens (e.g. the same `<ore-select>` reused in different dialogs), and the detected\n // ancestor's own rect can change between opens even when it's the same element (a resized\n // dialog).\n const resolvedBoundary = getBoundaryRect(\n boundary ?? (useClippingAncestor ? getClippingAncestorRect(floating) : undefined),\n );\n\n const refWidth = ref.getBoundingClientRect().width;\n let naturalWidth = 0;\n\n if (matchWidth) {\n // Measure the panel at its natural content width, floored at the reference width, so\n // `computePosition()` places (and `shift` keeps inside the boundary) the box that will\n // actually render. `left: 0` frees the measurement from the shrink-to-fit clamp a previous\n // `left` would impose on a `position: fixed` element near the right edge.\n floating.style.left = '0px';\n floating.style.width = 'auto';\n floating.style.minWidth = `${refWidth}px`;\n naturalWidth = floating.getBoundingClientRect().width;\n // Clamp to the width the `size` middleware will report *before* positioning, so `flip`\n // and `shift` compensate for the box that actually renders. Without this, a panel whose\n // natural width exceeds the boundary is shifted fully inside for a width it is then\n // clamped out of — landing further inside the boundary than needed, misaligned with its\n // trigger. Horizontal placements derive their available width from the post-shift x and\n // cannot be pre-clamped; they keep the post-positioning clamp below.\n if (placement.startsWith('top') || placement.startsWith('bottom')) {\n const availableWidth = Math.max(0, resolvedBoundary.width - padding * 2);\n floating.style.width = `${Math.min(Math.max(naturalWidth, refWidth), availableWidth)}px`;\n }\n }\n\n const result = computePosition(ref, floating, {\n boundary: resolvedBoundary,\n middleware: [\n ...(() => {\n const offsetPx = getOffsetPx();\n\n return offsetPx ? [offset(offsetPx)] : [];\n })(),\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 // `computePosition()` assumes `left`/`top` resolve relative to the viewport (correct for\n // `position: fixed`) — true almost always, but not when some ancestor establishes a\n // containing block for fixed descendants (a non-`none` `transform`, even a visually-identity\n // one left over from an entrance transition that never resets to `none` at rest is a real,\n // easy-to-hit case — a modal dialog's panel, say). Analytically detecting *that* ancestor via\n // `getContainingBlock()` and pre-subtracting its rect turned out to be unreliable in\n // practice: browsers don't apply the \"ancestor transform traps fixed descendants\" rule\n // uniformly across every element nested under it in every case we tested — some floating\n // elements in the exact same subtree needed the correction and some didn't, for reasons we\n // couldn't fully pin down. Measuring what actually happened after writing `left`/`top`\n // and correcting only the observed gap sidesteps that: it's a no-op when the browser already\n // put the element where asked, and it fixes the same class of bug the moment there's a real\n // mismatch, regardless of which specific ancestor (if any) turns out to be responsible.\n //\n // The measurement itself must not be fooled by the floating element's *own* transform,\n // though: dropdowns/popovers here all use a `transform: translateY(...)` entrance transition\n // driven by a `[data-open]` attribute + `@starting-style` — right at open, before the\n // transition has visibly progressed, `getBoundingClientRect()` can still reflect that\n // starting offset (a handful of px, matching `--overlay-enter-translate-y`), which this\n // correction would otherwise misread as a permanent ancestor-driven mismatch and bake in\n // forever. Temporarily neutralizing the floating element's own transform for the measurement\n // (and restoring it before anything paints, so there's no visible flash) isolates the\n // correction to ancestor-driven offsets only, which is the only thing it's meant to fix.\n const prevTransition = floating.style.transition;\n const prevTransform = floating.style.transform;\n\n floating.style.transition = 'none';\n floating.style.transform = 'none';\n\n const actual = floating.getBoundingClientRect();\n const deltaX = result.x - actual.left;\n const deltaY = result.y - actual.top;\n\n floating.style.transition = prevTransition;\n floating.style.transform = prevTransform;\n\n if (deltaX !== 0 || deltaY !== 0) {\n floating.style.left = `${result.x + deltaX}px`;\n floating.style.top = `${result.y + deltaY}px`;\n }\n\n if (matchWidth) {\n const available =\n (result.middlewareData.size as SizeData | undefined)?.availableWidth ?? Number.POSITIVE_INFINITY;\n // A panel measured while not yet rendered reports 0 — fall back to the reference width.\n floating.style.width = `${Math.min(Math.max(naturalWidth, refWidth), available)}px`;\n }\n\n // Reported last, after every `left`/`top`/`width` write has settled, so a consumer reacting to\n // the placement (e.g. tooltip's per-side closed transform) sees the final geometry.\n onPlacementChange?.(result.placement);\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"],"mappings":"oEA6EA,IAAM,aAAgB,GAChB,EAAE,SAAS,QAAQ,EAAU,EAAE,QAAQ,SAAU,MAAM,EAEvD,EAAE,SAAS,MAAM,EAAU,EAAE,QAAQ,OAAQ,QAAQ,EAElD,EAaT,SAAgB,yBAAyB,CACvC,WACA,SACA,cACA,kBAAoB,EACpB,eACA,eACA,aAAa,GACb,oBACA,UAAU,EACV,sBAAsB,IACyB,CAC/C,SAAS,mBAA+B,CACtC,IAAM,EAAO,IAAe,GAAK,eAGjC,OAFY,IAAS,GAAK,EAAA,iBAAiB,EAAa,CAAC,KAE1C,MAAQ,aAAa,CAAI,EAAI,CAC9C,CAEA,SAAS,gBAAuB,CAC9B,IAAM,EAAM,EAAa,EACnB,EAAW,EAAY,EAE7B,GAAI,CAAC,GAAO,CAAC,EAAU,OAEvB,IAAM,EAAY,kBAAkB,EAO9B,GAAA,EAAmB,EAAA,gBAAA,CACvB,IAAa,GAAA,EAAsB,EAAA,wBAAA,CAAwB,CAAQ,EAAI,IAAA,GACzE,EAEM,EAAW,EAAI,sBAAsB,CAAC,CAAC,MACzC,EAAe,EAEnB,GAAI,IAKF,EAAS,MAAM,KAAO,MACtB,EAAS,MAAM,MAAQ,OACvB,EAAS,MAAM,SAAW,GAAG,EAAS,IACtC,EAAe,EAAS,sBAAsB,CAAC,CAAC,MAO5C,EAAU,WAAW,KAAK,GAAK,EAAU,WAAW,QAAQ,GAAG,CACjE,IAAM,EAAiB,KAAK,IAAI,EAAG,EAAiB,MAAQ,EAAU,CAAC,EACvE,EAAS,MAAM,MAAQ,GAAG,KAAK,IAAI,KAAK,IAAI,EAAc,CAAQ,EAAG,CAAc,EAAE,GACvF,CAGF,IAAM,GAAA,EAAS,EAAA,gBAAA,CAAgB,EAAK,EAAU,CAC5C,SAAU,EACV,WAAY,CACV,QAAU,CACR,IAAM,EAAW,EAAY,EAE7B,OAAO,EAAW,EAAA,EAAC,EAAA,OAAA,CAAO,CAAQ,CAAC,EAAI,CAAC,CAC1C,EAAA,CAAG,GACH,EAAA,EAAA,KAAA,CAAK,CAAE,SAAQ,CAAC,GAChB,EAAA,EAAA,MAAA,CAAM,CAAE,SAAQ,CAAC,EACjB,GAAI,EAAa,EAAA,EAAC,EAAA,KAAA,CAAK,CAAE,SAAQ,CAAC,CAAC,EAAI,CAAC,CAC1C,EACA,WACF,CAAC,EAED,EAAS,MAAM,KAAO,GAAG,EAAO,EAAE,IAClC,EAAS,MAAM,IAAM,GAAG,EAAO,EAAE,IAyBjC,IAAM,EAAiB,EAAS,MAAM,WAChC,EAAgB,EAAS,MAAM,UAErC,EAAS,MAAM,WAAa,OAC5B,EAAS,MAAM,UAAY,OAE3B,IAAM,EAAS,EAAS,sBAAsB,EACxC,EAAS,EAAO,EAAI,EAAO,KAC3B,EAAS,EAAO,EAAI,EAAO,IAUjC,GARA,EAAS,MAAM,WAAa,EAC5B,EAAS,MAAM,UAAY,GAEvB,IAAW,GAAK,IAAW,KAC7B,EAAS,MAAM,KAAO,GAAG,EAAO,EAAI,EAAO,IAC3C,EAAS,MAAM,IAAM,GAAG,EAAO,EAAI,EAAO,KAGxC,EAAY,CACd,IAAM,EACH,EAAO,eAAe,MAA+B,gBAAkB,IAE1E,EAAS,MAAM,MAAQ,GAAG,KAAK,IAAI,KAAK,IAAI,EAAc,CAAQ,EAAG,CAAS,EAAE,GAClF,CAIA,IAAoB,EAAO,SAAS,CACtC,CAEA,SAAS,iBAA8B,CACrC,IAAM,EAAM,EAAa,EACnB,EAAW,EAAY,EAI7B,MAFI,CAAC,GAAO,CAAC,MAAuB,CAAC,GAErC,EAAO,EAAA,WAAA,CAAW,EAAK,EAAU,cAAc,CACjD,CAEA,MAAO,CAAE,SAAU,EAAa,UAAW,EAAc,gBAAiB,OAAQ,cAAe,CACnG"}
|
|
1
|
+
{"version":3,"file":"positioner.cjs","names":[],"sources":["../../src/core/positioner.ts"],"sourcesContent":["import {\n autoUpdate,\n computePosition,\n flip,\n getBoundaryRect,\n getClippingAncestorRect,\n offset,\n type Placement,\n type Rect,\n type SizeData,\n shift,\n size,\n} 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 * Clipping boundary for flip/shift/size: the edges the dropdown must stay within.\n * Defaults to the nearest ancestor that actually clips content (`overflow:\n * hidden|auto|scroll|clip`, e.g. a dialog panel), auto-detected per update via\n * `getClippingAncestorRect()`, intersected with the viewport. Without this, flip/shift only\n * avoid the full page viewport: a dropdown can be \"in view\" by that measure while still\n * visibly overhanging a much smaller container it's actually nested in. Pass an explicit\n * boundary to override auto-detection.\n */\n boundary?: Element | Rect;\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 /**\n * Whether to size the floating element from the reference: at least as wide as the reference,\n * growing to fit its own content, capped by the boundary. Default: true\n */\n matchWidth?: boolean;\n /**\n * Returns the offset in pixels between reference and floating element, read on every update so a\n * reactive offset prop is honored. Default: 0.\n */\n getOffsetPx?: () => number;\n /**\n * Called after each update with the resolved placement (after RTL mirroring and flip). The\n * positioner also writes it to the floating element's `data-placement` attribute itself, so this\n * is only needed to react to placement changes (e.g. tooltip's per-side closed transform).\n */\n onPlacementChange?: (placement: Placement) => void;\n /** Padding (px) used by flip, shift, and size middleware. Default: 6 */\n padding?: number;\n /**\n * Whether to constrain placement to a clipping ancestor when `boundary` is unset. Default:\n * true. Disable for native Popover API panels, which render in the top layer.\n */\n useClippingAncestor?: boolean;\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 boundary,\n getDir,\n getFloating,\n getOffsetPx = () => 0,\n getPlacement,\n getReference,\n matchWidth = true,\n onPlacementChange,\n padding = 6,\n useClippingAncestor = true,\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 // Defaults to `undefined` (meaning \"auto-detect\"), not the detected value itself :\n // re-running the detection on every update (rather than once, at positioner-creation time)\n // matters because the dialog/scroll-container an instance is rendered into can change\n // across opens (e.g. the same `<ore-select>` reused in different dialogs), and the detected\n // ancestor's own rect can change between opens even when it's the same element (a resized\n // dialog).\n const resolvedBoundary = getBoundaryRect(\n boundary ?? (useClippingAncestor ? getClippingAncestorRect(floating) : undefined),\n );\n\n const refWidth = ref.getBoundingClientRect().width;\n let naturalWidth = 0;\n\n if (matchWidth) {\n // Measure the panel at its natural content width, floored at the reference width, so\n // `computePosition()` places (and `shift` keeps inside the boundary) the box that will\n // actually render. `left: 0` frees the measurement from the shrink-to-fit clamp a previous\n // `left` would impose on a `position: fixed` element near the right edge.\n floating.style.left = '0px';\n floating.style.width = 'auto';\n floating.style.minWidth = `${refWidth}px`;\n naturalWidth = floating.getBoundingClientRect().width;\n // Clamp to the width the `size` middleware will report *before* positioning, so `flip`\n // and `shift` compensate for the box that actually renders. Without this, a panel whose\n // natural width exceeds the boundary is shifted fully inside for a width it is then\n // clamped out of: landing further inside the boundary than needed, misaligned with its\n // trigger. Horizontal placements derive their available width from the post-shift x and\n // cannot be pre-clamped; they keep the post-positioning clamp below.\n if (placement.startsWith('top') || placement.startsWith('bottom')) {\n const availableWidth = Math.max(0, resolvedBoundary.width - padding * 2);\n floating.style.width = `${Math.min(Math.max(naturalWidth, refWidth), availableWidth)}px`;\n }\n }\n\n const result = computePosition(ref, floating, {\n boundary: resolvedBoundary,\n middleware: [\n ...(() => {\n const offsetPx = getOffsetPx();\n\n return offsetPx ? [offset(offsetPx)] : [];\n })(),\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 // `computePosition()` assumes `left`/`top` resolve relative to the viewport (correct for\n // `position: fixed`): true almost always, but not when some ancestor establishes a\n // containing block for fixed descendants (a non-`none` `transform`, even a visually-identity\n // one left over from an entrance transition that never resets to `none` at rest is a real,\n // easy-to-hit case: a modal dialog's panel, say). Analytically detecting *that* ancestor via\n // `getContainingBlock()` and pre-subtracting its rect turned out to be unreliable in\n // practice: browsers don't apply the \"ancestor transform traps fixed descendants\" rule\n // uniformly across every element nested under it in every case we tested: some floating\n // elements in the exact same subtree needed the correction and some didn't, for reasons we\n // couldn't fully pin down. Measuring what actually happened after writing `left`/`top`\n // and correcting only the observed gap sidesteps that: it's a no-op when the browser already\n // put the element where asked, and it fixes the same class of bug the moment there's a real\n // mismatch, regardless of which specific ancestor (if any) turns out to be responsible.\n //\n // The measurement itself must not be fooled by the floating element's *own* transform,\n // though: dropdowns/popovers here all use a `transform: translateY(...)` entrance transition\n // driven by a `[data-open]` attribute + `@starting-style`: right at open, before the\n // transition has visibly progressed, `getBoundingClientRect()` can still reflect that\n // starting offset (a handful of px, matching `--overlay-enter-translate-y`), which this\n // correction would otherwise misread as a permanent ancestor-driven mismatch and bake in\n // forever. Temporarily neutralizing the floating element's own transform for the measurement\n // (and restoring it before anything paints, so there's no visible flash) isolates the\n // correction to ancestor-driven offsets only, which is the only thing it's meant to fix.\n const prevTransition = floating.style.transition;\n const prevTransform = floating.style.transform;\n\n floating.style.transition = 'none';\n floating.style.transform = 'none';\n\n const actual = floating.getBoundingClientRect();\n const deltaX = result.x - actual.left;\n const deltaY = result.y - actual.top;\n\n floating.style.transition = prevTransition;\n floating.style.transform = prevTransform;\n\n if (deltaX !== 0 || deltaY !== 0) {\n floating.style.left = `${result.x + deltaX}px`;\n floating.style.top = `${result.y + deltaY}px`;\n }\n\n if (matchWidth) {\n const available =\n (result.middlewareData.size as SizeData | undefined)?.availableWidth ?? Number.POSITIVE_INFINITY;\n // A panel measured while not yet rendered reports 0: fall back to the reference width.\n floating.style.width = `${Math.min(Math.max(naturalWidth, refWidth), available)}px`;\n }\n\n // Reported last, after every `left`/`top`/`width` write has settled, so a consumer reacting to\n // the placement (e.g. tooltip's per-side closed transform) sees the final geometry.\n onPlacementChange?.(result.placement);\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"],"mappings":"oEA6EA,IAAM,aAAgB,GAChB,EAAE,SAAS,QAAQ,EAAU,EAAE,QAAQ,SAAU,MAAM,EAEvD,EAAE,SAAS,MAAM,EAAU,EAAE,QAAQ,OAAQ,QAAQ,EAElD,EAaT,SAAgB,yBAAyB,CACvC,WACA,SACA,cACA,kBAAoB,EACpB,eACA,eACA,aAAa,GACb,oBACA,UAAU,EACV,sBAAsB,IACyB,CAC/C,SAAS,mBAA+B,CACtC,IAAM,EAAO,IAAe,GAAK,eAGjC,OAFY,IAAS,GAAK,EAAA,iBAAiB,EAAa,CAAC,KAE1C,MAAQ,aAAa,CAAI,EAAI,CAC9C,CAEA,SAAS,gBAAuB,CAC9B,IAAM,EAAM,EAAa,EACnB,EAAW,EAAY,EAE7B,GAAI,CAAC,GAAO,CAAC,EAAU,OAEvB,IAAM,EAAY,kBAAkB,EAO9B,GAAA,EAAmB,EAAA,gBAAA,CACvB,IAAa,GAAA,EAAsB,EAAA,wBAAA,CAAwB,CAAQ,EAAI,IAAA,GACzE,EAEM,EAAW,EAAI,sBAAsB,CAAC,CAAC,MACzC,EAAe,EAEnB,GAAI,IAKF,EAAS,MAAM,KAAO,MACtB,EAAS,MAAM,MAAQ,OACvB,EAAS,MAAM,SAAW,GAAG,EAAS,IACtC,EAAe,EAAS,sBAAsB,CAAC,CAAC,MAO5C,EAAU,WAAW,KAAK,GAAK,EAAU,WAAW,QAAQ,GAAG,CACjE,IAAM,EAAiB,KAAK,IAAI,EAAG,EAAiB,MAAQ,EAAU,CAAC,EACvE,EAAS,MAAM,MAAQ,GAAG,KAAK,IAAI,KAAK,IAAI,EAAc,CAAQ,EAAG,CAAc,EAAE,GACvF,CAGF,IAAM,GAAA,EAAS,EAAA,gBAAA,CAAgB,EAAK,EAAU,CAC5C,SAAU,EACV,WAAY,CACV,QAAU,CACR,IAAM,EAAW,EAAY,EAE7B,OAAO,EAAW,EAAA,EAAC,EAAA,OAAA,CAAO,CAAQ,CAAC,EAAI,CAAC,CAC1C,EAAA,CAAG,GACH,EAAA,EAAA,KAAA,CAAK,CAAE,SAAQ,CAAC,GAChB,EAAA,EAAA,MAAA,CAAM,CAAE,SAAQ,CAAC,EACjB,GAAI,EAAa,EAAA,EAAC,EAAA,KAAA,CAAK,CAAE,SAAQ,CAAC,CAAC,EAAI,CAAC,CAC1C,EACA,WACF,CAAC,EAED,EAAS,MAAM,KAAO,GAAG,EAAO,EAAE,IAClC,EAAS,MAAM,IAAM,GAAG,EAAO,EAAE,IAyBjC,IAAM,EAAiB,EAAS,MAAM,WAChC,EAAgB,EAAS,MAAM,UAErC,EAAS,MAAM,WAAa,OAC5B,EAAS,MAAM,UAAY,OAE3B,IAAM,EAAS,EAAS,sBAAsB,EACxC,EAAS,EAAO,EAAI,EAAO,KAC3B,EAAS,EAAO,EAAI,EAAO,IAUjC,GARA,EAAS,MAAM,WAAa,EAC5B,EAAS,MAAM,UAAY,GAEvB,IAAW,GAAK,IAAW,KAC7B,EAAS,MAAM,KAAO,GAAG,EAAO,EAAI,EAAO,IAC3C,EAAS,MAAM,IAAM,GAAG,EAAO,EAAI,EAAO,KAGxC,EAAY,CACd,IAAM,EACH,EAAO,eAAe,MAA+B,gBAAkB,IAE1E,EAAS,MAAM,MAAQ,GAAG,KAAK,IAAI,KAAK,IAAI,EAAc,CAAQ,EAAG,CAAS,EAAE,GAClF,CAIA,IAAoB,EAAO,SAAS,CACtC,CAEA,SAAS,iBAA8B,CACrC,IAAM,EAAM,EAAa,EACnB,EAAW,EAAY,EAI7B,MAFI,CAAC,GAAO,CAAC,MAAuB,CAAC,GAErC,EAAO,EAAA,WAAA,CAAW,EAAK,EAAU,cAAc,CACjD,CAEA,MAAO,CAAE,SAAU,EAAa,UAAW,EAAc,gBAAiB,OAAQ,cAAe,CACnG"}
|
|
@@ -8,11 +8,11 @@ export type OverlayPositioner = {
|
|
|
8
8
|
};
|
|
9
9
|
export type DropdownPositionerOptions = {
|
|
10
10
|
/**
|
|
11
|
-
* Clipping boundary for flip/shift/size
|
|
11
|
+
* Clipping boundary for flip/shift/size: the edges the dropdown must stay within.
|
|
12
12
|
* Defaults to the nearest ancestor that actually clips content (`overflow:
|
|
13
13
|
* hidden|auto|scroll|clip`, e.g. a dialog panel), auto-detected per update via
|
|
14
14
|
* `getClippingAncestorRect()`, intersected with the viewport. Without this, flip/shift only
|
|
15
|
-
* avoid the full page viewport
|
|
15
|
+
* avoid the full page viewport: a dropdown can be "in view" by that measure while still
|
|
16
16
|
* visibly overhanging a much smaller container it's actually nested in. Pass an explicit
|
|
17
17
|
* boundary to override auto-detection.
|
|
18
18
|
*/
|
|
@@ -20,7 +20,7 @@ export type DropdownPositionerOptions = {
|
|
|
20
20
|
/**
|
|
21
21
|
* Returns the text direction used for placement mirroring. Defaults to the resolved
|
|
22
22
|
* direction of the reference element (nearest `dir="ltr"|"rtl"` ancestor, falling back to
|
|
23
|
-
* computed style)
|
|
23
|
+
* computed style): most callers never need to pass this explicitly.
|
|
24
24
|
*/
|
|
25
25
|
getDir?: () => 'ltr' | 'rtl';
|
|
26
26
|
/** Getter for the floating (dropdown panel) element. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"positioner.js","names":[],"sources":["../../src/core/positioner.ts"],"sourcesContent":["import {\n autoUpdate,\n computePosition,\n flip,\n getBoundaryRect,\n getClippingAncestorRect,\n offset,\n type Placement,\n type Rect,\n type SizeData,\n shift,\n size,\n} 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 * Clipping boundary for flip/shift/size — the edges the dropdown must stay within.\n * Defaults to the nearest ancestor that actually clips content (`overflow:\n * hidden|auto|scroll|clip`, e.g. a dialog panel), auto-detected per update via\n * `getClippingAncestorRect()`, intersected with the viewport. Without this, flip/shift only\n * avoid the full page viewport — a dropdown can be \"in view\" by that measure while still\n * visibly overhanging a much smaller container it's actually nested in. Pass an explicit\n * boundary to override auto-detection.\n */\n boundary?: Element | Rect;\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 /**\n * Whether to size the floating element from the reference: at least as wide as the reference,\n * growing to fit its own content, capped by the boundary. Default: true\n */\n matchWidth?: boolean;\n /**\n * Returns the offset in pixels between reference and floating element, read on every update so a\n * reactive offset prop is honored. Default: 0.\n */\n getOffsetPx?: () => number;\n /**\n * Called after each update with the resolved placement (after RTL mirroring and flip). The\n * positioner also writes it to the floating element's `data-placement` attribute itself, so this\n * is only needed to react to placement changes (e.g. tooltip's per-side closed transform).\n */\n onPlacementChange?: (placement: Placement) => void;\n /** Padding (px) used by flip, shift, and size middleware. Default: 6 */\n padding?: number;\n /**\n * Whether to constrain placement to a clipping ancestor when `boundary` is unset. Default:\n * true. Disable for native Popover API panels, which render in the top layer.\n */\n useClippingAncestor?: boolean;\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 boundary,\n getDir,\n getFloating,\n getOffsetPx = () => 0,\n getPlacement,\n getReference,\n matchWidth = true,\n onPlacementChange,\n padding = 6,\n useClippingAncestor = true,\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 // Defaults to `undefined` (meaning \"auto-detect\"), not the detected value itself —\n // re-running the detection on every update (rather than once, at positioner-creation time)\n // matters because the dialog/scroll-container an instance is rendered into can change\n // across opens (e.g. the same `<ore-select>` reused in different dialogs), and the detected\n // ancestor's own rect can change between opens even when it's the same element (a resized\n // dialog).\n const resolvedBoundary = getBoundaryRect(\n boundary ?? (useClippingAncestor ? getClippingAncestorRect(floating) : undefined),\n );\n\n const refWidth = ref.getBoundingClientRect().width;\n let naturalWidth = 0;\n\n if (matchWidth) {\n // Measure the panel at its natural content width, floored at the reference width, so\n // `computePosition()` places (and `shift` keeps inside the boundary) the box that will\n // actually render. `left: 0` frees the measurement from the shrink-to-fit clamp a previous\n // `left` would impose on a `position: fixed` element near the right edge.\n floating.style.left = '0px';\n floating.style.width = 'auto';\n floating.style.minWidth = `${refWidth}px`;\n naturalWidth = floating.getBoundingClientRect().width;\n // Clamp to the width the `size` middleware will report *before* positioning, so `flip`\n // and `shift` compensate for the box that actually renders. Without this, a panel whose\n // natural width exceeds the boundary is shifted fully inside for a width it is then\n // clamped out of — landing further inside the boundary than needed, misaligned with its\n // trigger. Horizontal placements derive their available width from the post-shift x and\n // cannot be pre-clamped; they keep the post-positioning clamp below.\n if (placement.startsWith('top') || placement.startsWith('bottom')) {\n const availableWidth = Math.max(0, resolvedBoundary.width - padding * 2);\n floating.style.width = `${Math.min(Math.max(naturalWidth, refWidth), availableWidth)}px`;\n }\n }\n\n const result = computePosition(ref, floating, {\n boundary: resolvedBoundary,\n middleware: [\n ...(() => {\n const offsetPx = getOffsetPx();\n\n return offsetPx ? [offset(offsetPx)] : [];\n })(),\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 // `computePosition()` assumes `left`/`top` resolve relative to the viewport (correct for\n // `position: fixed`) — true almost always, but not when some ancestor establishes a\n // containing block for fixed descendants (a non-`none` `transform`, even a visually-identity\n // one left over from an entrance transition that never resets to `none` at rest is a real,\n // easy-to-hit case — a modal dialog's panel, say). Analytically detecting *that* ancestor via\n // `getContainingBlock()` and pre-subtracting its rect turned out to be unreliable in\n // practice: browsers don't apply the \"ancestor transform traps fixed descendants\" rule\n // uniformly across every element nested under it in every case we tested — some floating\n // elements in the exact same subtree needed the correction and some didn't, for reasons we\n // couldn't fully pin down. Measuring what actually happened after writing `left`/`top`\n // and correcting only the observed gap sidesteps that: it's a no-op when the browser already\n // put the element where asked, and it fixes the same class of bug the moment there's a real\n // mismatch, regardless of which specific ancestor (if any) turns out to be responsible.\n //\n // The measurement itself must not be fooled by the floating element's *own* transform,\n // though: dropdowns/popovers here all use a `transform: translateY(...)` entrance transition\n // driven by a `[data-open]` attribute + `@starting-style` — right at open, before the\n // transition has visibly progressed, `getBoundingClientRect()` can still reflect that\n // starting offset (a handful of px, matching `--overlay-enter-translate-y`), which this\n // correction would otherwise misread as a permanent ancestor-driven mismatch and bake in\n // forever. Temporarily neutralizing the floating element's own transform for the measurement\n // (and restoring it before anything paints, so there's no visible flash) isolates the\n // correction to ancestor-driven offsets only, which is the only thing it's meant to fix.\n const prevTransition = floating.style.transition;\n const prevTransform = floating.style.transform;\n\n floating.style.transition = 'none';\n floating.style.transform = 'none';\n\n const actual = floating.getBoundingClientRect();\n const deltaX = result.x - actual.left;\n const deltaY = result.y - actual.top;\n\n floating.style.transition = prevTransition;\n floating.style.transform = prevTransform;\n\n if (deltaX !== 0 || deltaY !== 0) {\n floating.style.left = `${result.x + deltaX}px`;\n floating.style.top = `${result.y + deltaY}px`;\n }\n\n if (matchWidth) {\n const available =\n (result.middlewareData.size as SizeData | undefined)?.availableWidth ?? Number.POSITIVE_INFINITY;\n // A panel measured while not yet rendered reports 0 — fall back to the reference width.\n floating.style.width = `${Math.min(Math.max(naturalWidth, refWidth), available)}px`;\n }\n\n // Reported last, after every `left`/`top`/`width` write has settled, so a consumer reacting to\n // the placement (e.g. tooltip's per-side closed transform) sees the final geometry.\n onPlacementChange?.(result.placement);\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"],"mappings":"iNA6EA,IAAM,aAAgB,GAChB,EAAE,SAAS,QAAQ,EAAU,EAAE,QAAQ,SAAU,MAAM,EAEvD,EAAE,SAAS,MAAM,EAAU,EAAE,QAAQ,OAAQ,QAAQ,EAElD,EAaT,SAAgB,yBAAyB,CACvC,WACA,SACA,cACA,kBAAoB,EACpB,eACA,eACA,aAAa,GACb,oBACA,UAAU,EACV,sBAAsB,IACyB,CAC/C,SAAS,mBAA+B,CACtC,IAAM,EAAO,IAAe,GAAK,eAGjC,OAFY,IAAS,GAAK,EAAiB,EAAa,CAAC,KAE1C,MAAQ,aAAa,CAAI,EAAI,CAC9C,CAEA,SAAS,gBAAuB,CAC9B,IAAM,EAAM,EAAa,EACnB,EAAW,EAAY,EAE7B,GAAI,CAAC,GAAO,CAAC,EAAU,OAEvB,IAAM,EAAY,kBAAkB,EAO9B,EAAmB,EACvB,IAAa,EAAsB,EAAwB,CAAQ,EAAI,IAAA,GACzE,EAEM,EAAW,EAAI,sBAAsB,CAAC,CAAC,MACzC,EAAe,EAEnB,GAAI,IAKF,EAAS,MAAM,KAAO,MACtB,EAAS,MAAM,MAAQ,OACvB,EAAS,MAAM,SAAW,GAAG,EAAS,IACtC,EAAe,EAAS,sBAAsB,CAAC,CAAC,MAO5C,EAAU,WAAW,KAAK,GAAK,EAAU,WAAW,QAAQ,GAAG,CACjE,IAAM,EAAiB,KAAK,IAAI,EAAG,EAAiB,MAAQ,EAAU,CAAC,EACvE,EAAS,MAAM,MAAQ,GAAG,KAAK,IAAI,KAAK,IAAI,EAAc,CAAQ,EAAG,CAAc,EAAE,GACvF,CAGF,IAAM,EAAS,EAAgB,EAAK,EAAU,CAC5C,SAAU,EACV,WAAY,CACV,QAAU,CACR,IAAM,EAAW,EAAY,EAE7B,OAAO,EAAW,CAAC,EAAO,CAAQ,CAAC,EAAI,CAAC,CAC1C,EAAA,CAAG,EACH,EAAK,CAAE,SAAQ,CAAC,EAChB,EAAM,CAAE,SAAQ,CAAC,EACjB,GAAI,EAAa,CAAC,EAAK,CAAE,SAAQ,CAAC,CAAC,EAAI,CAAC,CAC1C,EACA,WACF,CAAC,EAED,EAAS,MAAM,KAAO,GAAG,EAAO,EAAE,IAClC,EAAS,MAAM,IAAM,GAAG,EAAO,EAAE,IAyBjC,IAAM,EAAiB,EAAS,MAAM,WAChC,EAAgB,EAAS,MAAM,UAErC,EAAS,MAAM,WAAa,OAC5B,EAAS,MAAM,UAAY,OAE3B,IAAM,EAAS,EAAS,sBAAsB,EACxC,EAAS,EAAO,EAAI,EAAO,KAC3B,EAAS,EAAO,EAAI,EAAO,IAUjC,GARA,EAAS,MAAM,WAAa,EAC5B,EAAS,MAAM,UAAY,GAEvB,IAAW,GAAK,IAAW,KAC7B,EAAS,MAAM,KAAO,GAAG,EAAO,EAAI,EAAO,IAC3C,EAAS,MAAM,IAAM,GAAG,EAAO,EAAI,EAAO,KAGxC,EAAY,CACd,IAAM,EACH,EAAO,eAAe,MAA+B,gBAAkB,IAE1E,EAAS,MAAM,MAAQ,GAAG,KAAK,IAAI,KAAK,IAAI,EAAc,CAAQ,EAAG,CAAS,EAAE,GAClF,CAIA,IAAoB,EAAO,SAAS,CACtC,CAEA,SAAS,iBAA8B,CACrC,IAAM,EAAM,EAAa,EACnB,EAAW,EAAY,EAI7B,MAFI,CAAC,GAAO,CAAC,MAAuB,CAAC,EAE9B,EAAW,EAAK,EAAU,cAAc,CACjD,CAEA,MAAO,CAAE,SAAU,EAAa,UAAW,EAAc,gBAAiB,OAAQ,cAAe,CACnG"}
|
|
1
|
+
{"version":3,"file":"positioner.js","names":[],"sources":["../../src/core/positioner.ts"],"sourcesContent":["import {\n autoUpdate,\n computePosition,\n flip,\n getBoundaryRect,\n getClippingAncestorRect,\n offset,\n type Placement,\n type Rect,\n type SizeData,\n shift,\n size,\n} 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 * Clipping boundary for flip/shift/size: the edges the dropdown must stay within.\n * Defaults to the nearest ancestor that actually clips content (`overflow:\n * hidden|auto|scroll|clip`, e.g. a dialog panel), auto-detected per update via\n * `getClippingAncestorRect()`, intersected with the viewport. Without this, flip/shift only\n * avoid the full page viewport: a dropdown can be \"in view\" by that measure while still\n * visibly overhanging a much smaller container it's actually nested in. Pass an explicit\n * boundary to override auto-detection.\n */\n boundary?: Element | Rect;\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 /**\n * Whether to size the floating element from the reference: at least as wide as the reference,\n * growing to fit its own content, capped by the boundary. Default: true\n */\n matchWidth?: boolean;\n /**\n * Returns the offset in pixels between reference and floating element, read on every update so a\n * reactive offset prop is honored. Default: 0.\n */\n getOffsetPx?: () => number;\n /**\n * Called after each update with the resolved placement (after RTL mirroring and flip). The\n * positioner also writes it to the floating element's `data-placement` attribute itself, so this\n * is only needed to react to placement changes (e.g. tooltip's per-side closed transform).\n */\n onPlacementChange?: (placement: Placement) => void;\n /** Padding (px) used by flip, shift, and size middleware. Default: 6 */\n padding?: number;\n /**\n * Whether to constrain placement to a clipping ancestor when `boundary` is unset. Default:\n * true. Disable for native Popover API panels, which render in the top layer.\n */\n useClippingAncestor?: boolean;\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 boundary,\n getDir,\n getFloating,\n getOffsetPx = () => 0,\n getPlacement,\n getReference,\n matchWidth = true,\n onPlacementChange,\n padding = 6,\n useClippingAncestor = true,\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 // Defaults to `undefined` (meaning \"auto-detect\"), not the detected value itself :\n // re-running the detection on every update (rather than once, at positioner-creation time)\n // matters because the dialog/scroll-container an instance is rendered into can change\n // across opens (e.g. the same `<ore-select>` reused in different dialogs), and the detected\n // ancestor's own rect can change between opens even when it's the same element (a resized\n // dialog).\n const resolvedBoundary = getBoundaryRect(\n boundary ?? (useClippingAncestor ? getClippingAncestorRect(floating) : undefined),\n );\n\n const refWidth = ref.getBoundingClientRect().width;\n let naturalWidth = 0;\n\n if (matchWidth) {\n // Measure the panel at its natural content width, floored at the reference width, so\n // `computePosition()` places (and `shift` keeps inside the boundary) the box that will\n // actually render. `left: 0` frees the measurement from the shrink-to-fit clamp a previous\n // `left` would impose on a `position: fixed` element near the right edge.\n floating.style.left = '0px';\n floating.style.width = 'auto';\n floating.style.minWidth = `${refWidth}px`;\n naturalWidth = floating.getBoundingClientRect().width;\n // Clamp to the width the `size` middleware will report *before* positioning, so `flip`\n // and `shift` compensate for the box that actually renders. Without this, a panel whose\n // natural width exceeds the boundary is shifted fully inside for a width it is then\n // clamped out of: landing further inside the boundary than needed, misaligned with its\n // trigger. Horizontal placements derive their available width from the post-shift x and\n // cannot be pre-clamped; they keep the post-positioning clamp below.\n if (placement.startsWith('top') || placement.startsWith('bottom')) {\n const availableWidth = Math.max(0, resolvedBoundary.width - padding * 2);\n floating.style.width = `${Math.min(Math.max(naturalWidth, refWidth), availableWidth)}px`;\n }\n }\n\n const result = computePosition(ref, floating, {\n boundary: resolvedBoundary,\n middleware: [\n ...(() => {\n const offsetPx = getOffsetPx();\n\n return offsetPx ? [offset(offsetPx)] : [];\n })(),\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 // `computePosition()` assumes `left`/`top` resolve relative to the viewport (correct for\n // `position: fixed`): true almost always, but not when some ancestor establishes a\n // containing block for fixed descendants (a non-`none` `transform`, even a visually-identity\n // one left over from an entrance transition that never resets to `none` at rest is a real,\n // easy-to-hit case: a modal dialog's panel, say). Analytically detecting *that* ancestor via\n // `getContainingBlock()` and pre-subtracting its rect turned out to be unreliable in\n // practice: browsers don't apply the \"ancestor transform traps fixed descendants\" rule\n // uniformly across every element nested under it in every case we tested: some floating\n // elements in the exact same subtree needed the correction and some didn't, for reasons we\n // couldn't fully pin down. Measuring what actually happened after writing `left`/`top`\n // and correcting only the observed gap sidesteps that: it's a no-op when the browser already\n // put the element where asked, and it fixes the same class of bug the moment there's a real\n // mismatch, regardless of which specific ancestor (if any) turns out to be responsible.\n //\n // The measurement itself must not be fooled by the floating element's *own* transform,\n // though: dropdowns/popovers here all use a `transform: translateY(...)` entrance transition\n // driven by a `[data-open]` attribute + `@starting-style`: right at open, before the\n // transition has visibly progressed, `getBoundingClientRect()` can still reflect that\n // starting offset (a handful of px, matching `--overlay-enter-translate-y`), which this\n // correction would otherwise misread as a permanent ancestor-driven mismatch and bake in\n // forever. Temporarily neutralizing the floating element's own transform for the measurement\n // (and restoring it before anything paints, so there's no visible flash) isolates the\n // correction to ancestor-driven offsets only, which is the only thing it's meant to fix.\n const prevTransition = floating.style.transition;\n const prevTransform = floating.style.transform;\n\n floating.style.transition = 'none';\n floating.style.transform = 'none';\n\n const actual = floating.getBoundingClientRect();\n const deltaX = result.x - actual.left;\n const deltaY = result.y - actual.top;\n\n floating.style.transition = prevTransition;\n floating.style.transform = prevTransform;\n\n if (deltaX !== 0 || deltaY !== 0) {\n floating.style.left = `${result.x + deltaX}px`;\n floating.style.top = `${result.y + deltaY}px`;\n }\n\n if (matchWidth) {\n const available =\n (result.middlewareData.size as SizeData | undefined)?.availableWidth ?? Number.POSITIVE_INFINITY;\n // A panel measured while not yet rendered reports 0: fall back to the reference width.\n floating.style.width = `${Math.min(Math.max(naturalWidth, refWidth), available)}px`;\n }\n\n // Reported last, after every `left`/`top`/`width` write has settled, so a consumer reacting to\n // the placement (e.g. tooltip's per-side closed transform) sees the final geometry.\n onPlacementChange?.(result.placement);\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"],"mappings":"iNA6EA,IAAM,aAAgB,GAChB,EAAE,SAAS,QAAQ,EAAU,EAAE,QAAQ,SAAU,MAAM,EAEvD,EAAE,SAAS,MAAM,EAAU,EAAE,QAAQ,OAAQ,QAAQ,EAElD,EAaT,SAAgB,yBAAyB,CACvC,WACA,SACA,cACA,kBAAoB,EACpB,eACA,eACA,aAAa,GACb,oBACA,UAAU,EACV,sBAAsB,IACyB,CAC/C,SAAS,mBAA+B,CACtC,IAAM,EAAO,IAAe,GAAK,eAGjC,OAFY,IAAS,GAAK,EAAiB,EAAa,CAAC,KAE1C,MAAQ,aAAa,CAAI,EAAI,CAC9C,CAEA,SAAS,gBAAuB,CAC9B,IAAM,EAAM,EAAa,EACnB,EAAW,EAAY,EAE7B,GAAI,CAAC,GAAO,CAAC,EAAU,OAEvB,IAAM,EAAY,kBAAkB,EAO9B,EAAmB,EACvB,IAAa,EAAsB,EAAwB,CAAQ,EAAI,IAAA,GACzE,EAEM,EAAW,EAAI,sBAAsB,CAAC,CAAC,MACzC,EAAe,EAEnB,GAAI,IAKF,EAAS,MAAM,KAAO,MACtB,EAAS,MAAM,MAAQ,OACvB,EAAS,MAAM,SAAW,GAAG,EAAS,IACtC,EAAe,EAAS,sBAAsB,CAAC,CAAC,MAO5C,EAAU,WAAW,KAAK,GAAK,EAAU,WAAW,QAAQ,GAAG,CACjE,IAAM,EAAiB,KAAK,IAAI,EAAG,EAAiB,MAAQ,EAAU,CAAC,EACvE,EAAS,MAAM,MAAQ,GAAG,KAAK,IAAI,KAAK,IAAI,EAAc,CAAQ,EAAG,CAAc,EAAE,GACvF,CAGF,IAAM,EAAS,EAAgB,EAAK,EAAU,CAC5C,SAAU,EACV,WAAY,CACV,QAAU,CACR,IAAM,EAAW,EAAY,EAE7B,OAAO,EAAW,CAAC,EAAO,CAAQ,CAAC,EAAI,CAAC,CAC1C,EAAA,CAAG,EACH,EAAK,CAAE,SAAQ,CAAC,EAChB,EAAM,CAAE,SAAQ,CAAC,EACjB,GAAI,EAAa,CAAC,EAAK,CAAE,SAAQ,CAAC,CAAC,EAAI,CAAC,CAC1C,EACA,WACF,CAAC,EAED,EAAS,MAAM,KAAO,GAAG,EAAO,EAAE,IAClC,EAAS,MAAM,IAAM,GAAG,EAAO,EAAE,IAyBjC,IAAM,EAAiB,EAAS,MAAM,WAChC,EAAgB,EAAS,MAAM,UAErC,EAAS,MAAM,WAAa,OAC5B,EAAS,MAAM,UAAY,OAE3B,IAAM,EAAS,EAAS,sBAAsB,EACxC,EAAS,EAAO,EAAI,EAAO,KAC3B,EAAS,EAAO,EAAI,EAAO,IAUjC,GARA,EAAS,MAAM,WAAa,EAC5B,EAAS,MAAM,UAAY,GAEvB,IAAW,GAAK,IAAW,KAC7B,EAAS,MAAM,KAAO,GAAG,EAAO,EAAI,EAAO,IAC3C,EAAS,MAAM,IAAM,GAAG,EAAO,EAAI,EAAO,KAGxC,EAAY,CACd,IAAM,EACH,EAAO,eAAe,MAA+B,gBAAkB,IAE1E,EAAS,MAAM,MAAQ,GAAG,KAAK,IAAI,KAAK,IAAI,EAAc,CAAQ,EAAG,CAAS,EAAE,GAClF,CAIA,IAAoB,EAAO,SAAS,CACtC,CAEA,SAAS,iBAA8B,CACrC,IAAM,EAAM,EAAa,EACnB,EAAW,EAAY,EAI7B,MAFI,CAAC,GAAO,CAAC,MAAuB,CAAC,EAE9B,EAAW,EAAK,EAAU,cAAc,CACjD,CAEA,MAAO,CAAE,SAAU,EAAa,UAAW,EAAc,gBAAiB,OAAQ,cAAe,CACnG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ref-callback.cjs","names":[],"sources":["../../src/core/ref-callback.ts"],"sourcesContent":["import type { Readable } from '@vielzeug/ripple';\nimport { watch } from '@vielzeug/ripple';\n\n/** Shape every `ref` prop in this package uses
|
|
1
|
+
{"version":3,"file":"ref-callback.cjs","names":[],"sources":["../../src/core/ref-callback.ts"],"sourcesContent":["import type { Readable } from '@vielzeug/ripple';\nimport { watch } from '@vielzeug/ripple';\n\n/** Shape every `ref` prop in this package uses: a JS-only escape hatch to the live element. */\nexport type RefCallback<T> = ((el: T | null) => void) | null | undefined;\n\n/**\n * Forwards a mounted element to a JS-only `ref` callback prop, and keeps forwarding to a\n * *new* callback if the prop is set again after mount (e.g. a parent sets it via a ref\n * callback after render, rather than at initial mount). Every text-entry-style component\n * with a `ref` escape-hatch prop (`ore-input`, `ore-textarea`, `ore-message-composer`,\n * `ore-file-input`) wires this identically: call it once from inside `onElement()`, alongside\n * whatever else that element needs wired.\n *\n * @example\n * ```ts\n * onElement(fieldRef, (el) => {\n * const unwireField = tf.wire(el);\n * const unwireRef = bindRefCallback(props.ref, el);\n *\n * return () => {\n * unwireField();\n * unwireRef();\n * };\n * });\n * ```\n */\nexport const bindRefCallback = <T extends Element>(ref: Readable<RefCallback<T>>, el: T): (() => void) => {\n // Immediate fire for when the prop is already set on mount.\n ref.value?.(el);\n\n const sub = watch(ref, (cb) => cb?.(el));\n\n return () => {\n sub.dispose();\n ref.value?.(null);\n };\n};\n"],"mappings":"kCA2BA,IAAa,iBAAsC,EAA+B,IAAwB,CAExG,EAAI,QAAQ,CAAE,EAEd,IAAM,GAAA,EAAM,EAAA,MAAA,CAAM,EAAM,GAAO,IAAK,CAAE,CAAC,EAEvC,UAAa,CACX,EAAI,QAAQ,EACZ,EAAI,QAAQ,IAAI,CAClB,CACF"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { Readable } from '@vielzeug/ripple';
|
|
2
|
-
/** Shape every `ref` prop in this package uses
|
|
2
|
+
/** Shape every `ref` prop in this package uses: a JS-only escape hatch to the live element. */
|
|
3
3
|
export type RefCallback<T> = ((el: T | null) => void) | null | undefined;
|
|
4
4
|
/**
|
|
5
5
|
* Forwards a mounted element to a JS-only `ref` callback prop, and keeps forwarding to a
|
|
6
6
|
* *new* callback if the prop is set again after mount (e.g. a parent sets it via a ref
|
|
7
7
|
* callback after render, rather than at initial mount). Every text-entry-style component
|
|
8
8
|
* with a `ref` escape-hatch prop (`ore-input`, `ore-textarea`, `ore-message-composer`,
|
|
9
|
-
* `ore-file-input`) wires this identically
|
|
9
|
+
* `ore-file-input`) wires this identically: call it once from inside `onElement()`, alongside
|
|
10
10
|
* whatever else that element needs wired.
|
|
11
11
|
*
|
|
12
12
|
* @example
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ref-callback.d.ts","sourceRoot":"","sources":["../../src/core/ref-callback.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAGjD
|
|
1
|
+
{"version":3,"file":"ref-callback.d.ts","sourceRoot":"","sources":["../../src/core/ref-callback.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAGjD,+FAA+F;AAC/F,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,KAAK,IAAI,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;AAEzE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,eAAe,GAAI,CAAC,SAAS,OAAO,EAAE,KAAK,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,KAAG,CAAC,MAAM,IAAI,CAUpG,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ref-callback.js","names":[],"sources":["../../src/core/ref-callback.ts"],"sourcesContent":["import type { Readable } from '@vielzeug/ripple';\nimport { watch } from '@vielzeug/ripple';\n\n/** Shape every `ref` prop in this package uses
|
|
1
|
+
{"version":3,"file":"ref-callback.js","names":[],"sources":["../../src/core/ref-callback.ts"],"sourcesContent":["import type { Readable } from '@vielzeug/ripple';\nimport { watch } from '@vielzeug/ripple';\n\n/** Shape every `ref` prop in this package uses: a JS-only escape hatch to the live element. */\nexport type RefCallback<T> = ((el: T | null) => void) | null | undefined;\n\n/**\n * Forwards a mounted element to a JS-only `ref` callback prop, and keeps forwarding to a\n * *new* callback if the prop is set again after mount (e.g. a parent sets it via a ref\n * callback after render, rather than at initial mount). Every text-entry-style component\n * with a `ref` escape-hatch prop (`ore-input`, `ore-textarea`, `ore-message-composer`,\n * `ore-file-input`) wires this identically: call it once from inside `onElement()`, alongside\n * whatever else that element needs wired.\n *\n * @example\n * ```ts\n * onElement(fieldRef, (el) => {\n * const unwireField = tf.wire(el);\n * const unwireRef = bindRefCallback(props.ref, el);\n *\n * return () => {\n * unwireField();\n * unwireRef();\n * };\n * });\n * ```\n */\nexport const bindRefCallback = <T extends Element>(ref: Readable<RefCallback<T>>, el: T): (() => void) => {\n // Immediate fire for when the prop is already set on mount.\n ref.value?.(el);\n\n const sub = watch(ref, (cb) => cb?.(el));\n\n return () => {\n sub.dispose();\n ref.value?.(null);\n };\n};\n"],"mappings":"yCA2BA,IAAa,iBAAsC,EAA+B,IAAwB,CAExG,EAAI,QAAQ,CAAE,EAEd,IAAM,EAAM,EAAM,EAAM,GAAO,IAAK,CAAE,CAAC,EAEvC,UAAa,CACX,EAAI,QAAQ,EACZ,EAAI,QAAQ,IAAI,CAClB,CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text-field.cjs","names":[],"sources":["../../src/core/text-field.ts"],"sourcesContent":["import { computed, 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 /**\n * Bars the field from constraint validation while true
|
|
1
|
+
{"version":3,"file":"text-field.cjs","names":[],"sources":["../../src/core/text-field.ts"],"sourcesContent":["import { computed, 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 /**\n * Bars the field from constraint validation while true: matches the native HTML rule that a\n * `readonly` field is never a candidate for constraint validation (a `readonly required`\n * field is always valid, per spec), so `validity`/`validationMessage` don't feed a false\n * `valueMissing` into `useField()` just because a read-only field happens to be blank.\n */\n readonly?: Readable<boolean | undefined>;\n /** Marks a blank value invalid: feeds `validity`/`validationMessage` (see below). */\n required?: Readable<boolean | undefined>;\n /** Message for the blank+required case. Defaults to `'This field is required.'`. */\n requiredMessage?: Readable<string | undefined>;\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 /**\n * Registers the real form field handle (the return value of `useField()`) so that\n * `triggerValidation()`: called internally on blur/change: can call its\n * `reportValidity()`. `useField()` itself needs `value` (below) to exist first, so this\n * is a two-step wiring rather than a constructor option:\n *\n * ```ts\n * const tf = createTextField({ value: props.value, ... });\n * const formField = useField({ value: tf.value, ... });\n * tf.attachFormField(formField);\n * ```\n */\n attachFormField: (formField: { reportValidity(): void }) => void;\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 /**\n * Restores the value to whatever the `value` option currently holds (native form\n * `reset()` semantics: a `<input>` reverts to its *current* `value` content attribute,\n * not a frozen snapshot from element creation, so setting the attribute programmatically\n * after mount changes what a later reset reverts to). Wire into `useField({ onReset: tf.reset })`.\n */\n reset: () => void;\n /** Reactive validation message paired with `validity`. Empty string when valid. */\n validationMessage: Readable<string>;\n /**\n * Reactive `ValidityStateFlags`: `{ valueMissing: true }` while `required` and blank,\n * `null` (valid) otherwise. Pass straight to `useField({ validity: tf.validity })`.\n */\n validity: Readable<ValidityStateFlags | 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\nconst isBlank = (value: string): boolean => value.trim() === '';\nconst toFieldValue = (v: string | undefined): string => String(v ?? '');\n\nexport const createTextField = (options: TextFieldOptions): TextFieldHandle => {\n const value = syncedSignal(options.value, options.signal, toFieldValue);\n\n const field = createField(options);\n const counter = options.maxLength ? createCounterState({ maxLength: options.maxLength, value }) : null;\n\n const validity = computed<ValidityStateFlags | null>(() =>\n !options.readonly?.value && options.required?.value && isBlank(value.value) ? { valueMissing: true } : null,\n );\n const validationMessage = computed(() =>\n validity.value ? options.requiredMessage?.value || 'This field is required.' : '',\n );\n\n const reset = (): void => {\n value.value = toFieldValue(options.value.value);\n field.triggerValidation('change');\n };\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, reset, validationMessage, validity, value, wire };\n};\n"],"mappings":"iGAyFA,IAAM,QAAW,GAA2B,EAAM,KAAK,IAAM,GACvD,aAAgB,GAAkC,OAAO,GAAK,EAAE,EAEzD,gBAAmB,GAA+C,CAC7E,IAAM,EAAQ,EAAA,aAAa,EAAQ,MAAO,EAAQ,OAAQ,YAAY,EAEhE,EAAQ,EAAA,YAAY,CAAO,EAC3B,EAAU,EAAQ,UAAY,EAAA,mBAAmB,CAAE,UAAW,EAAQ,UAAW,OAAM,CAAC,EAAI,KAE5F,GAAA,EAAW,EAAA,SAAA,KACf,CAAC,EAAQ,UAAU,OAAS,EAAQ,UAAU,OAAS,QAAQ,EAAM,KAAK,EAAI,CAAE,aAAc,EAAK,EAAI,IACzG,EACM,GAAA,EAAoB,EAAA,SAAA,KACxB,EAAS,MAAQ,EAAQ,iBAAiB,OAAS,0BAA4B,EACjF,EAEM,UAAoB,CACxB,EAAM,MAAQ,aAAa,EAAQ,MAAM,KAAK,EAC9C,EAAM,kBAAkB,QAAQ,CAClC,EAEM,MAAS,GAAwB,CACrC,GAAO,iBAAiB,EACxB,EAAM,MAAQ,GACd,EAAQ,UAAU,GAAS,IAAI,WAAW,QAAS,CAAE,QAAS,EAAK,CAAC,EAAG,EAAE,EACzE,EAAQ,WAAW,GAAS,IAAI,MAAM,SAAU,CAAE,QAAS,EAAK,CAAC,EAAG,EAAE,EACtE,EAAM,kBAAkB,QAAQ,CAClC,EAEM,MAAQ,EAAiD,IAA0C,CACvG,IAAM,EAA8B,CAAC,EAC/B,IAAM,EAAc,IAAiC,CACzD,EAAQ,iBAAiB,EAAM,CAAO,EACtC,EAAS,SAAW,EAAQ,oBAAoB,EAAM,CAAO,CAAC,CAChE,EAEI,EAAQ,SACV,GAAG,QAAU,GAAM,EAAQ,UAAU,CAAe,CAAC,EAGvD,GAAG,QAAU,GAAM,CACjB,EAAE,gBAAgB,EAClB,EAAQ,gBAAgB,CAAC,EACzB,EAAM,MAAQ,EAAQ,MACtB,EAAQ,UAAU,EAAG,EAAQ,KAAK,CACpC,CAAC,EAED,GAAG,SAAW,GAAM,CAClB,EAAE,gBAAgB,EAClB,EAAM,MAAQ,EAAQ,MACtB,EAAQ,WAAW,EAAG,EAAQ,KAAK,EACnC,EAAM,kBAAkB,QAAQ,CAClC,CAAC,EAED,GAAG,OAAS,GAAM,CAChB,EAAQ,SAAS,CAAe,EAChC,EAAM,kBAAkB,MAAM,CAChC,CAAC,EAED,IAAI,EAAW,GACT,WAAqB,CACrB,MAEJ,GAAW,GACX,IAAK,IAAM,KAAW,EAAU,EAAQ,CAD7B,CAEb,EAIA,OAFA,GAAQ,iBAAiB,QAAS,OAAQ,CAAE,KAAM,EAAK,CAAC,EAEjD,MACT,EAEA,MAAO,CAAE,GAAG,EAAO,MAAO,UAAS,MAAO,oBAAmB,WAAU,QAAO,IAAK,CACrF"}
|
|
@@ -15,13 +15,13 @@ export type TextFieldOptions = FieldOptions & {
|
|
|
15
15
|
onFocus?: (event: FocusEvent) => void;
|
|
16
16
|
onInput?: (event: Event, value: string) => void;
|
|
17
17
|
/**
|
|
18
|
-
* Bars the field from constraint validation while true
|
|
18
|
+
* Bars the field from constraint validation while true: matches the native HTML rule that a
|
|
19
19
|
* `readonly` field is never a candidate for constraint validation (a `readonly required`
|
|
20
20
|
* field is always valid, per spec), so `validity`/`validationMessage` don't feed a false
|
|
21
21
|
* `valueMissing` into `useField()` just because a read-only field happens to be blank.
|
|
22
22
|
*/
|
|
23
23
|
readonly?: Readable<boolean | undefined>;
|
|
24
|
-
/** Marks a blank value invalid
|
|
24
|
+
/** Marks a blank value invalid: feeds `validity`/`validationMessage` (see below). */
|
|
25
25
|
required?: Readable<boolean | undefined>;
|
|
26
26
|
/** Message for the blank+required case. Defaults to `'This field is required.'`. */
|
|
27
27
|
requiredMessage?: Readable<string | undefined>;
|
|
@@ -32,7 +32,7 @@ export type TextFieldOptions = FieldOptions & {
|
|
|
32
32
|
export type TextFieldHandle = FieldHandle & {
|
|
33
33
|
/**
|
|
34
34
|
* Registers the real form field handle (the return value of `useField()`) so that
|
|
35
|
-
* `triggerValidation()
|
|
35
|
+
* `triggerValidation()`: called internally on blur/change: can call its
|
|
36
36
|
* `reportValidity()`. `useField()` itself needs `value` (below) to exist first, so this
|
|
37
37
|
* is a two-step wiring rather than a constructor option:
|
|
38
38
|
*
|
|
@@ -55,14 +55,14 @@ export type TextFieldHandle = FieldHandle & {
|
|
|
55
55
|
/**
|
|
56
56
|
* Restores the value to whatever the `value` option currently holds (native form
|
|
57
57
|
* `reset()` semantics: a `<input>` reverts to its *current* `value` content attribute,
|
|
58
|
-
* not a frozen snapshot from element creation
|
|
58
|
+
* not a frozen snapshot from element creation, so setting the attribute programmatically
|
|
59
59
|
* after mount changes what a later reset reverts to). Wire into `useField({ onReset: tf.reset })`.
|
|
60
60
|
*/
|
|
61
61
|
reset: () => void;
|
|
62
62
|
/** Reactive validation message paired with `validity`. Empty string when valid. */
|
|
63
63
|
validationMessage: Readable<string>;
|
|
64
64
|
/**
|
|
65
|
-
* Reactive `ValidityStateFlags
|
|
65
|
+
* Reactive `ValidityStateFlags`: `{ valueMissing: true }` while `required` and blank,
|
|
66
66
|
* `null` (valid) otherwise. Pass straight to `useField({ validity: tf.validity })`.
|
|
67
67
|
*/
|
|
68
68
|
validity: Readable<ValidityStateFlags | null>;
|
|
@@ -75,7 +75,7 @@ export type TextFieldHandle = FieldHandle & {
|
|
|
75
75
|
* the signal's controller calls `abort()`. Without a signal the returned
|
|
76
76
|
* `TextFieldDetach` must be called manually.
|
|
77
77
|
*
|
|
78
|
-
* Safe to call multiple times
|
|
78
|
+
* Safe to call multiple times: each call attaches a fresh set of listeners
|
|
79
79
|
* and returns a distinct detach function. Calling detach multiple times is
|
|
80
80
|
* a no-op (guarded internally).
|
|
81
81
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text-field.d.ts","sourceRoot":"","sources":["../../src/core/text-field.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,QAAQ,EAAE,KAAK,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAExE,OAAO,EAAE,KAAK,YAAY,EAAmC,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAKvH,8EAA8E;AAC9E,MAAM,MAAM,eAAe,GAAG,MAAM,IAAI,CAAC;AAEzC,MAAM,MAAM,gBAAgB,GAAG,YAAY,GAAG;IAC5C,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC;;;;OAIG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACvC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IACrC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IACzC,
|
|
1
|
+
{"version":3,"file":"text-field.d.ts","sourceRoot":"","sources":["../../src/core/text-field.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,QAAQ,EAAE,KAAK,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAExE,OAAO,EAAE,KAAK,YAAY,EAAmC,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAKvH,8EAA8E;AAC9E,MAAM,MAAM,eAAe,GAAG,MAAM,IAAI,CAAC;AAEzC,MAAM,MAAM,gBAAgB,GAAG,YAAY,GAAG;IAC5C,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC;;;;OAIG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACvC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IACrC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IACzC,qFAAqF;IACrF,QAAQ,CAAC,EAAE,QAAQ,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IACzC,oFAAoF;IACpF,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC/C,wGAAwG;IACxG,MAAM,EAAE,WAAW,CAAC;IACpB,KAAK,EAAE,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CACrC,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG;IAC1C;;;;;;;;;;;OAWG;IACH,eAAe,EAAE,CAAC,SAAS,EAAE;QAAE,cAAc,IAAI,IAAI,CAAA;KAAE,KAAK,IAAI,CAAC;IACjE,sEAAsE;IACtE,KAAK,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,IAAI,CAAC;IAC/B;;;OAGG;IACH,OAAO,EAAE,QAAQ,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC;IACvC;;;;;OAKG;IACH,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,mFAAmF;IACnF,iBAAiB,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACpC;;;OAGG;IACH,QAAQ,EAAE,QAAQ,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAAC;IAC9C,uFAAuF;IACvF,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACtB;;;;;;;;;;OAUG;IACH,IAAI,EAAE,CAAC,EAAE,EAAE,gBAAgB,GAAG,mBAAmB,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,eAAe,CAAC;CAC7F,CAAC;AAKF,eAAO,MAAM,eAAe,GAAI,SAAS,gBAAgB,KAAG,eAsE3D,CAAC"}
|