@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
package/dist/copy-command.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"copy-command.js","names":[],"sources":["../src/content/copy-command/copy-command.ts"],"sourcesContent":["import { define, html, onCleanup, prop, useEmit, useSlots } from '@vielzeug/ore';\nimport { computed, signal } from '@vielzeug/ripple';\nimport { srOnlyMixin } from '../../styles';\nimport type { ComponentSize, RoundedSize } from '../../types';\n\nimport componentStyles from './copy-command.css?inline';\n\nexport { ICON_TAG } from '../icon/icon';\n/** Copy command component properties */\nexport type OreCopyCommandProps = {\n /** Border radius size */\n rounded?: RoundedSize;\n /** Component size */\n size?: ComponentSize;\n /** The command string to display and copy to clipboard */\n value?: string;\n /** Visual style variant */\n variant?: 'flat' | 'bordered' | 'ghost';\n};\n\n/** Copy command component events */\nexport type OreCopyCommandEvents = {\n /** Emitted when the command is successfully copied to the clipboard */\n copy: { value: string };\n};\n\n/**\n * A styled, copy-to-clipboard command display component.\n * Shows a command string in a monospace code block with a copy button.\n * Clicking the component copies the value to the clipboard, shows a transient\n * check-mark confirmation, and emits a `copy` event.\n *\n * @element ore-copy-command\n *\n * @attr {string} value - The command string to display and copy\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} variant - Visual style: 'flat' | 'bordered' | 'ghost'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n *\n * @fires copy - Emitted on successful clipboard write. detail: { value: string }\n *\n * @slot suffix - Optional controls appended after the copy button (e.g. a cycle button)\n *\n * @cssprop --copy-command-bg - Background color of the command block\n * @cssprop --copy-command-color - Text color of the command string\n * @cssprop --copy-command-border-color - Border color\n * @cssprop --copy-command-radius - Border radius (overrides the `rounded` attribute)\n * @cssprop --copy-command-padding - Inner padding of the command button\n * @cssprop --copy-command-font-size - Font size of the command string\n * @cssprop --copy-command-icon-color - Color of the copy/check icon\n * @cssprop --copy-command-hover-bg - Background on hover\n *\n * @part wrapper - Outer flex container\n * @part command - The copy button element\n * @part command-text - The `<code>` element displaying the command string\n * @part copy-icon - The icon wrapper span\n * @part suffix - Suffix slot container\n *\n * @example\n * ```html\n * <ore-copy-command value=\"npm install @vielzeug/ripple\"></ore-copy-command>\n *\n * <ore-copy-command value=\"npx -y @vielzeug/codex\" size=\"sm\" variant=\"bordered\"></ore-copy-command>\n *\n * <!-- With a suffix slot (e.g. a cycle button) -->\n * <ore-copy-command value=\"npm install @vielzeug/ripple\">\n * <button slot=\"suffix\" type=\"button\" aria-label=\"Next package\">›</button>\n * </ore-copy-command>\n * ```\n */\nexport const COPY_COMMAND_TAG = 'ore-copy-command' as const;\n\ndefine<OreCopyCommandProps>(COPY_COMMAND_TAG, {\n props: {\n rounded: prop.string<RoundedSize>('md'),\n size: prop.string<ComponentSize>('md'),\n value: prop.string(''),\n variant: prop.string<'flat' | 'bordered' | 'ghost'>('flat'),\n },\n\n setup(props) {\n const emit = useEmit<OreCopyCommandEvents>();\n const slots = useSlots();\n\n const copied = signal(false);\n const copyFailed = signal(false);\n let resetTimer: ReturnType<typeof setTimeout> | null = null;\n\n onCleanup(() => {\n if (resetTimer !== null) clearTimeout(resetTimer);\n });\n\n const handleCopy = async () => {\n const text = props.value.value ?? '';\n\n if (!text) return;\n\n if (resetTimer !== null) clearTimeout(resetTimer);\n\n try {\n await navigator.clipboard.writeText(text);\n copied.value = true;\n copyFailed.value = false;\n emit('copy', { value: text });\n } catch {\n // Clipboard access denied or unavailable (e.g. insecure context)
|
|
1
|
+
{"version":3,"file":"copy-command.js","names":[],"sources":["../src/content/copy-command/copy-command.ts"],"sourcesContent":["import { define, html, onCleanup, prop, useEmit, useSlots } from '@vielzeug/ore';\nimport { computed, signal } from '@vielzeug/ripple';\nimport { srOnlyMixin } from '../../styles';\nimport type { ComponentSize, RoundedSize } from '../../types';\n\nimport componentStyles from './copy-command.css?inline';\n\nexport { ICON_TAG } from '../icon/icon';\n/** Copy command component properties */\nexport type OreCopyCommandProps = {\n /** Border radius size */\n rounded?: RoundedSize;\n /** Component size */\n size?: ComponentSize;\n /** The command string to display and copy to clipboard */\n value?: string;\n /** Visual style variant */\n variant?: 'flat' | 'bordered' | 'ghost';\n};\n\n/** Copy command component events */\nexport type OreCopyCommandEvents = {\n /** Emitted when the command is successfully copied to the clipboard */\n copy: { value: string };\n};\n\n/**\n * A styled, copy-to-clipboard command display component.\n * Shows a command string in a monospace code block with a copy button.\n * Clicking the component copies the value to the clipboard, shows a transient\n * check-mark confirmation, and emits a `copy` event.\n *\n * @element ore-copy-command\n *\n * @attr {string} value - The command string to display and copy\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} variant - Visual style: 'flat' | 'bordered' | 'ghost'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n *\n * @fires copy - Emitted on successful clipboard write. detail: { value: string }\n *\n * @slot suffix - Optional controls appended after the copy button (e.g. a cycle button)\n *\n * @cssprop --copy-command-bg - Background color of the command block\n * @cssprop --copy-command-color - Text color of the command string\n * @cssprop --copy-command-border-color - Border color\n * @cssprop --copy-command-radius - Border radius (overrides the `rounded` attribute)\n * @cssprop --copy-command-padding - Inner padding of the command button\n * @cssprop --copy-command-font-size - Font size of the command string\n * @cssprop --copy-command-icon-color - Color of the copy/check icon\n * @cssprop --copy-command-hover-bg - Background on hover\n *\n * @part wrapper - Outer flex container\n * @part command - The copy button element\n * @part command-text - The `<code>` element displaying the command string\n * @part copy-icon - The icon wrapper span\n * @part suffix - Suffix slot container\n *\n * @example\n * ```html\n * <ore-copy-command value=\"npm install @vielzeug/ripple\"></ore-copy-command>\n *\n * <ore-copy-command value=\"npx -y @vielzeug/codex\" size=\"sm\" variant=\"bordered\"></ore-copy-command>\n *\n * <!-- With a suffix slot (e.g. a cycle button) -->\n * <ore-copy-command value=\"npm install @vielzeug/ripple\">\n * <button slot=\"suffix\" type=\"button\" aria-label=\"Next package\">›</button>\n * </ore-copy-command>\n * ```\n */\nexport const COPY_COMMAND_TAG = 'ore-copy-command' as const;\n\ndefine<OreCopyCommandProps>(COPY_COMMAND_TAG, {\n props: {\n rounded: prop.string<RoundedSize>('md'),\n size: prop.string<ComponentSize>('md'),\n value: prop.string(''),\n variant: prop.string<'flat' | 'bordered' | 'ghost'>('flat'),\n },\n\n setup(props) {\n const emit = useEmit<OreCopyCommandEvents>();\n const slots = useSlots();\n\n const copied = signal(false);\n const copyFailed = signal(false);\n let resetTimer: ReturnType<typeof setTimeout> | null = null;\n\n onCleanup(() => {\n if (resetTimer !== null) clearTimeout(resetTimer);\n });\n\n const handleCopy = async () => {\n const text = props.value.value ?? '';\n\n if (!text) return;\n\n if (resetTimer !== null) clearTimeout(resetTimer);\n\n try {\n await navigator.clipboard.writeText(text);\n copied.value = true;\n copyFailed.value = false;\n emit('copy', { value: text });\n } catch {\n // Clipboard access denied or unavailable (e.g. insecure context): surface it instead of failing silently\n copied.value = false;\n copyFailed.value = true;\n }\n\n resetTimer = setTimeout(() => {\n copied.value = false;\n copyFailed.value = false;\n resetTimer = null;\n }, 2000);\n };\n\n const hasSuffix = computed(() => slots.has('suffix').value);\n const btnLabel = computed(() => {\n if (copied.value) return 'Copied!';\n\n if (copyFailed.value) return 'Copy failed: press to try again';\n\n return `Copy: ${props.value.value ?? ''}`;\n });\n\n return html`\n <div class=\"wrapper\" part=\"wrapper\">\n <button class=\"command\" part=\"command\" type=\"button\" aria-label=\"${btnLabel}\" @click=${handleCopy}>\n <code class=\"command-text\" part=\"command-text\">${props.value}</code>\n <span class=\"copy-icon\" part=\"copy-icon\" aria-hidden=\"true\">\n ${() => {\n if (copied.value)\n return html`\n <ore-icon name=\"check\" size=\"14\" class=\"icon-copied\" aria-hidden=\"true\"></ore-icon>\n `;\n\n if (copyFailed.value)\n return html`\n <ore-icon name=\"circle-alert\" size=\"14\" class=\"icon-failed\" aria-hidden=\"true\"></ore-icon>\n `;\n\n return html`\n <ore-icon name=\"copy\" size=\"14\" aria-hidden=\"true\"></ore-icon>\n `;\n }}\n </span>\n </button>\n <div class=\"suffix\" part=\"suffix\" ?hidden=\"${() => !hasSuffix.value}\">\n <slot name=\"suffix\"></slot>\n </div>\n </div>\n <div role=\"status\" class=\"sr-only\">\n ${() => {\n if (copied.value) return 'Copied to clipboard.';\n\n if (copyFailed.value) return 'Copy failed. Select the command text and copy it manually.';\n\n return '';\n }}\n </div>\n `;\n },\n\n styles: [srOnlyMixin, componentStyles],\n});\n"],"mappings":"+TAsEA,IAAa,EAAmB,mBAEhC,EAA4B,EAAkB,CAC5C,MAAO,CACL,QAAS,EAAK,OAAoB,IAAI,EACtC,KAAM,EAAK,OAAsB,IAAI,EACrC,MAAO,EAAK,OAAO,EAAE,EACrB,QAAS,EAAK,OAAsC,MAAM,CAC5D,EAEA,MAAM,EAAO,CACX,IAAM,EAAO,EAA8B,EACrC,EAAQ,EAAS,EAEjB,EAAS,EAAO,EAAK,EACrB,EAAa,EAAO,EAAK,EAC3B,EAAmD,KAEvD,MAAgB,CACV,IAAe,MAAM,aAAa,CAAU,CAClD,CAAC,EAED,IAAM,WAAa,SAAY,CAC7B,IAAM,EAAO,EAAM,MAAM,OAAS,GAE7B,KAEL,CAAI,IAAe,MAAM,aAAa,CAAU,EAEhD,GAAI,CACF,MAAM,UAAU,UAAU,UAAU,CAAI,EACxC,EAAO,MAAQ,GACf,EAAW,MAAQ,GACnB,EAAK,OAAQ,CAAE,MAAO,CAAK,CAAC,CAC9B,MAAQ,CAEN,EAAO,MAAQ,GACf,EAAW,MAAQ,EACrB,CAEA,EAAa,eAAiB,CAC5B,EAAO,MAAQ,GACf,EAAW,MAAQ,GACnB,EAAa,IACf,EAAG,GAAI,CAjByC,CAkBlD,EAEM,EAAY,MAAe,EAAM,IAAI,QAAQ,CAAC,CAAC,KAAK,EACpD,EAAW,MACX,EAAO,MAAc,UAErB,EAAW,MAAc,kCAEtB,SAAS,EAAM,MAAM,OAAS,IACtC,EAED,MAAO,EAAI;;2EAE4D,EAAS,WAAW,WAAW;2DAC/C,EAAM,MAAM;;kBAGrD,EAAO,MACF,CAAI;;kBAIT,EAAW,MACN,CAAI;;kBAIN,CAAI;;gBAGX;;;yDAG6C,CAAC,EAAU,MAAM;;;;;cAM9D,EAAO,MAAc,uBAErB,EAAW,MAAc,6DAEtB,GACP;;KAGR,EAEA,OAAQ,CAAC,EAAa,CAAe,CACvC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"announcer.cjs","names":[],"sources":["../../src/core/announcer.ts"],"sourcesContent":["// ── Live-Region Announcer ─────────────────────────────────────────────────────\n// Programmatic announcements to screen readers without requiring a visible\n// DOM element. Used for status messages, selection feedback, and count updates\n// that live in components where the visible element is hidden or absent.\n//\n// Two visually-hidden live regions are lazily created in the target document's\n// `<body
|
|
1
|
+
{"version":3,"file":"announcer.cjs","names":[],"sources":["../../src/core/announcer.ts"],"sourcesContent":["// ── Live-Region Announcer ─────────────────────────────────────────────────────\n// Programmatic announcements to screen readers without requiring a visible\n// DOM element. Used for status messages, selection feedback, and count updates\n// that live in components where the visible element is hidden or absent.\n//\n// Two visually-hidden live regions are lazily created in the target document's\n// `<body>`: one polite, one assertive. The clear-then-set pattern forces AT to\n// re-read even identical consecutive messages.\n//\n// Behavior is latest-value replacement (debounce), not queueing: rapid\n// consecutive calls to the same politeness cancel pending writes so only the\n// last message survives. JavaScript cannot know when assistive technology\n// finishes speaking, so a queue would be dishonest.\n//\n// Usage:\n// ```ts\n// import { announce } from './announcer';\n// announce(`${selectedCount} items selected`);\n// announce('Error: field is required', { politeness: 'assertive' });\n// announce('Saved', { document: getHost().ownerDocument });\n// ```\n\nimport { SR_ONLY_INLINE_STYLE } from '../styles';\n\n// ── Per-document live regions (WeakMap for automatic GC + test isolation) ────\n\ntype DocumentRegions = { assertive?: HTMLElement; polite?: HTMLElement };\n\nconst _regions = new WeakMap<Document, DocumentRegions>();\nconst _timers = new WeakMap<HTMLElement, ReturnType<typeof setTimeout>>();\n\n/** Creates and mounts a visually-hidden live region with the given politeness. */\nconst createRegion = (politeness: 'assertive' | 'polite', doc: Document): HTMLElement | null => {\n if (!doc.body) return null;\n\n const el = doc.createElement('div');\n\n el.setAttribute('aria-live', politeness);\n el.setAttribute('aria-atomic', 'true');\n el.setAttribute('data-block-announcer', politeness);\n el.style.cssText = SR_ONLY_INLINE_STYLE;\n\n doc.body.appendChild(el);\n\n return el;\n};\n\n/**\n * Returns the live region for the requested politeness in the given document,\n * creating it on first access. Returns `null` outside a browser context or\n * when the document has no `<body>`.\n */\nconst getRegion = (politeness: 'assertive' | 'polite', doc: Document): HTMLElement | null => {\n let regions = _regions.get(doc);\n\n // Re-create if this specific region was removed from the DOM (e.g. by test teardown).\n if (regions?.[politeness] && !doc.body?.contains(regions[politeness])) {\n regions[politeness] = undefined;\n }\n\n if (!regions?.[politeness]) {\n const el = createRegion(politeness, doc);\n\n if (!el) return null;\n\n if (!regions) {\n regions = {};\n _regions.set(doc, regions);\n }\n\n regions[politeness] = el;\n }\n\n return regions[politeness] ?? null;\n};\n\n// ── Public API ────────────────────────────────────────────────────────────────\n\nexport type AnnouncePoliteness = 'assertive' | 'polite';\n\nexport type AnnounceOptions = {\n /**\n * The document whose `<body>` will host the visually-hidden live region.\n * Defaults to the global `document`. Pass `getHost().ownerDocument` from\n * inside a component that may live in an iframe to announce through the\n * correct accessibility tree.\n */\n document?: Document;\n /**\n * `'polite'`: latest-value replacement; does not interrupt ongoing speech.\n * `'assertive'`: interrupts immediately. Use sparingly; reserve for errors.\n *\n * Default: `'polite'`.\n */\n politeness?: AnnouncePoliteness;\n};\n\n/**\n * Announces a message to screen readers via a singleton visually-hidden\n * live region. Safe to call outside a component lifecycle (no cleanup needed).\n *\n * Uses latest-value replacement: rapid consecutive calls to the same politeness\n * cancel pending writes so only the last message is spoken. The clear-then-set\n * pattern (short delay) forces AT to re-read even when the message text hasn't\n * changed.\n *\n * @example\n * ```ts\n * announce('3 results found');\n * announce('Session expired', { politeness: 'assertive' });\n * announce('Saved', { document: getHost().ownerDocument });\n * ```\n */\nexport const announce = (message: string, options: AnnounceOptions = {}): void => {\n const doc = options.document ?? (typeof document !== 'undefined' ? document : null);\n\n if (!doc) return;\n\n const politeness = options.politeness ?? 'polite';\n const region = getRegion(politeness, doc);\n\n if (!region) return;\n\n // Clear immediately so AT registers a content change, then set after a short\n // delay. This is a debounce window, not a guaranteed speech timing: AT speech\n // timing varies across browsers and screen readers.\n region.textContent = '';\n\n // Use a per-element timer so concurrent polite + assertive announcements don't\n // clobber each other's pending writes.\n const existing = _timers.get(region);\n\n if (existing !== undefined) clearTimeout(existing);\n\n const timer = setTimeout(() => {\n region.textContent = message;\n _timers.delete(region);\n }, 50);\n\n _timers.set(region, timer);\n};\n"],"mappings":"0DA4BA,IAAM,EAAW,IAAI,QACf,EAAU,IAAI,QAGd,cAAgB,EAAoC,IAAsC,CAC9F,GAAI,CAAC,EAAI,KAAM,OAAO,KAEtB,IAAM,EAAK,EAAI,cAAc,KAAK,EASlC,OAPA,EAAG,aAAa,YAAa,CAAU,EACvC,EAAG,aAAa,cAAe,MAAM,EACrC,EAAG,aAAa,uBAAwB,CAAU,EAClD,EAAG,MAAM,QAAU,EAAA,qBAEnB,EAAI,KAAK,YAAY,CAAE,EAEhB,CACT,EAOM,WAAa,EAAoC,IAAsC,CAC3F,IAAI,EAAU,EAAS,IAAI,CAAG,EAO9B,GAJI,IAAU,IAAe,CAAC,EAAI,MAAM,SAAS,EAAQ,EAAW,IAClE,EAAQ,GAAc,IAAA,IAGpB,CAAC,IAAU,GAAa,CAC1B,IAAM,EAAK,aAAa,EAAY,CAAG,EAEvC,GAAI,CAAC,EAAI,OAAO,KAEX,IACH,EAAU,CAAC,EACX,EAAS,IAAI,EAAK,CAAO,GAG3B,EAAQ,GAAc,CACxB,CAEA,OAAO,EAAQ,IAAe,IAChC,EAuCa,UAAY,EAAiB,EAA2B,CAAC,IAAY,CAChF,IAAM,EAAM,EAAQ,WAAa,OAAO,SAAa,IAAc,SAAW,MAE9E,GAAI,CAAC,EAAK,OAGV,IAAM,EAAS,UADI,EAAQ,YAAc,SACJ,CAAG,EAExC,GAAI,CAAC,EAAQ,OAKb,EAAO,YAAc,GAIrB,IAAM,EAAW,EAAQ,IAAI,CAAM,EAE/B,IAAa,IAAA,IAAW,aAAa,CAAQ,EAEjD,IAAM,EAAQ,eAAiB,CAC7B,EAAO,YAAc,EACrB,EAAQ,OAAO,CAAM,CACvB,EAAG,EAAE,EAEL,EAAQ,IAAI,EAAQ,CAAK,CAC3B"}
|
package/dist/core/announcer.d.ts
CHANGED
|
@@ -8,8 +8,8 @@ export type AnnounceOptions = {
|
|
|
8
8
|
*/
|
|
9
9
|
document?: Document;
|
|
10
10
|
/**
|
|
11
|
-
* `'polite'
|
|
12
|
-
* `'assertive'
|
|
11
|
+
* `'polite'`: latest-value replacement; does not interrupt ongoing speech.
|
|
12
|
+
* `'assertive'`: interrupts immediately. Use sparingly; reserve for errors.
|
|
13
13
|
*
|
|
14
14
|
* Default: `'polite'`.
|
|
15
15
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"announcer.js","names":[],"sources":["../../src/core/announcer.ts"],"sourcesContent":["// ── Live-Region Announcer ─────────────────────────────────────────────────────\n// Programmatic announcements to screen readers without requiring a visible\n// DOM element. Used for status messages, selection feedback, and count updates\n// that live in components where the visible element is hidden or absent.\n//\n// Two visually-hidden live regions are lazily created in the target document's\n// `<body
|
|
1
|
+
{"version":3,"file":"announcer.js","names":[],"sources":["../../src/core/announcer.ts"],"sourcesContent":["// ── Live-Region Announcer ─────────────────────────────────────────────────────\n// Programmatic announcements to screen readers without requiring a visible\n// DOM element. Used for status messages, selection feedback, and count updates\n// that live in components where the visible element is hidden or absent.\n//\n// Two visually-hidden live regions are lazily created in the target document's\n// `<body>`: one polite, one assertive. The clear-then-set pattern forces AT to\n// re-read even identical consecutive messages.\n//\n// Behavior is latest-value replacement (debounce), not queueing: rapid\n// consecutive calls to the same politeness cancel pending writes so only the\n// last message survives. JavaScript cannot know when assistive technology\n// finishes speaking, so a queue would be dishonest.\n//\n// Usage:\n// ```ts\n// import { announce } from './announcer';\n// announce(`${selectedCount} items selected`);\n// announce('Error: field is required', { politeness: 'assertive' });\n// announce('Saved', { document: getHost().ownerDocument });\n// ```\n\nimport { SR_ONLY_INLINE_STYLE } from '../styles';\n\n// ── Per-document live regions (WeakMap for automatic GC + test isolation) ────\n\ntype DocumentRegions = { assertive?: HTMLElement; polite?: HTMLElement };\n\nconst _regions = new WeakMap<Document, DocumentRegions>();\nconst _timers = new WeakMap<HTMLElement, ReturnType<typeof setTimeout>>();\n\n/** Creates and mounts a visually-hidden live region with the given politeness. */\nconst createRegion = (politeness: 'assertive' | 'polite', doc: Document): HTMLElement | null => {\n if (!doc.body) return null;\n\n const el = doc.createElement('div');\n\n el.setAttribute('aria-live', politeness);\n el.setAttribute('aria-atomic', 'true');\n el.setAttribute('data-block-announcer', politeness);\n el.style.cssText = SR_ONLY_INLINE_STYLE;\n\n doc.body.appendChild(el);\n\n return el;\n};\n\n/**\n * Returns the live region for the requested politeness in the given document,\n * creating it on first access. Returns `null` outside a browser context or\n * when the document has no `<body>`.\n */\nconst getRegion = (politeness: 'assertive' | 'polite', doc: Document): HTMLElement | null => {\n let regions = _regions.get(doc);\n\n // Re-create if this specific region was removed from the DOM (e.g. by test teardown).\n if (regions?.[politeness] && !doc.body?.contains(regions[politeness])) {\n regions[politeness] = undefined;\n }\n\n if (!regions?.[politeness]) {\n const el = createRegion(politeness, doc);\n\n if (!el) return null;\n\n if (!regions) {\n regions = {};\n _regions.set(doc, regions);\n }\n\n regions[politeness] = el;\n }\n\n return regions[politeness] ?? null;\n};\n\n// ── Public API ────────────────────────────────────────────────────────────────\n\nexport type AnnouncePoliteness = 'assertive' | 'polite';\n\nexport type AnnounceOptions = {\n /**\n * The document whose `<body>` will host the visually-hidden live region.\n * Defaults to the global `document`. Pass `getHost().ownerDocument` from\n * inside a component that may live in an iframe to announce through the\n * correct accessibility tree.\n */\n document?: Document;\n /**\n * `'polite'`: latest-value replacement; does not interrupt ongoing speech.\n * `'assertive'`: interrupts immediately. Use sparingly; reserve for errors.\n *\n * Default: `'polite'`.\n */\n politeness?: AnnouncePoliteness;\n};\n\n/**\n * Announces a message to screen readers via a singleton visually-hidden\n * live region. Safe to call outside a component lifecycle (no cleanup needed).\n *\n * Uses latest-value replacement: rapid consecutive calls to the same politeness\n * cancel pending writes so only the last message is spoken. The clear-then-set\n * pattern (short delay) forces AT to re-read even when the message text hasn't\n * changed.\n *\n * @example\n * ```ts\n * announce('3 results found');\n * announce('Session expired', { politeness: 'assertive' });\n * announce('Saved', { document: getHost().ownerDocument });\n * ```\n */\nexport const announce = (message: string, options: AnnounceOptions = {}): void => {\n const doc = options.document ?? (typeof document !== 'undefined' ? document : null);\n\n if (!doc) return;\n\n const politeness = options.politeness ?? 'polite';\n const region = getRegion(politeness, doc);\n\n if (!region) return;\n\n // Clear immediately so AT registers a content change, then set after a short\n // delay. This is a debounce window, not a guaranteed speech timing: AT speech\n // timing varies across browsers and screen readers.\n region.textContent = '';\n\n // Use a per-element timer so concurrent polite + assertive announcements don't\n // clobber each other's pending writes.\n const existing = _timers.get(region);\n\n if (existing !== undefined) clearTimeout(existing);\n\n const timer = setTimeout(() => {\n region.textContent = message;\n _timers.delete(region);\n }, 50);\n\n _timers.set(region, timer);\n};\n"],"mappings":"6EA4BA,IAAM,EAAW,IAAI,QACf,EAAU,IAAI,QAGd,cAAgB,EAAoC,IAAsC,CAC9F,GAAI,CAAC,EAAI,KAAM,OAAO,KAEtB,IAAM,EAAK,EAAI,cAAc,KAAK,EASlC,OAPA,EAAG,aAAa,YAAa,CAAU,EACvC,EAAG,aAAa,cAAe,MAAM,EACrC,EAAG,aAAa,uBAAwB,CAAU,EAClD,EAAG,MAAM,QAAU,EAEnB,EAAI,KAAK,YAAY,CAAE,EAEhB,CACT,EAOM,WAAa,EAAoC,IAAsC,CAC3F,IAAI,EAAU,EAAS,IAAI,CAAG,EAO9B,GAJI,IAAU,IAAe,CAAC,EAAI,MAAM,SAAS,EAAQ,EAAW,IAClE,EAAQ,GAAc,IAAA,IAGpB,CAAC,IAAU,GAAa,CAC1B,IAAM,EAAK,aAAa,EAAY,CAAG,EAEvC,GAAI,CAAC,EAAI,OAAO,KAEX,IACH,EAAU,CAAC,EACX,EAAS,IAAI,EAAK,CAAO,GAG3B,EAAQ,GAAc,CACxB,CAEA,OAAO,EAAQ,IAAe,IAChC,EAuCa,UAAY,EAAiB,EAA2B,CAAC,IAAY,CAChF,IAAM,EAAM,EAAQ,WAAa,OAAO,SAAa,IAAc,SAAW,MAE9E,GAAI,CAAC,EAAK,OAGV,IAAM,EAAS,UADI,EAAQ,YAAc,SACJ,CAAG,EAExC,GAAI,CAAC,EAAQ,OAKb,EAAO,YAAc,GAIrB,IAAM,EAAW,EAAQ,IAAI,CAAM,EAE/B,IAAa,IAAA,IAAW,aAAa,CAAQ,EAEjD,IAAM,EAAQ,eAAiB,CAC7B,EAAO,YAAc,EACrB,EAAQ,OAAO,CAAM,CACvB,EAAG,EAAE,EAEL,EAAQ,IAAI,EAAQ,CAAK,CAC3B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aria-reflection.cjs","names":[],"sources":["../../src/core/aria-reflection.ts"],"sourcesContent":["/**\n * Cross-shadow-root ARIA relationship helper.\n *\n * Plain IDREF attributes (`aria-controls`, `aria-describedby`, `aria-labelledby`, …) cannot\n * resolve across shadow-tree boundaries
|
|
1
|
+
{"version":3,"file":"aria-reflection.cjs","names":[],"sources":["../../src/core/aria-reflection.ts"],"sourcesContent":["/**\n * Cross-shadow-root ARIA relationship helper.\n *\n * Plain IDREF attributes (`aria-controls`, `aria-describedby`, `aria-labelledby`, …) cannot\n * resolve across shadow-tree boundaries: the browser only looks up an `id` within the same\n * root as the referencing element, so `<div id=\"x\">` inside one component's shadow root is\n * invisible to `aria-controls=\"x\"` set inside another component's shadow root, even when both\n * custom elements are siblings in the light DOM. This is a platform limitation, not a bug :\n * see the WICG \"reference target\" explainer for the full rationale.\n *\n * Modern browsers instead expose element-reflection IDL properties\n * (`ariaControlsElements`, `ariaDescribedByElements`, `ariaLabelledByElements`, …) that accept\n * live `Element` references directly, sidestepping ID lookup entirely: these work across\n * shadow roots by design. Where unsupported, this falls back to the plain IDREF attribute,\n * which is still correct for same-root pairings and degrades gracefully (no relationship)\n * for cross-root ones instead of throwing.\n */\n\nexport type AriaReflectionProperty = 'ariaControlsElements' | 'ariaDescribedByElements' | 'ariaLabelledByElements';\n\nconst ATTR_BY_PROPERTY: Record<AriaReflectionProperty, string> = {\n ariaControlsElements: 'aria-controls',\n ariaDescribedByElements: 'aria-describedby',\n ariaLabelledByElements: 'aria-labelledby',\n};\n\n/**\n * Associates `el` with `targets` via the given ARIA relationship. Prefers the\n * cross-shadow-root-safe element-reflection property; falls back to a plain IDREF attribute\n * built from `targets`' own `id`s when the browser doesn't support element reflection yet.\n *\n * Pass an empty array to clear the relationship.\n */\nexport function setAriaReflection(el: Element, property: AriaReflectionProperty, targets: readonly Element[]): void {\n if (property in el) {\n (el as unknown as Record<AriaReflectionProperty, readonly Element[] | null>)[property] =\n targets.length > 0 ? targets : null;\n\n return;\n }\n\n const attr = ATTR_BY_PROPERTY[property];\n const ids = targets.map((target) => target.id).filter(Boolean);\n\n if (ids.length === 0) el.removeAttribute(attr);\n else el.setAttribute(attr, ids.join(' '));\n}\n"],"mappings":"AAoBA,IAAM,EAA2D,CAC/D,qBAAsB,gBACtB,wBAAyB,mBACzB,uBAAwB,iBAC1B,EASA,SAAgB,kBAAkB,EAAa,EAAkC,EAAmC,CAClH,GAAI,KAAY,EAAI,CAClB,EAA6E,GAC3E,EAAQ,OAAS,EAAI,EAAU,KAEjC,MACF,CAEA,IAAM,EAAO,EAAiB,GACxB,EAAM,EAAQ,IAAK,GAAW,EAAO,EAAE,CAAC,CAAC,OAAO,OAAO,EAEzD,EAAI,SAAW,EAAG,EAAG,gBAAgB,CAAI,EACxC,EAAG,aAAa,EAAM,EAAI,KAAK,GAAG,CAAC,CAC1C"}
|
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
* Cross-shadow-root ARIA relationship helper.
|
|
3
3
|
*
|
|
4
4
|
* Plain IDREF attributes (`aria-controls`, `aria-describedby`, `aria-labelledby`, …) cannot
|
|
5
|
-
* resolve across shadow-tree boundaries
|
|
5
|
+
* resolve across shadow-tree boundaries: the browser only looks up an `id` within the same
|
|
6
6
|
* root as the referencing element, so `<div id="x">` inside one component's shadow root is
|
|
7
7
|
* invisible to `aria-controls="x"` set inside another component's shadow root, even when both
|
|
8
|
-
* custom elements are siblings in the light DOM. This is a platform limitation, not a bug
|
|
8
|
+
* custom elements are siblings in the light DOM. This is a platform limitation, not a bug :
|
|
9
9
|
* see the WICG "reference target" explainer for the full rationale.
|
|
10
10
|
*
|
|
11
11
|
* Modern browsers instead expose element-reflection IDL properties
|
|
12
12
|
* (`ariaControlsElements`, `ariaDescribedByElements`, `ariaLabelledByElements`, …) that accept
|
|
13
|
-
* live `Element` references directly, sidestepping ID lookup entirely
|
|
13
|
+
* live `Element` references directly, sidestepping ID lookup entirely: these work across
|
|
14
14
|
* shadow roots by design. Where unsupported, this falls back to the plain IDREF attribute,
|
|
15
15
|
* which is still correct for same-root pairings and degrades gracefully (no relationship)
|
|
16
16
|
* for cross-root ones instead of throwing.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aria-reflection.js","names":[],"sources":["../../src/core/aria-reflection.ts"],"sourcesContent":["/**\n * Cross-shadow-root ARIA relationship helper.\n *\n * Plain IDREF attributes (`aria-controls`, `aria-describedby`, `aria-labelledby`, …) cannot\n * resolve across shadow-tree boundaries
|
|
1
|
+
{"version":3,"file":"aria-reflection.js","names":[],"sources":["../../src/core/aria-reflection.ts"],"sourcesContent":["/**\n * Cross-shadow-root ARIA relationship helper.\n *\n * Plain IDREF attributes (`aria-controls`, `aria-describedby`, `aria-labelledby`, …) cannot\n * resolve across shadow-tree boundaries: the browser only looks up an `id` within the same\n * root as the referencing element, so `<div id=\"x\">` inside one component's shadow root is\n * invisible to `aria-controls=\"x\"` set inside another component's shadow root, even when both\n * custom elements are siblings in the light DOM. This is a platform limitation, not a bug :\n * see the WICG \"reference target\" explainer for the full rationale.\n *\n * Modern browsers instead expose element-reflection IDL properties\n * (`ariaControlsElements`, `ariaDescribedByElements`, `ariaLabelledByElements`, …) that accept\n * live `Element` references directly, sidestepping ID lookup entirely: these work across\n * shadow roots by design. Where unsupported, this falls back to the plain IDREF attribute,\n * which is still correct for same-root pairings and degrades gracefully (no relationship)\n * for cross-root ones instead of throwing.\n */\n\nexport type AriaReflectionProperty = 'ariaControlsElements' | 'ariaDescribedByElements' | 'ariaLabelledByElements';\n\nconst ATTR_BY_PROPERTY: Record<AriaReflectionProperty, string> = {\n ariaControlsElements: 'aria-controls',\n ariaDescribedByElements: 'aria-describedby',\n ariaLabelledByElements: 'aria-labelledby',\n};\n\n/**\n * Associates `el` with `targets` via the given ARIA relationship. Prefers the\n * cross-shadow-root-safe element-reflection property; falls back to a plain IDREF attribute\n * built from `targets`' own `id`s when the browser doesn't support element reflection yet.\n *\n * Pass an empty array to clear the relationship.\n */\nexport function setAriaReflection(el: Element, property: AriaReflectionProperty, targets: readonly Element[]): void {\n if (property in el) {\n (el as unknown as Record<AriaReflectionProperty, readonly Element[] | null>)[property] =\n targets.length > 0 ? targets : null;\n\n return;\n }\n\n const attr = ATTR_BY_PROPERTY[property];\n const ids = targets.map((target) => target.id).filter(Boolean);\n\n if (ids.length === 0) el.removeAttribute(attr);\n else el.setAttribute(attr, ids.join(' '));\n}\n"],"mappings":"AAoBA,IAAM,EAA2D,CAC/D,qBAAsB,gBACtB,wBAAyB,mBACzB,uBAAwB,iBAC1B,EASA,SAAgB,kBAAkB,EAAa,EAAkC,EAAmC,CAClH,GAAI,KAAY,EAAI,CAClB,EAA6E,GAC3E,EAAQ,OAAS,EAAI,EAAU,KAEjC,MACF,CAEA,IAAM,EAAO,EAAiB,GACxB,EAAM,EAAQ,IAAK,GAAW,EAAO,EAAE,CAAC,CAAC,OAAO,OAAO,EAEzD,EAAI,SAAW,EAAG,EAAG,gBAAgB,CAAI,EACxC,EAAG,aAAa,EAAM,EAAI,KAAK,GAAG,CAAC,CAC1C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auto-resize.cjs","names":[],"sources":["../../src/core/auto-resize.ts"],"sourcesContent":["import type { Readable } from '@vielzeug/ripple';\n\nexport type AutoResizeOptions = {\n /** Gates growth; omit for an always-on composer field, or pass a signal for a toggleable `auto-resize` attribute. */\n enabled?: Readable<boolean | undefined>;\n};\n\nexport type AutoResizeControl = {\n /** Recomputes height from the wired element's current content. No-ops when `enabled` is false or nothing is wired. */\n recompute: () => void;\n /** Wire onto the raw `<textarea>` when it mounts. Returns a detach function to call on unmount. */\n wire: (el: HTMLTextAreaElement) => () => void;\n};\n\n/**\n * Grows a `<textarea>`'s height to fit its content, shared by every component that offers\n * auto-resize (`ore-textarea`, `ore-message-composer`) instead of each reimplementing it.\n *\n * Owns only height
|
|
1
|
+
{"version":3,"file":"auto-resize.cjs","names":[],"sources":["../../src/core/auto-resize.ts"],"sourcesContent":["import type { Readable } from '@vielzeug/ripple';\n\nexport type AutoResizeOptions = {\n /** Gates growth; omit for an always-on composer field, or pass a signal for a toggleable `auto-resize` attribute. */\n enabled?: Readable<boolean | undefined>;\n};\n\nexport type AutoResizeControl = {\n /** Recomputes height from the wired element's current content. No-ops when `enabled` is false or nothing is wired. */\n recompute: () => void;\n /** Wire onto the raw `<textarea>` when it mounts. Returns a detach function to call on unmount. */\n wire: (el: HTMLTextAreaElement) => () => void;\n};\n\n/**\n * Grows a `<textarea>`'s height to fit its content, shared by every component that offers\n * auto-resize (`ore-textarea`, `ore-message-composer`) instead of each reimplementing it.\n *\n * Owns only height: manual-resize cursor/direction is a per-component styling concern, not\n * shared behavior, so it stays local to whichever component renders a resize handle.\n *\n * @example\n * ```ts\n * const autoResize = createAutoResize({ enabled: props['auto-resize'] });\n *\n * onElement(textareaRef, (el) => autoResize.wire(el));\n * // after a programmatic value change that doesn't fire a native `input` event:\n * autoResize.recompute();\n * ```\n */\nexport const createAutoResize = (options: AutoResizeOptions = {}): AutoResizeControl => {\n let wiredEl: HTMLTextAreaElement | null = null;\n\n const recompute = (): void => {\n if (!wiredEl || options.enabled?.value === false) return;\n\n wiredEl.style.height = 'auto';\n wiredEl.style.height = `${wiredEl.scrollHeight}px`;\n };\n\n const wire = (el: HTMLTextAreaElement): (() => void) => {\n wiredEl = el;\n el.addEventListener('input', recompute);\n\n // Deferred a frame: right after mount, the browser hasn't necessarily finished laying out\n // the textarea yet, so a synchronous `scrollHeight` read here can be stale: often reading\n // as 0 and collapsing the field until the next real `input` event happens to correct it.\n // `ore-textarea` has always worked around this locally with its own extra `requestAnimationFrame`\n // call; folding the deferral into `wire()` itself means every consumer gets it for free.\n requestAnimationFrame(recompute);\n\n return () => {\n el.removeEventListener('input', recompute);\n\n if (wiredEl === el) wiredEl = null;\n };\n };\n\n return { recompute, wire };\n};\n"],"mappings":"AA8BA,IAAa,kBAAoB,EAA6B,CAAC,IAAyB,CACtF,IAAI,EAAsC,KAEpC,cAAwB,CACvB,GAAW,EAAQ,SAAS,QAAU,KAE3C,EAAQ,MAAM,OAAS,OACvB,EAAQ,MAAM,OAAS,GAAG,EAAQ,aAAa,IACjD,EAEM,KAAQ,IACZ,EAAU,EACV,EAAG,iBAAiB,QAAS,SAAS,EAOtC,sBAAsB,SAAS,MAElB,CACX,EAAG,oBAAoB,QAAS,SAAS,EAErC,IAAY,IAAI,EAAU,KAChC,GAGF,MAAO,CAAE,UAAW,IAAK,CAC3B"}
|
|
@@ -13,7 +13,7 @@ export type AutoResizeControl = {
|
|
|
13
13
|
* Grows a `<textarea>`'s height to fit its content, shared by every component that offers
|
|
14
14
|
* auto-resize (`ore-textarea`, `ore-message-composer`) instead of each reimplementing it.
|
|
15
15
|
*
|
|
16
|
-
* Owns only height
|
|
16
|
+
* Owns only height: manual-resize cursor/direction is a per-component styling concern, not
|
|
17
17
|
* shared behavior, so it stays local to whichever component renders a resize handle.
|
|
18
18
|
*
|
|
19
19
|
* @example
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auto-resize.js","names":[],"sources":["../../src/core/auto-resize.ts"],"sourcesContent":["import type { Readable } from '@vielzeug/ripple';\n\nexport type AutoResizeOptions = {\n /** Gates growth; omit for an always-on composer field, or pass a signal for a toggleable `auto-resize` attribute. */\n enabled?: Readable<boolean | undefined>;\n};\n\nexport type AutoResizeControl = {\n /** Recomputes height from the wired element's current content. No-ops when `enabled` is false or nothing is wired. */\n recompute: () => void;\n /** Wire onto the raw `<textarea>` when it mounts. Returns a detach function to call on unmount. */\n wire: (el: HTMLTextAreaElement) => () => void;\n};\n\n/**\n * Grows a `<textarea>`'s height to fit its content, shared by every component that offers\n * auto-resize (`ore-textarea`, `ore-message-composer`) instead of each reimplementing it.\n *\n * Owns only height
|
|
1
|
+
{"version":3,"file":"auto-resize.js","names":[],"sources":["../../src/core/auto-resize.ts"],"sourcesContent":["import type { Readable } from '@vielzeug/ripple';\n\nexport type AutoResizeOptions = {\n /** Gates growth; omit for an always-on composer field, or pass a signal for a toggleable `auto-resize` attribute. */\n enabled?: Readable<boolean | undefined>;\n};\n\nexport type AutoResizeControl = {\n /** Recomputes height from the wired element's current content. No-ops when `enabled` is false or nothing is wired. */\n recompute: () => void;\n /** Wire onto the raw `<textarea>` when it mounts. Returns a detach function to call on unmount. */\n wire: (el: HTMLTextAreaElement) => () => void;\n};\n\n/**\n * Grows a `<textarea>`'s height to fit its content, shared by every component that offers\n * auto-resize (`ore-textarea`, `ore-message-composer`) instead of each reimplementing it.\n *\n * Owns only height: manual-resize cursor/direction is a per-component styling concern, not\n * shared behavior, so it stays local to whichever component renders a resize handle.\n *\n * @example\n * ```ts\n * const autoResize = createAutoResize({ enabled: props['auto-resize'] });\n *\n * onElement(textareaRef, (el) => autoResize.wire(el));\n * // after a programmatic value change that doesn't fire a native `input` event:\n * autoResize.recompute();\n * ```\n */\nexport const createAutoResize = (options: AutoResizeOptions = {}): AutoResizeControl => {\n let wiredEl: HTMLTextAreaElement | null = null;\n\n const recompute = (): void => {\n if (!wiredEl || options.enabled?.value === false) return;\n\n wiredEl.style.height = 'auto';\n wiredEl.style.height = `${wiredEl.scrollHeight}px`;\n };\n\n const wire = (el: HTMLTextAreaElement): (() => void) => {\n wiredEl = el;\n el.addEventListener('input', recompute);\n\n // Deferred a frame: right after mount, the browser hasn't necessarily finished laying out\n // the textarea yet, so a synchronous `scrollHeight` read here can be stale: often reading\n // as 0 and collapsing the field until the next real `input` event happens to correct it.\n // `ore-textarea` has always worked around this locally with its own extra `requestAnimationFrame`\n // call; folding the deferral into `wire()` itself means every consumer gets it for free.\n requestAnimationFrame(recompute);\n\n return () => {\n el.removeEventListener('input', recompute);\n\n if (wiredEl === el) wiredEl = null;\n };\n };\n\n return { recompute, wire };\n};\n"],"mappings":"AA8BA,IAAa,kBAAoB,EAA6B,CAAC,IAAyB,CACtF,IAAI,EAAsC,KAEpC,cAAwB,CACvB,GAAW,EAAQ,SAAS,QAAU,KAE3C,EAAQ,MAAM,OAAS,OACvB,EAAQ,MAAM,OAAS,GAAG,EAAQ,aAAa,IACjD,EAEM,KAAQ,IACZ,EAAU,EACV,EAAG,iBAAiB,QAAS,SAAS,EAOtC,sBAAsB,SAAS,MAElB,CACX,EAAG,oBAAoB,QAAS,SAAS,EAErC,IAAY,IAAI,EAAU,KAChC,GAGF,MAAO,CAAE,UAAW,IAAK,CAC3B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkable.cjs","names":[],"sources":["../../src/core/checkable.ts"],"sourcesContent":["import { computed, type Readable, type Signal, signal } from '@vielzeug/ripple';\n\nimport { type ControlValidationMode, createDirtyTracker, createField, type FieldHandle } from './field-base';\nimport { createInteraction } from './keyboard';\nimport { syncedSignal } from './signals';\n\n// ── Checkable control ─────────────────────────────────────────────────────────\n\nexport type CheckableChangePayload = {\n checked: boolean;\n originalEvent?: Event;\n value: string;\n};\n\nexport type CheckableOptions = {\n checked: Readable<boolean | undefined>;\n clearIndeterminateFirst?: boolean;\n disabled?: Readable<boolean | undefined>;\n error?: Readable<string | undefined>;\n group?: { toggle: (value: string, originalEvent?: Event) => void };\n helper?: Readable<string | undefined>;\n indeterminate?: Readable<boolean | undefined>;\n onToggle?: (payload: CheckableChangePayload) => void;\n prefix?: string;\n /** Marks an unchecked control invalid
|
|
1
|
+
{"version":3,"file":"checkable.cjs","names":[],"sources":["../../src/core/checkable.ts"],"sourcesContent":["import { computed, type Readable, type Signal, signal } from '@vielzeug/ripple';\n\nimport { type ControlValidationMode, createDirtyTracker, createField, type FieldHandle } from './field-base';\nimport { createInteraction } from './keyboard';\nimport { syncedSignal } from './signals';\n\n// ── Checkable control ─────────────────────────────────────────────────────────\n\nexport type CheckableChangePayload = {\n checked: boolean;\n originalEvent?: Event;\n value: string;\n};\n\nexport type CheckableOptions = {\n checked: Readable<boolean | undefined>;\n clearIndeterminateFirst?: boolean;\n disabled?: Readable<boolean | undefined>;\n error?: Readable<string | undefined>;\n group?: { toggle: (value: string, originalEvent?: Event) => void };\n helper?: Readable<string | undefined>;\n indeterminate?: Readable<boolean | undefined>;\n onToggle?: (payload: CheckableChangePayload) => void;\n prefix?: string;\n /** Marks an unchecked control invalid: feeds `validity`/`validationMessage` (see below). */\n required?: Readable<boolean | undefined>;\n /** Message for the unchecked+required case. Defaults to `'This field is required.'`. */\n requiredMessage?: Readable<string | undefined>;\n /** `AbortSignal` from the component lifecycle. All reactive subscriptions are torn down on abort. */\n signal: AbortSignal;\n validateOn?: Readable<ControlValidationMode>;\n value: Readable<string | undefined>;\n};\n\nexport type CheckableHandle = FieldHandle & {\n /** The form submission value: null when unchecked/indeterminate, the value string when checked. */\n checkableFormValue: Readable<string | null>;\n checked: Signal<boolean>;\n handleClick: (event: MouseEvent) => boolean;\n handleKeydown: (event: KeyboardEvent) => boolean;\n indeterminate: Signal<boolean>;\n /**\n * Restores `checked`/`indeterminate` to their native \"default\" value. See `DirtyTracker`\n * for the two-state rationale. Wire into `useField({ onReset: checkable.reset })`.\n */\n reset: () => void;\n toggle: (event: Event) => 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 unchecked\n * (indeterminate counts as unchecked), `null` (valid) otherwise. Pass straight to\n * `useField({ validity: checkable.validity })`.\n */\n validity: Readable<ValidityStateFlags | null>;\n};\n\nexport const createCheckable = (options: CheckableOptions): CheckableHandle => {\n const checked = syncedSignal(options.checked, options.signal, Boolean);\n const indeterminate = options.indeterminate\n ? syncedSignal(options.indeterminate, options.signal, Boolean)\n : signal(false);\n const initialChecked = checked.value;\n const initialIndeterminate = indeterminate.value;\n const dirtyTracker = createDirtyTracker();\n\n const checkableFormValue = computed<string | null>(() =>\n indeterminate.value ? null : checked.value ? (options.value.value ?? '') : null,\n );\n\n const field = createField(options);\n\n const validity = computed<ValidityStateFlags | null>(() =>\n options.required?.value && (!checked.value || indeterminate.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 checked.value = dirtyTracker.isDirty ? initialChecked : Boolean(options.checked.value);\n indeterminate.value = dirtyTracker.isDirty ? initialIndeterminate : Boolean(options.indeterminate?.value);\n dirtyTracker.clear();\n field.triggerValidation('change');\n };\n\n const createPayload = (event: Event): CheckableChangePayload => ({\n checked: checked.value,\n originalEvent: event,\n value: options.value.value ?? '',\n });\n\n const toggle = (event: Event): void => {\n if (field.disabled.value) return;\n\n dirtyTracker.markDirty();\n\n if (options.group) {\n indeterminate.value = false;\n options.group.toggle(options.value.value ?? '', event);\n options.onToggle?.(createPayload(event));\n\n return;\n }\n\n if (options.clearIndeterminateFirst && indeterminate.value) {\n indeterminate.value = false;\n } else {\n checked.value = !checked.value;\n indeterminate.value = false;\n }\n\n options.onToggle?.(createPayload(event));\n };\n\n const interaction = createInteraction({\n disabled: field.disabled,\n onPress: (event) => toggle(event),\n });\n\n return {\n ...field,\n checkableFormValue,\n checked,\n handleClick: interaction.handleClick,\n handleKeydown: interaction.handleKeydown,\n indeterminate,\n reset,\n toggle,\n validationMessage,\n validity,\n };\n};\n"],"mappings":"6HAyDA,IAAa,gBAAmB,GAA+C,CAC7E,IAAM,EAAU,EAAA,aAAa,EAAQ,QAAS,EAAQ,OAAQ,OAAO,EAC/D,EAAgB,EAAQ,cAC1B,EAAA,aAAa,EAAQ,cAAe,EAAQ,OAAQ,OAAO,GAAA,EAC3D,EAAA,OAAA,CAAO,EAAK,EACV,EAAiB,EAAQ,MACzB,EAAuB,EAAc,MACrC,EAAe,EAAA,mBAAmB,EAElC,GAAA,EAAqB,EAAA,SAAA,KACzB,EAAc,MAAQ,KAAO,EAAQ,MAAS,EAAQ,MAAM,OAAS,GAAM,IAC7E,EAEM,EAAQ,EAAA,YAAY,CAAO,EAE3B,GAAA,EAAW,EAAA,SAAA,KACf,EAAQ,UAAU,QAAU,CAAC,EAAQ,OAAS,EAAc,OAAS,CAAE,aAAc,EAAK,EAAI,IAChG,EACM,GAAA,EAAoB,EAAA,SAAA,KACxB,EAAS,MAAQ,EAAQ,iBAAiB,OAAS,0BAA4B,EACjF,EAEM,UAAoB,CACxB,EAAQ,MAAQ,EAAa,QAAU,EAAiB,EAAQ,EAAQ,QAAQ,MAChF,EAAc,MAAQ,EAAa,QAAU,EAAuB,EAAQ,EAAQ,eAAe,MACnG,EAAa,MAAM,EACnB,EAAM,kBAAkB,QAAQ,CAClC,EAEM,cAAiB,IAA0C,CAC/D,QAAS,EAAQ,MACjB,cAAe,EACf,MAAO,EAAQ,MAAM,OAAS,EAChC,GAEM,OAAU,GAAuB,CACjC,MAAM,SAAS,MAInB,IAFA,EAAa,UAAU,EAEnB,EAAQ,MAAO,CACjB,EAAc,MAAQ,GACtB,EAAQ,MAAM,OAAO,EAAQ,MAAM,OAAS,GAAI,CAAK,EACrD,EAAQ,WAAW,cAAc,CAAK,CAAC,EAEvC,MACF,CAEI,EAAQ,yBAA2B,EAAc,QAGnD,EAAQ,MAAQ,CAAC,EAAQ,OAFzB,EAAc,MAAQ,GAMxB,EAAQ,WAAW,cAAc,CAAK,CAAC,CATvC,CAUF,EAEM,EAAc,EAAA,kBAAkB,CACpC,SAAU,EAAM,SAChB,QAAU,GAAU,OAAO,CAAK,CAClC,CAAC,EAED,MAAO,CACL,GAAG,EACH,qBACA,UACA,YAAa,EAAY,YACzB,cAAe,EAAY,cAC3B,gBACA,MACA,OACA,oBACA,UACF,CACF"}
|
package/dist/core/checkable.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ export type CheckableOptions = {
|
|
|
17
17
|
indeterminate?: Readable<boolean | undefined>;
|
|
18
18
|
onToggle?: (payload: CheckableChangePayload) => void;
|
|
19
19
|
prefix?: string;
|
|
20
|
-
/** Marks an unchecked control invalid
|
|
20
|
+
/** Marks an unchecked control invalid: feeds `validity`/`validationMessage` (see below). */
|
|
21
21
|
required?: Readable<boolean | undefined>;
|
|
22
22
|
/** Message for the unchecked+required case. Defaults to `'This field is required.'`. */
|
|
23
23
|
requiredMessage?: Readable<string | undefined>;
|
|
@@ -42,7 +42,7 @@ export type CheckableHandle = FieldHandle & {
|
|
|
42
42
|
/** Reactive validation message paired with `validity`. Empty string when valid. */
|
|
43
43
|
validationMessage: Readable<string>;
|
|
44
44
|
/**
|
|
45
|
-
* Reactive `ValidityStateFlags
|
|
45
|
+
* Reactive `ValidityStateFlags`: `{ valueMissing: true }` while `required` and unchecked
|
|
46
46
|
* (indeterminate counts as unchecked), `null` (valid) otherwise. Pass straight to
|
|
47
47
|
* `useField({ validity: checkable.validity })`.
|
|
48
48
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkable.d.ts","sourceRoot":"","sources":["../../src/core/checkable.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,QAAQ,EAAE,KAAK,MAAM,EAAU,MAAM,kBAAkB,CAAC;AAEhF,OAAO,EAAE,KAAK,qBAAqB,EAAmC,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAM7G,MAAM,MAAM,sBAAsB,GAAG;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,KAAK,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,QAAQ,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IACvC,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,EAAE,QAAQ,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IACzC,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACrC,KAAK,CAAC,EAAE;QAAE,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,KAAK,KAAK,IAAI,CAAA;KAAE,CAAC;IACnE,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACtC,aAAa,CAAC,EAAE,QAAQ,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IAC9C,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,sBAAsB,KAAK,IAAI,CAAC;IACrD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,
|
|
1
|
+
{"version":3,"file":"checkable.d.ts","sourceRoot":"","sources":["../../src/core/checkable.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,QAAQ,EAAE,KAAK,MAAM,EAAU,MAAM,kBAAkB,CAAC;AAEhF,OAAO,EAAE,KAAK,qBAAqB,EAAmC,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAM7G,MAAM,MAAM,sBAAsB,GAAG;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,KAAK,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,QAAQ,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IACvC,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,EAAE,QAAQ,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IACzC,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACrC,KAAK,CAAC,EAAE;QAAE,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,KAAK,KAAK,IAAI,CAAA;KAAE,CAAC;IACnE,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACtC,aAAa,CAAC,EAAE,QAAQ,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IAC9C,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,sBAAsB,KAAK,IAAI,CAAC;IACrD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4FAA4F;IAC5F,QAAQ,CAAC,EAAE,QAAQ,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IACzC,wFAAwF;IACxF,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC/C,qGAAqG;IACrG,MAAM,EAAE,WAAW,CAAC;IACpB,UAAU,CAAC,EAAE,QAAQ,CAAC,qBAAqB,CAAC,CAAC;IAC7C,KAAK,EAAE,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CACrC,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG;IAC1C,mGAAmG;IACnG,kBAAkB,EAAE,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC5C,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACzB,WAAW,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC;IAC5C,aAAa,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,OAAO,CAAC;IACjD,aAAa,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAC/B;;;OAGG;IACH,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAC/B,mFAAmF;IACnF,iBAAiB,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACpC;;;;OAIG;IACH,QAAQ,EAAE,QAAQ,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAAC;CAC/C,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,SAAS,gBAAgB,KAAG,eA2E3D,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkable.js","names":[],"sources":["../../src/core/checkable.ts"],"sourcesContent":["import { computed, type Readable, type Signal, signal } from '@vielzeug/ripple';\n\nimport { type ControlValidationMode, createDirtyTracker, createField, type FieldHandle } from './field-base';\nimport { createInteraction } from './keyboard';\nimport { syncedSignal } from './signals';\n\n// ── Checkable control ─────────────────────────────────────────────────────────\n\nexport type CheckableChangePayload = {\n checked: boolean;\n originalEvent?: Event;\n value: string;\n};\n\nexport type CheckableOptions = {\n checked: Readable<boolean | undefined>;\n clearIndeterminateFirst?: boolean;\n disabled?: Readable<boolean | undefined>;\n error?: Readable<string | undefined>;\n group?: { toggle: (value: string, originalEvent?: Event) => void };\n helper?: Readable<string | undefined>;\n indeterminate?: Readable<boolean | undefined>;\n onToggle?: (payload: CheckableChangePayload) => void;\n prefix?: string;\n /** Marks an unchecked control invalid
|
|
1
|
+
{"version":3,"file":"checkable.js","names":[],"sources":["../../src/core/checkable.ts"],"sourcesContent":["import { computed, type Readable, type Signal, signal } from '@vielzeug/ripple';\n\nimport { type ControlValidationMode, createDirtyTracker, createField, type FieldHandle } from './field-base';\nimport { createInteraction } from './keyboard';\nimport { syncedSignal } from './signals';\n\n// ── Checkable control ─────────────────────────────────────────────────────────\n\nexport type CheckableChangePayload = {\n checked: boolean;\n originalEvent?: Event;\n value: string;\n};\n\nexport type CheckableOptions = {\n checked: Readable<boolean | undefined>;\n clearIndeterminateFirst?: boolean;\n disabled?: Readable<boolean | undefined>;\n error?: Readable<string | undefined>;\n group?: { toggle: (value: string, originalEvent?: Event) => void };\n helper?: Readable<string | undefined>;\n indeterminate?: Readable<boolean | undefined>;\n onToggle?: (payload: CheckableChangePayload) => void;\n prefix?: string;\n /** Marks an unchecked control invalid: feeds `validity`/`validationMessage` (see below). */\n required?: Readable<boolean | undefined>;\n /** Message for the unchecked+required case. Defaults to `'This field is required.'`. */\n requiredMessage?: Readable<string | undefined>;\n /** `AbortSignal` from the component lifecycle. All reactive subscriptions are torn down on abort. */\n signal: AbortSignal;\n validateOn?: Readable<ControlValidationMode>;\n value: Readable<string | undefined>;\n};\n\nexport type CheckableHandle = FieldHandle & {\n /** The form submission value: null when unchecked/indeterminate, the value string when checked. */\n checkableFormValue: Readable<string | null>;\n checked: Signal<boolean>;\n handleClick: (event: MouseEvent) => boolean;\n handleKeydown: (event: KeyboardEvent) => boolean;\n indeterminate: Signal<boolean>;\n /**\n * Restores `checked`/`indeterminate` to their native \"default\" value. See `DirtyTracker`\n * for the two-state rationale. Wire into `useField({ onReset: checkable.reset })`.\n */\n reset: () => void;\n toggle: (event: Event) => 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 unchecked\n * (indeterminate counts as unchecked), `null` (valid) otherwise. Pass straight to\n * `useField({ validity: checkable.validity })`.\n */\n validity: Readable<ValidityStateFlags | null>;\n};\n\nexport const createCheckable = (options: CheckableOptions): CheckableHandle => {\n const checked = syncedSignal(options.checked, options.signal, Boolean);\n const indeterminate = options.indeterminate\n ? syncedSignal(options.indeterminate, options.signal, Boolean)\n : signal(false);\n const initialChecked = checked.value;\n const initialIndeterminate = indeterminate.value;\n const dirtyTracker = createDirtyTracker();\n\n const checkableFormValue = computed<string | null>(() =>\n indeterminate.value ? null : checked.value ? (options.value.value ?? '') : null,\n );\n\n const field = createField(options);\n\n const validity = computed<ValidityStateFlags | null>(() =>\n options.required?.value && (!checked.value || indeterminate.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 checked.value = dirtyTracker.isDirty ? initialChecked : Boolean(options.checked.value);\n indeterminate.value = dirtyTracker.isDirty ? initialIndeterminate : Boolean(options.indeterminate?.value);\n dirtyTracker.clear();\n field.triggerValidation('change');\n };\n\n const createPayload = (event: Event): CheckableChangePayload => ({\n checked: checked.value,\n originalEvent: event,\n value: options.value.value ?? '',\n });\n\n const toggle = (event: Event): void => {\n if (field.disabled.value) return;\n\n dirtyTracker.markDirty();\n\n if (options.group) {\n indeterminate.value = false;\n options.group.toggle(options.value.value ?? '', event);\n options.onToggle?.(createPayload(event));\n\n return;\n }\n\n if (options.clearIndeterminateFirst && indeterminate.value) {\n indeterminate.value = false;\n } else {\n checked.value = !checked.value;\n indeterminate.value = false;\n }\n\n options.onToggle?.(createPayload(event));\n };\n\n const interaction = createInteraction({\n disabled: field.disabled,\n onPress: (event) => toggle(event),\n });\n\n return {\n ...field,\n checkableFormValue,\n checked,\n handleClick: interaction.handleClick,\n handleKeydown: interaction.handleKeydown,\n indeterminate,\n reset,\n toggle,\n validationMessage,\n validity,\n };\n};\n"],"mappings":"4NAyDA,IAAa,gBAAmB,GAA+C,CAC7E,IAAM,EAAU,EAAa,EAAQ,QAAS,EAAQ,OAAQ,OAAO,EAC/D,EAAgB,EAAQ,cAC1B,EAAa,EAAQ,cAAe,EAAQ,OAAQ,OAAO,EAC3D,EAAO,EAAK,EACV,EAAiB,EAAQ,MACzB,EAAuB,EAAc,MACrC,EAAe,EAAmB,EAElC,EAAqB,MACzB,EAAc,MAAQ,KAAO,EAAQ,MAAS,EAAQ,MAAM,OAAS,GAAM,IAC7E,EAEM,EAAQ,EAAY,CAAO,EAE3B,EAAW,MACf,EAAQ,UAAU,QAAU,CAAC,EAAQ,OAAS,EAAc,OAAS,CAAE,aAAc,EAAK,EAAI,IAChG,EACM,EAAoB,MACxB,EAAS,MAAQ,EAAQ,iBAAiB,OAAS,0BAA4B,EACjF,EAEM,UAAoB,CACxB,EAAQ,MAAQ,EAAa,QAAU,EAAiB,EAAQ,EAAQ,QAAQ,MAChF,EAAc,MAAQ,EAAa,QAAU,EAAuB,EAAQ,EAAQ,eAAe,MACnG,EAAa,MAAM,EACnB,EAAM,kBAAkB,QAAQ,CAClC,EAEM,cAAiB,IAA0C,CAC/D,QAAS,EAAQ,MACjB,cAAe,EACf,MAAO,EAAQ,MAAM,OAAS,EAChC,GAEM,OAAU,GAAuB,CACjC,MAAM,SAAS,MAInB,IAFA,EAAa,UAAU,EAEnB,EAAQ,MAAO,CACjB,EAAc,MAAQ,GACtB,EAAQ,MAAM,OAAO,EAAQ,MAAM,OAAS,GAAI,CAAK,EACrD,EAAQ,WAAW,cAAc,CAAK,CAAC,EAEvC,MACF,CAEI,EAAQ,yBAA2B,EAAc,QAGnD,EAAQ,MAAQ,CAAC,EAAQ,OAFzB,EAAc,MAAQ,GAMxB,EAAQ,WAAW,cAAc,CAAK,CAAC,CATvC,CAUF,EAEM,EAAc,EAAkB,CACpC,SAAU,EAAM,SAChB,QAAU,GAAU,OAAO,CAAK,CAClC,CAAC,EAED,MAAO,CACL,GAAG,EACH,qBACA,UACA,YAAa,EAAY,YACzB,cAAe,EAAY,cAC3B,gBACA,MACA,OACA,oBACA,UACF,CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"choice-field.cjs","names":[],"sources":["../../src/core/choice-field.ts"],"sourcesContent":["import { computed, type Readable, watch } from '@vielzeug/ripple';\n\nimport { createDirtyTracker, createField, type FieldHandle, type FieldOptions } from './field-base';\nimport { syncedSignal } from './signals';\n\n// ── Choice change event payload ──────────────────────────────────────────────────────────────\n\nexport type ChoiceChangeDetail = {\n labels: string[];\n originalEvent?: Event;\n values: string[];\n};\n\n// ── Choice field ──────────────────────────────────────────────────────────────────────\n\nexport type ChoiceFieldOptions = FieldOptions & {\n multiple?: Readable<boolean | undefined>;\n /** Marks an empty selection invalid
|
|
1
|
+
{"version":3,"file":"choice-field.cjs","names":[],"sources":["../../src/core/choice-field.ts"],"sourcesContent":["import { computed, type Readable, watch } from '@vielzeug/ripple';\n\nimport { createDirtyTracker, createField, type FieldHandle, type FieldOptions } from './field-base';\nimport { syncedSignal } from './signals';\n\n// ── Choice change event payload ──────────────────────────────────────────────────────────────\n\nexport type ChoiceChangeDetail = {\n labels: string[];\n originalEvent?: Event;\n values: string[];\n};\n\n// ── Choice field ──────────────────────────────────────────────────────────────────────\n\nexport type ChoiceFieldOptions = FieldOptions & {\n multiple?: Readable<boolean | undefined>;\n /** Marks an empty selection invalid: feeds `validity`/`validationMessage` (see below). */\n required?: Readable<boolean | undefined>;\n /** Message for the empty-selection+required case. Defaults to `'Please make a selection.'`. */\n requiredMessage?: Readable<string | undefined>;\n /** `AbortSignal` from the component lifecycle. All internal subscriptions are disposed on abort. */\n signal: AbortSignal;\n /**\n * Current selection value(s). Accepts a comma-separated string\n * (legacy/single-select form serialisation) or a `string[]` array.\n * The field normalises both formats internally via `parseChoiceValues`.\n */\n value: Readable<string | string[] | undefined>;\n};\n\nexport type ChoiceFieldHandle = FieldHandle & {\n clear: () => void;\n formValue: Readable<string>;\n removeValue: (value: string) => void;\n /**\n * Restores the selection to its native \"default\". See `DirtyTracker` for the two-state\n * rationale.\n */\n reset: () => void;\n selectedValue: Readable<string | undefined>;\n selectedValues: Readable<string[]>;\n selectValue: (value: string) => void;\n setValues: (values: string[]) => void;\n /**\n * Toggles `value` in the selection.\n * - **Multiple mode**: adds if absent, removes if present.\n * - **Single mode**: always selects `value` (acts like `selectValue`: cannot\n * deselect; use `clear()` to reset a single-select field).\n */\n toggleValue: (value: string) => void;\n /** Reactive validation message paired with `validity`. Empty string when valid. */\n validationMessage: Readable<string>;\n /**\n * Reactive `ValidityStateFlags`: `{ valueMissing: true }` while `required` and no option is\n * selected, `null` (valid) otherwise. Pass straight to `useField({ validity: choice.validity })`.\n */\n validity: Readable<ValidityStateFlags | null>;\n};\n\nconst parseChoiceValues = (raw: string | string[] | undefined): string[] => {\n if (!raw) return [];\n\n if (Array.isArray(raw)) return raw.filter(Boolean);\n\n return raw\n .split(',')\n .map((entry) => entry.trim())\n .filter(Boolean);\n};\n\nexport const createChoiceField = (options: ChoiceFieldOptions): ChoiceFieldHandle => {\n const isMultiple = computed(() => Boolean(options.multiple?.value));\n\n const normalizeValues = (values: string[]): string[] => {\n const normalized = isMultiple.value ? values : values.slice(0, 1);\n\n return [...new Set(normalized.filter(Boolean))];\n };\n\n // Kept in sync with `options.value` via the shared helper (see `checkable.ts`/`text-field.ts`\n // for the same pattern) rather than a hand-rolled signal + watch pair.\n const selectedValues = syncedSignal(options.value, options.signal, (raw) => normalizeValues(parseChoiceValues(raw)));\n const formValue = computed(() =>\n isMultiple.value ? selectedValues.value.join(',') : (selectedValues.value[0] ?? ''),\n );\n\n const dirtyTracker = createDirtyTracker();\n\n // The actual state setter, shared by every mutation path. Deliberately *not* where the dirty\n // tracker gets marked: `syncFromProp` (below) calls this directly to stay exempt from it,\n // since mirroring an external prop change is never \"the user changed the selection\".\n const applyValues = (values: string[]): void => {\n selectedValues.value = normalizeValues(values);\n };\n\n const setValues = (values: string[]): void => {\n dirtyTracker.markDirty();\n applyValues(values);\n };\n const clear = (): void => setValues([]);\n const removeValue = (value: string): void => {\n dirtyTracker.markDirty();\n selectedValues.value = selectedValues.value.filter((v) => v !== value);\n };\n\n const selectValue = (value: string): void => {\n if (isMultiple.value) {\n if (!selectedValues.value.includes(value)) setValues([...selectedValues.value, value]);\n\n return;\n }\n\n setValues([value]);\n };\n\n const toggleValue = (value: string): void => {\n if (isMultiple.value) {\n if (selectedValues.value.includes(value)) removeValue(value);\n else selectValue(value);\n } else {\n selectValue(value);\n }\n };\n\n const syncFromProp = (nextValue: string | string[] | undefined): void => {\n applyValues(parseChoiceValues(nextValue));\n };\n\n const field = createField(options);\n\n const validity = computed<ValidityStateFlags | null>(() =>\n options.required?.value && selectedValues.value.length === 0 ? { valueMissing: true } : null,\n );\n const validationMessage = computed(() =>\n validity.value ? options.requiredMessage?.value || 'Please make a selection.' : '',\n );\n\n if (options.multiple) {\n const multipleSub = watch(options.multiple, () => syncFromProp(options.value.value));\n\n options.signal.addEventListener('abort', () => multipleSub.dispose(), { once: true });\n }\n\n const initialValues = selectedValues.value;\n const reset = (): void => {\n applyValues(dirtyTracker.isDirty ? initialValues : parseChoiceValues(options.value.value));\n dirtyTracker.clear();\n field.triggerValidation('change');\n };\n\n return {\n ...field,\n clear,\n formValue,\n removeValue,\n reset,\n selectedValue: computed(() => selectedValues.value[0]),\n selectedValues,\n selectValue,\n setValues,\n toggleValue,\n validationMessage,\n validity,\n };\n};\n"],"mappings":"iGA4DA,IAAM,kBAAqB,GACpB,EAED,MAAM,QAAQ,CAAG,EAAU,EAAI,OAAO,OAAO,EAE1C,EACJ,MAAM,GAAG,CAAC,CACV,IAAK,GAAU,EAAM,KAAK,CAAC,CAAC,CAC5B,OAAO,OAAO,EAPA,CAAC,EAUP,kBAAqB,GAAmD,CACnF,IAAM,GAAA,EAAa,EAAA,SAAA,KAAe,EAAQ,EAAQ,UAAU,KAAM,EAE5D,gBAAmB,GAA+B,CACtD,IAAM,EAAa,EAAW,MAAQ,EAAS,EAAO,MAAM,EAAG,CAAC,EAEhE,MAAO,CAAC,GAAG,IAAI,IAAI,EAAW,OAAO,OAAO,CAAC,CAAC,CAChD,EAIM,EAAiB,EAAA,aAAa,EAAQ,MAAO,EAAQ,OAAS,GAAQ,gBAAgB,kBAAkB,CAAG,CAAC,CAAC,EAC7G,GAAA,EAAY,EAAA,SAAA,KAChB,EAAW,MAAQ,EAAe,MAAM,KAAK,GAAG,EAAK,EAAe,MAAM,IAAM,EAClF,EAEM,EAAe,EAAA,mBAAmB,EAKlC,YAAe,GAA2B,CAC9C,EAAe,MAAQ,gBAAgB,CAAM,CAC/C,EAEM,UAAa,GAA2B,CAC5C,EAAa,UAAU,EACvB,YAAY,CAAM,CACpB,EACM,UAAoB,UAAU,CAAC,CAAC,EAChC,YAAe,GAAwB,CAC3C,EAAa,UAAU,EACvB,EAAe,MAAQ,EAAe,MAAM,OAAQ,GAAM,IAAM,CAAK,CACvE,EAEM,YAAe,GAAwB,CAC3C,GAAI,EAAW,MAAO,CACf,EAAe,MAAM,SAAS,CAAK,GAAG,UAAU,CAAC,GAAG,EAAe,MAAO,CAAK,CAAC,EAErF,MACF,CAEA,UAAU,CAAC,CAAK,CAAC,CACnB,EAEM,YAAe,GAAwB,CACvC,EAAW,OACT,EAAe,MAAM,SAAS,CAAK,EAAG,YAAY,CAAK,EACtD,YAAY,CAAK,CAI1B,EAEM,aAAgB,GAAmD,CACvE,YAAY,kBAAkB,CAAS,CAAC,CAC1C,EAEM,EAAQ,EAAA,YAAY,CAAO,EAE3B,GAAA,EAAW,EAAA,SAAA,KACf,EAAQ,UAAU,OAAS,EAAe,MAAM,SAAW,EAAI,CAAE,aAAc,EAAK,EAAI,IAC1F,EACM,GAAA,EAAoB,EAAA,SAAA,KACxB,EAAS,MAAQ,EAAQ,iBAAiB,OAAS,2BAA6B,EAClF,EAEA,GAAI,EAAQ,SAAU,CACpB,IAAM,GAAA,EAAc,EAAA,MAAA,CAAM,EAAQ,aAAgB,aAAa,EAAQ,MAAM,KAAK,CAAC,EAEnF,EAAQ,OAAO,iBAAiB,YAAe,EAAY,QAAQ,EAAG,CAAE,KAAM,EAAK,CAAC,CACtF,CAEA,IAAM,EAAgB,EAAe,MAC/B,UAAoB,CACxB,YAAY,EAAa,QAAU,EAAgB,kBAAkB,EAAQ,MAAM,KAAK,CAAC,EACzF,EAAa,MAAM,EACnB,EAAM,kBAAkB,QAAQ,CAClC,EAEA,MAAO,CACL,GAAG,EACH,MACA,YACA,YACA,MACA,eAAA,EAAe,EAAA,SAAA,KAAe,EAAe,MAAM,EAAE,EACrD,iBACA,YACA,UACA,YACA,oBACA,UACF,CACF"}
|
|
@@ -7,7 +7,7 @@ export type ChoiceChangeDetail = {
|
|
|
7
7
|
};
|
|
8
8
|
export type ChoiceFieldOptions = FieldOptions & {
|
|
9
9
|
multiple?: Readable<boolean | undefined>;
|
|
10
|
-
/** Marks an empty selection invalid
|
|
10
|
+
/** Marks an empty selection invalid: feeds `validity`/`validationMessage` (see below). */
|
|
11
11
|
required?: Readable<boolean | undefined>;
|
|
12
12
|
/** Message for the empty-selection+required case. Defaults to `'Please make a selection.'`. */
|
|
13
13
|
requiredMessage?: Readable<string | undefined>;
|
|
@@ -36,14 +36,14 @@ export type ChoiceFieldHandle = FieldHandle & {
|
|
|
36
36
|
/**
|
|
37
37
|
* Toggles `value` in the selection.
|
|
38
38
|
* - **Multiple mode**: adds if absent, removes if present.
|
|
39
|
-
* - **Single mode**: always selects `value` (acts like `selectValue
|
|
39
|
+
* - **Single mode**: always selects `value` (acts like `selectValue`: cannot
|
|
40
40
|
* deselect; use `clear()` to reset a single-select field).
|
|
41
41
|
*/
|
|
42
42
|
toggleValue: (value: string) => void;
|
|
43
43
|
/** Reactive validation message paired with `validity`. Empty string when valid. */
|
|
44
44
|
validationMessage: Readable<string>;
|
|
45
45
|
/**
|
|
46
|
-
* Reactive `ValidityStateFlags
|
|
46
|
+
* Reactive `ValidityStateFlags`: `{ valueMissing: true }` while `required` and no option is
|
|
47
47
|
* selected, `null` (valid) otherwise. Pass straight to `useField({ validity: choice.validity })`.
|
|
48
48
|
*/
|
|
49
49
|
validity: Readable<ValidityStateFlags | null>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"choice-field.d.ts","sourceRoot":"","sources":["../../src/core/choice-field.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,QAAQ,EAAS,MAAM,kBAAkB,CAAC;AAElE,OAAO,EAAmC,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAKpG,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,aAAa,CAAC,EAAE,KAAK,CAAC;IACtB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAIF,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG;IAC9C,QAAQ,CAAC,EAAE,QAAQ,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IACzC,
|
|
1
|
+
{"version":3,"file":"choice-field.d.ts","sourceRoot":"","sources":["../../src/core/choice-field.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,QAAQ,EAAS,MAAM,kBAAkB,CAAC;AAElE,OAAO,EAAmC,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAKpG,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,aAAa,CAAC,EAAE,KAAK,CAAC;IACtB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAIF,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG;IAC9C,QAAQ,CAAC,EAAE,QAAQ,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IACzC,0FAA0F;IAC1F,QAAQ,CAAC,EAAE,QAAQ,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IACzC,+FAA+F;IAC/F,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC/C,oGAAoG;IACpG,MAAM,EAAE,WAAW,CAAC;IACpB;;;;OAIG;IACH,KAAK,EAAE,QAAQ,CAAC,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG;IAC5C,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC5B,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC;;;OAGG;IACH,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,aAAa,EAAE,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC5C,cAAc,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACnC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACtC;;;;;OAKG;IACH,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,mFAAmF;IACnF,iBAAiB,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACpC;;;OAGG;IACH,QAAQ,EAAE,QAAQ,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAAC;CAC/C,CAAC;AAaF,eAAO,MAAM,iBAAiB,GAAI,SAAS,kBAAkB,KAAG,iBA8F/D,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"choice-field.js","names":[],"sources":["../../src/core/choice-field.ts"],"sourcesContent":["import { computed, type Readable, watch } from '@vielzeug/ripple';\n\nimport { createDirtyTracker, createField, type FieldHandle, type FieldOptions } from './field-base';\nimport { syncedSignal } from './signals';\n\n// ── Choice change event payload ──────────────────────────────────────────────────────────────\n\nexport type ChoiceChangeDetail = {\n labels: string[];\n originalEvent?: Event;\n values: string[];\n};\n\n// ── Choice field ──────────────────────────────────────────────────────────────────────\n\nexport type ChoiceFieldOptions = FieldOptions & {\n multiple?: Readable<boolean | undefined>;\n /** Marks an empty selection invalid
|
|
1
|
+
{"version":3,"file":"choice-field.js","names":[],"sources":["../../src/core/choice-field.ts"],"sourcesContent":["import { computed, type Readable, watch } from '@vielzeug/ripple';\n\nimport { createDirtyTracker, createField, type FieldHandle, type FieldOptions } from './field-base';\nimport { syncedSignal } from './signals';\n\n// ── Choice change event payload ──────────────────────────────────────────────────────────────\n\nexport type ChoiceChangeDetail = {\n labels: string[];\n originalEvent?: Event;\n values: string[];\n};\n\n// ── Choice field ──────────────────────────────────────────────────────────────────────\n\nexport type ChoiceFieldOptions = FieldOptions & {\n multiple?: Readable<boolean | undefined>;\n /** Marks an empty selection invalid: feeds `validity`/`validationMessage` (see below). */\n required?: Readable<boolean | undefined>;\n /** Message for the empty-selection+required case. Defaults to `'Please make a selection.'`. */\n requiredMessage?: Readable<string | undefined>;\n /** `AbortSignal` from the component lifecycle. All internal subscriptions are disposed on abort. */\n signal: AbortSignal;\n /**\n * Current selection value(s). Accepts a comma-separated string\n * (legacy/single-select form serialisation) or a `string[]` array.\n * The field normalises both formats internally via `parseChoiceValues`.\n */\n value: Readable<string | string[] | undefined>;\n};\n\nexport type ChoiceFieldHandle = FieldHandle & {\n clear: () => void;\n formValue: Readable<string>;\n removeValue: (value: string) => void;\n /**\n * Restores the selection to its native \"default\". See `DirtyTracker` for the two-state\n * rationale.\n */\n reset: () => void;\n selectedValue: Readable<string | undefined>;\n selectedValues: Readable<string[]>;\n selectValue: (value: string) => void;\n setValues: (values: string[]) => void;\n /**\n * Toggles `value` in the selection.\n * - **Multiple mode**: adds if absent, removes if present.\n * - **Single mode**: always selects `value` (acts like `selectValue`: cannot\n * deselect; use `clear()` to reset a single-select field).\n */\n toggleValue: (value: string) => void;\n /** Reactive validation message paired with `validity`. Empty string when valid. */\n validationMessage: Readable<string>;\n /**\n * Reactive `ValidityStateFlags`: `{ valueMissing: true }` while `required` and no option is\n * selected, `null` (valid) otherwise. Pass straight to `useField({ validity: choice.validity })`.\n */\n validity: Readable<ValidityStateFlags | null>;\n};\n\nconst parseChoiceValues = (raw: string | string[] | undefined): string[] => {\n if (!raw) return [];\n\n if (Array.isArray(raw)) return raw.filter(Boolean);\n\n return raw\n .split(',')\n .map((entry) => entry.trim())\n .filter(Boolean);\n};\n\nexport const createChoiceField = (options: ChoiceFieldOptions): ChoiceFieldHandle => {\n const isMultiple = computed(() => Boolean(options.multiple?.value));\n\n const normalizeValues = (values: string[]): string[] => {\n const normalized = isMultiple.value ? values : values.slice(0, 1);\n\n return [...new Set(normalized.filter(Boolean))];\n };\n\n // Kept in sync with `options.value` via the shared helper (see `checkable.ts`/`text-field.ts`\n // for the same pattern) rather than a hand-rolled signal + watch pair.\n const selectedValues = syncedSignal(options.value, options.signal, (raw) => normalizeValues(parseChoiceValues(raw)));\n const formValue = computed(() =>\n isMultiple.value ? selectedValues.value.join(',') : (selectedValues.value[0] ?? ''),\n );\n\n const dirtyTracker = createDirtyTracker();\n\n // The actual state setter, shared by every mutation path. Deliberately *not* where the dirty\n // tracker gets marked: `syncFromProp` (below) calls this directly to stay exempt from it,\n // since mirroring an external prop change is never \"the user changed the selection\".\n const applyValues = (values: string[]): void => {\n selectedValues.value = normalizeValues(values);\n };\n\n const setValues = (values: string[]): void => {\n dirtyTracker.markDirty();\n applyValues(values);\n };\n const clear = (): void => setValues([]);\n const removeValue = (value: string): void => {\n dirtyTracker.markDirty();\n selectedValues.value = selectedValues.value.filter((v) => v !== value);\n };\n\n const selectValue = (value: string): void => {\n if (isMultiple.value) {\n if (!selectedValues.value.includes(value)) setValues([...selectedValues.value, value]);\n\n return;\n }\n\n setValues([value]);\n };\n\n const toggleValue = (value: string): void => {\n if (isMultiple.value) {\n if (selectedValues.value.includes(value)) removeValue(value);\n else selectValue(value);\n } else {\n selectValue(value);\n }\n };\n\n const syncFromProp = (nextValue: string | string[] | undefined): void => {\n applyValues(parseChoiceValues(nextValue));\n };\n\n const field = createField(options);\n\n const validity = computed<ValidityStateFlags | null>(() =>\n options.required?.value && selectedValues.value.length === 0 ? { valueMissing: true } : null,\n );\n const validationMessage = computed(() =>\n validity.value ? options.requiredMessage?.value || 'Please make a selection.' : '',\n );\n\n if (options.multiple) {\n const multipleSub = watch(options.multiple, () => syncFromProp(options.value.value));\n\n options.signal.addEventListener('abort', () => multipleSub.dispose(), { once: true });\n }\n\n const initialValues = selectedValues.value;\n const reset = (): void => {\n applyValues(dirtyTracker.isDirty ? initialValues : parseChoiceValues(options.value.value));\n dirtyTracker.clear();\n field.triggerValidation('change');\n };\n\n return {\n ...field,\n clear,\n formValue,\n removeValue,\n reset,\n selectedValue: computed(() => selectedValues.value[0]),\n selectedValues,\n selectValue,\n setValues,\n toggleValue,\n validationMessage,\n validity,\n };\n};\n"],"mappings":"yKA4DA,IAAM,kBAAqB,GACpB,EAED,MAAM,QAAQ,CAAG,EAAU,EAAI,OAAO,OAAO,EAE1C,EACJ,MAAM,GAAG,CAAC,CACV,IAAK,GAAU,EAAM,KAAK,CAAC,CAAC,CAC5B,OAAO,OAAO,EAPA,CAAC,EAUP,kBAAqB,GAAmD,CACnF,IAAM,EAAa,MAAe,EAAQ,EAAQ,UAAU,KAAM,EAE5D,gBAAmB,GAA+B,CACtD,IAAM,EAAa,EAAW,MAAQ,EAAS,EAAO,MAAM,EAAG,CAAC,EAEhE,MAAO,CAAC,GAAG,IAAI,IAAI,EAAW,OAAO,OAAO,CAAC,CAAC,CAChD,EAIM,EAAiB,EAAa,EAAQ,MAAO,EAAQ,OAAS,GAAQ,gBAAgB,kBAAkB,CAAG,CAAC,CAAC,EAC7G,EAAY,MAChB,EAAW,MAAQ,EAAe,MAAM,KAAK,GAAG,EAAK,EAAe,MAAM,IAAM,EAClF,EAEM,EAAe,EAAmB,EAKlC,YAAe,GAA2B,CAC9C,EAAe,MAAQ,gBAAgB,CAAM,CAC/C,EAEM,UAAa,GAA2B,CAC5C,EAAa,UAAU,EACvB,YAAY,CAAM,CACpB,EACM,UAAoB,UAAU,CAAC,CAAC,EAChC,YAAe,GAAwB,CAC3C,EAAa,UAAU,EACvB,EAAe,MAAQ,EAAe,MAAM,OAAQ,GAAM,IAAM,CAAK,CACvE,EAEM,YAAe,GAAwB,CAC3C,GAAI,EAAW,MAAO,CACf,EAAe,MAAM,SAAS,CAAK,GAAG,UAAU,CAAC,GAAG,EAAe,MAAO,CAAK,CAAC,EAErF,MACF,CAEA,UAAU,CAAC,CAAK,CAAC,CACnB,EAEM,YAAe,GAAwB,CACvC,EAAW,OACT,EAAe,MAAM,SAAS,CAAK,EAAG,YAAY,CAAK,EACtD,YAAY,CAAK,CAI1B,EAEM,aAAgB,GAAmD,CACvE,YAAY,kBAAkB,CAAS,CAAC,CAC1C,EAEM,EAAQ,EAAY,CAAO,EAE3B,EAAW,MACf,EAAQ,UAAU,OAAS,EAAe,MAAM,SAAW,EAAI,CAAE,aAAc,EAAK,EAAI,IAC1F,EACM,EAAoB,MACxB,EAAS,MAAQ,EAAQ,iBAAiB,OAAS,2BAA6B,EAClF,EAEA,GAAI,EAAQ,SAAU,CACpB,IAAM,EAAc,EAAM,EAAQ,aAAgB,aAAa,EAAQ,MAAM,KAAK,CAAC,EAEnF,EAAQ,OAAO,iBAAiB,YAAe,EAAY,QAAQ,EAAG,CAAE,KAAM,EAAK,CAAC,CACtF,CAEA,IAAM,EAAgB,EAAe,MAC/B,UAAoB,CACxB,YAAY,EAAa,QAAU,EAAgB,kBAAkB,EAAQ,MAAM,KAAK,CAAC,EACzF,EAAa,MAAM,EACnB,EAAM,kBAAkB,QAAQ,CAClC,EAEA,MAAO,CACL,GAAG,EACH,MACA,YACA,YACA,MACA,cAAe,MAAe,EAAe,MAAM,EAAE,EACrD,iBACA,YACA,UACA,YACA,oBACA,UACF,CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"composer.cjs","names":[],"sources":["../../src/core/composer.ts"],"sourcesContent":["import type { Readable } from '@vielzeug/ripple';\n\nimport { computed } from '@vielzeug/ripple';\n\n/**\n * Keyboard shortcut that triggers a send:\n * - `'enter'` (default)
|
|
1
|
+
{"version":3,"file":"composer.cjs","names":[],"sources":["../../src/core/composer.ts"],"sourcesContent":["import type { Readable } from '@vielzeug/ripple';\n\nimport { computed } from '@vielzeug/ripple';\n\n/**\n * Keyboard shortcut that triggers a send:\n * - `'enter'` (default): Enter sends, Shift+Enter inserts a newline.\n * - `'mod+enter'`: Enter always inserts a newline; Ctrl/Cmd+Enter sends.\n */\nexport type SendShortcut = 'enter' | 'mod+enter';\n\nexport type ComposerControlOptions = {\n disabled?: Readable<boolean | undefined>;\n /** Blocks further sends (e.g. a send is already in flight) without disabling editing. */\n loading?: Readable<boolean | undefined>;\n /** Called for a send attempt that passed the `canSend` guard. */\n onSend: (event: KeyboardEvent | MouseEvent) => void;\n sendShortcut?: Readable<SendShortcut | undefined>;\n value: Readable<string | undefined>;\n};\n\nexport type ComposerControl = {\n /** Whether the current value is non-blank and the control isn't disabled/loading. */\n canSend: Readable<boolean>;\n /** Wire onto the raw `<textarea>`'s `keydown`: intercepts the resolved send shortcut. */\n handleKeydown: (event: KeyboardEvent) => void;\n /** `aria-keyshortcuts` value describing the resolved shortcut. */\n keyShortcutsHint: Readable<string>;\n /** Attempts a send; no-ops when `canSend` is false. Wire onto the send button's `click`. */\n send: (event: KeyboardEvent | MouseEvent) => void;\n};\n\nconst isBlank = (value: string | undefined): boolean => !value || value.trim() === '';\n\n/**\n * Send-gesture logic for a message/comment composer: decides *when* a send is allowed\n * and *whether* a given keydown counts as one. Owns no DOM, value state, or event dispatch;\n * the component wires `handleKeydown`/`send` and decides what a send actually does.\n *\n * @example\n * ```ts\n * const composer = createComposerControl({\n * onSend: (event) => attemptSend(event),\n * sendShortcut: props['send-shortcut'],\n * value,\n * });\n * // <textarea @keydown=\"${composer.handleKeydown}\" aria-keyshortcuts=\"${composer.keyShortcutsHint}\">\n * // <button ?disabled=\"${() => !composer.canSend.value}\" @click=\"${composer.send}\">\n * ```\n */\nexport const createComposerControl = (options: ComposerControlOptions): ComposerControl => {\n const canSend = computed(() => !isBlank(options.value.value) && !options.disabled?.value && !options.loading?.value);\n\n const send = (event: KeyboardEvent | MouseEvent): void => {\n if (!canSend.value) return;\n\n options.onSend(event);\n };\n\n const handleKeydown = (event: KeyboardEvent): void => {\n // A composing IME candidate selection also fires `Enter`: never treat that as a send.\n if (event.key !== 'Enter' || event.isComposing) return;\n\n const mode = options.sendShortcut?.value ?? 'enter';\n const hasModifier = event.metaKey || event.ctrlKey;\n\n if (mode === 'mod+enter' ? !hasModifier : event.shiftKey) return;\n\n event.preventDefault();\n send(event);\n };\n\n const keyShortcutsHint = computed(() =>\n (options.sendShortcut?.value ?? 'enter') === 'mod+enter' ? 'Control+Enter Meta+Enter' : 'Enter',\n );\n\n return { canSend, handleKeydown, keyShortcutsHint, send };\n};\n"],"mappings":"kCAgCA,IAAM,QAAW,GAAuC,CAAC,GAAS,EAAM,KAAK,IAAM,GAkBtE,sBAAyB,GAAqD,CACzF,IAAM,GAAA,EAAU,EAAA,SAAA,KAAe,CAAC,QAAQ,EAAQ,MAAM,KAAK,GAAK,CAAC,EAAQ,UAAU,OAAS,CAAC,EAAQ,SAAS,KAAK,EAE7G,KAAQ,GAA4C,CACnD,EAAQ,OAEb,EAAQ,OAAO,CAAK,CACtB,EAEM,cAAiB,GAA+B,CAEpD,GAAI,EAAM,MAAQ,SAAW,EAAM,YAAa,OAEhD,IAAM,EAAO,EAAQ,cAAc,OAAS,QACtC,EAAc,EAAM,SAAW,EAAM,SAEvC,IAAS,YAAc,CAAC,EAAc,EAAM,YAEhD,EAAM,eAAe,EACrB,KAAK,CAAK,EACZ,EAMA,MAAO,CAAE,UAAS,cAAe,kBAAA,EAJR,EAAA,SAAA,MACtB,EAAQ,cAAc,OAAS,WAAa,YAAc,2BAA6B,OAGzD,EAAkB,IAAK,CAC1D"}
|
package/dist/core/composer.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { Readable } from '@vielzeug/ripple';
|
|
2
2
|
/**
|
|
3
3
|
* Keyboard shortcut that triggers a send:
|
|
4
|
-
* - `'enter'` (default)
|
|
5
|
-
* - `'mod+enter'
|
|
4
|
+
* - `'enter'` (default): Enter sends, Shift+Enter inserts a newline.
|
|
5
|
+
* - `'mod+enter'`: Enter always inserts a newline; Ctrl/Cmd+Enter sends.
|
|
6
6
|
*/
|
|
7
7
|
export type SendShortcut = 'enter' | 'mod+enter';
|
|
8
8
|
export type ComposerControlOptions = {
|
|
@@ -17,7 +17,7 @@ export type ComposerControlOptions = {
|
|
|
17
17
|
export type ComposerControl = {
|
|
18
18
|
/** Whether the current value is non-blank and the control isn't disabled/loading. */
|
|
19
19
|
canSend: Readable<boolean>;
|
|
20
|
-
/** Wire onto the raw `<textarea>`'s `keydown
|
|
20
|
+
/** Wire onto the raw `<textarea>`'s `keydown`: intercepts the resolved send shortcut. */
|
|
21
21
|
handleKeydown: (event: KeyboardEvent) => void;
|
|
22
22
|
/** `aria-keyshortcuts` value describing the resolved shortcut. */
|
|
23
23
|
keyShortcutsHint: Readable<string>;
|
|
@@ -25,7 +25,7 @@ export type ComposerControl = {
|
|
|
25
25
|
send: (event: KeyboardEvent | MouseEvent) => void;
|
|
26
26
|
};
|
|
27
27
|
/**
|
|
28
|
-
* Send-gesture logic for a message/comment composer
|
|
28
|
+
* Send-gesture logic for a message/comment composer: decides *when* a send is allowed
|
|
29
29
|
* and *whether* a given keydown counts as one. Owns no DOM, value state, or event dispatch;
|
|
30
30
|
* the component wires `handleKeydown`/`send` and decides what a send actually does.
|
|
31
31
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"composer.d.ts","sourceRoot":"","sources":["../../src/core/composer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAIjD;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,WAAW,CAAC;AAEjD,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,CAAC,EAAE,QAAQ,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IACzC,yFAAyF;IACzF,OAAO,CAAC,EAAE,QAAQ,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IACxC,iEAAiE;IACjE,MAAM,EAAE,CAAC,KAAK,EAAE,aAAa,GAAG,UAAU,KAAK,IAAI,CAAC;IACpD,YAAY,CAAC,EAAE,QAAQ,CAAC,YAAY,GAAG,SAAS,CAAC,CAAC;IAClD,KAAK,EAAE,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CACrC,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,qFAAqF;IACrF,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC3B,
|
|
1
|
+
{"version":3,"file":"composer.d.ts","sourceRoot":"","sources":["../../src/core/composer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAIjD;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,WAAW,CAAC;AAEjD,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,CAAC,EAAE,QAAQ,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IACzC,yFAAyF;IACzF,OAAO,CAAC,EAAE,QAAQ,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IACxC,iEAAiE;IACjE,MAAM,EAAE,CAAC,KAAK,EAAE,aAAa,GAAG,UAAU,KAAK,IAAI,CAAC;IACpD,YAAY,CAAC,EAAE,QAAQ,CAAC,YAAY,GAAG,SAAS,CAAC,CAAC;IAClD,KAAK,EAAE,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CACrC,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,qFAAqF;IACrF,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC3B,yFAAyF;IACzF,aAAa,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC9C,kEAAkE;IAClE,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACnC,4FAA4F;IAC5F,IAAI,EAAE,CAAC,KAAK,EAAE,aAAa,GAAG,UAAU,KAAK,IAAI,CAAC;CACnD,CAAC;AAIF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,qBAAqB,GAAI,SAAS,sBAAsB,KAAG,eA2BvE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"composer.js","names":[],"sources":["../../src/core/composer.ts"],"sourcesContent":["import type { Readable } from '@vielzeug/ripple';\n\nimport { computed } from '@vielzeug/ripple';\n\n/**\n * Keyboard shortcut that triggers a send:\n * - `'enter'` (default)
|
|
1
|
+
{"version":3,"file":"composer.js","names":[],"sources":["../../src/core/composer.ts"],"sourcesContent":["import type { Readable } from '@vielzeug/ripple';\n\nimport { computed } from '@vielzeug/ripple';\n\n/**\n * Keyboard shortcut that triggers a send:\n * - `'enter'` (default): Enter sends, Shift+Enter inserts a newline.\n * - `'mod+enter'`: Enter always inserts a newline; Ctrl/Cmd+Enter sends.\n */\nexport type SendShortcut = 'enter' | 'mod+enter';\n\nexport type ComposerControlOptions = {\n disabled?: Readable<boolean | undefined>;\n /** Blocks further sends (e.g. a send is already in flight) without disabling editing. */\n loading?: Readable<boolean | undefined>;\n /** Called for a send attempt that passed the `canSend` guard. */\n onSend: (event: KeyboardEvent | MouseEvent) => void;\n sendShortcut?: Readable<SendShortcut | undefined>;\n value: Readable<string | undefined>;\n};\n\nexport type ComposerControl = {\n /** Whether the current value is non-blank and the control isn't disabled/loading. */\n canSend: Readable<boolean>;\n /** Wire onto the raw `<textarea>`'s `keydown`: intercepts the resolved send shortcut. */\n handleKeydown: (event: KeyboardEvent) => void;\n /** `aria-keyshortcuts` value describing the resolved shortcut. */\n keyShortcutsHint: Readable<string>;\n /** Attempts a send; no-ops when `canSend` is false. Wire onto the send button's `click`. */\n send: (event: KeyboardEvent | MouseEvent) => void;\n};\n\nconst isBlank = (value: string | undefined): boolean => !value || value.trim() === '';\n\n/**\n * Send-gesture logic for a message/comment composer: decides *when* a send is allowed\n * and *whether* a given keydown counts as one. Owns no DOM, value state, or event dispatch;\n * the component wires `handleKeydown`/`send` and decides what a send actually does.\n *\n * @example\n * ```ts\n * const composer = createComposerControl({\n * onSend: (event) => attemptSend(event),\n * sendShortcut: props['send-shortcut'],\n * value,\n * });\n * // <textarea @keydown=\"${composer.handleKeydown}\" aria-keyshortcuts=\"${composer.keyShortcutsHint}\">\n * // <button ?disabled=\"${() => !composer.canSend.value}\" @click=\"${composer.send}\">\n * ```\n */\nexport const createComposerControl = (options: ComposerControlOptions): ComposerControl => {\n const canSend = computed(() => !isBlank(options.value.value) && !options.disabled?.value && !options.loading?.value);\n\n const send = (event: KeyboardEvent | MouseEvent): void => {\n if (!canSend.value) return;\n\n options.onSend(event);\n };\n\n const handleKeydown = (event: KeyboardEvent): void => {\n // A composing IME candidate selection also fires `Enter`: never treat that as a send.\n if (event.key !== 'Enter' || event.isComposing) return;\n\n const mode = options.sendShortcut?.value ?? 'enter';\n const hasModifier = event.metaKey || event.ctrlKey;\n\n if (mode === 'mod+enter' ? !hasModifier : event.shiftKey) return;\n\n event.preventDefault();\n send(event);\n };\n\n const keyShortcutsHint = computed(() =>\n (options.sendShortcut?.value ?? 'enter') === 'mod+enter' ? 'Control+Enter Meta+Enter' : 'Enter',\n );\n\n return { canSend, handleKeydown, keyShortcutsHint, send };\n};\n"],"mappings":"4CAgCA,IAAM,QAAW,GAAuC,CAAC,GAAS,EAAM,KAAK,IAAM,GAkBtE,sBAAyB,GAAqD,CACzF,IAAM,EAAU,MAAe,CAAC,QAAQ,EAAQ,MAAM,KAAK,GAAK,CAAC,EAAQ,UAAU,OAAS,CAAC,EAAQ,SAAS,KAAK,EAE7G,KAAQ,GAA4C,CACnD,EAAQ,OAEb,EAAQ,OAAO,CAAK,CACtB,EAEM,cAAiB,GAA+B,CAEpD,GAAI,EAAM,MAAQ,SAAW,EAAM,YAAa,OAEhD,IAAM,EAAO,EAAQ,cAAc,OAAS,QACtC,EAAc,EAAM,SAAW,EAAM,SAEvC,IAAS,YAAc,CAAC,EAAc,EAAM,YAEhD,EAAM,eAAe,EACrB,KAAK,CAAK,EACZ,EAMA,MAAO,CAAE,UAAS,cAAe,iBAJR,OACtB,EAAQ,cAAc,OAAS,WAAa,YAAc,2BAA6B,OAGzD,EAAkB,IAAK,CAC1D"}
|