@vielzeug/refine 2.1.0 → 2.1.2
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/dist/accordion-item.cjs +1 -1
- package/dist/accordion-item.cjs.map +1 -1
- package/dist/accordion-item.js +1 -1
- package/dist/accordion-item.js.map +1 -1
- package/dist/accordion.cjs +1 -1
- package/dist/accordion.cjs.map +1 -1
- package/dist/accordion.js +1 -1
- package/dist/accordion.js.map +1 -1
- package/dist/alert.cjs.map +1 -1
- package/dist/alert.js.map +1 -1
- package/dist/async.cjs.map +1 -1
- package/dist/async.js.map +1 -1
- package/dist/avatar-group.cjs.map +1 -1
- package/dist/avatar-group.js.map +1 -1
- package/dist/avatar.cjs +6 -6
- package/dist/avatar.cjs.map +1 -1
- package/dist/avatar.js +1 -2
- package/dist/avatar.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/breadcrumb.cjs +3 -3
- package/dist/breadcrumb.cjs.map +1 -1
- package/dist/breadcrumb.js +4 -4
- package/dist/breadcrumb.js.map +1 -1
- package/dist/button-group.cjs +1 -1
- package/dist/button-group.cjs.map +1 -1
- package/dist/button-group.js +0 -1
- package/dist/button-group.js.map +1 -1
- package/dist/button.cjs.map +1 -1
- package/dist/button.js.map +1 -1
- package/dist/calendar.cjs.map +1 -1
- package/dist/calendar.js.map +1 -1
- package/dist/card.cjs +7 -7
- package/dist/card.cjs.map +1 -1
- package/dist/card.js +27 -27
- package/dist/card.js.map +1 -1
- package/dist/carousel.cjs +20 -20
- package/dist/carousel.cjs.map +1 -1
- package/dist/carousel.js +7 -8
- package/dist/carousel.js.map +1 -1
- package/dist/chat-message.cjs +10 -10
- package/dist/chat-message.cjs.map +1 -1
- package/dist/chat-message.js +1 -2
- package/dist/chat-message.js.map +1 -1
- package/dist/checkbox-group.cjs +7 -7
- package/dist/checkbox-group.cjs.map +1 -1
- package/dist/checkbox-group.js +26 -26
- package/dist/checkbox-group.js.map +1 -1
- package/dist/checkbox.cjs +2 -2
- package/dist/checkbox.cjs.map +1 -1
- package/dist/checkbox.js +33 -33
- package/dist/checkbox.js.map +1 -1
- package/dist/chip.cjs +16 -16
- package/dist/chip.cjs.map +1 -1
- package/dist/chip.js +1 -2
- package/dist/chip.js.map +1 -1
- package/dist/combobox.cjs +28 -28
- package/dist/combobox.cjs.map +1 -1
- package/dist/combobox.js +211 -211
- package/dist/combobox.js.map +1 -1
- package/dist/command-palette.cjs +21 -21
- package/dist/command-palette.cjs.map +1 -1
- package/dist/command-palette.js +27 -28
- package/dist/command-palette.js.map +1 -1
- package/dist/content/avatar/avatar.css.cjs +1 -1
- package/dist/content/avatar/avatar.css.js +1 -1
- package/dist/content/avatar/avatar.d.ts.map +1 -1
- package/dist/content/breadcrumb/breadcrumb.d.ts.map +1 -1
- package/dist/content/card/card.css.cjs +1 -1
- package/dist/content/card/card.css.cjs.map +1 -1
- package/dist/content/card/card.css.js +1 -1
- package/dist/content/card/card.css.js.map +1 -1
- package/dist/content/card/card.d.ts.map +1 -1
- package/dist/content/carousel/carousel-slide.cjs.map +1 -1
- package/dist/content/carousel/carousel-slide.js.map +1 -1
- package/dist/content/carousel/carousel.css.cjs +1 -1
- package/dist/content/carousel/carousel.css.cjs.map +1 -1
- package/dist/content/carousel/carousel.css.js +1 -1
- package/dist/content/carousel/carousel.css.js.map +1 -1
- package/dist/content/carousel/carousel.d.ts.map +1 -1
- package/dist/content/carousel/index.d.ts +1 -1
- package/dist/content/carousel/index.d.ts.map +1 -1
- package/dist/content/chat-message/chat-message.css.cjs +1 -1
- package/dist/content/chat-message/chat-message.css.js +1 -1
- package/dist/content/chat-message/chat-message.d.ts.map +1 -1
- package/dist/content/code-window/code-window.css.cjs +1 -1
- package/dist/content/code-window/code-window.css.js +1 -1
- package/dist/content/copy-command/copy-command.css.cjs +1 -1
- package/dist/content/copy-command/copy-command.css.js +1 -1
- package/dist/content/copy-command/copy-command.d.ts.map +1 -1
- package/dist/content/index.d.ts +22 -22
- 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 +1 -1
- 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 +1 -1
- package/dist/content/list/list-item.css.cjs.map +1 -1
- package/dist/content/list/list-item.css.js +1 -1
- package/dist/content/list/list-item.css.js.map +1 -1
- package/dist/content/list/list.d.ts.map +1 -1
- package/dist/content/marquee/marquee.css.cjs +1 -1
- package/dist/content/marquee/marquee.css.js +1 -1
- package/dist/content/pagination/pagination.css.cjs +1 -1
- package/dist/content/pagination/pagination.css.js +1 -1
- package/dist/content/pagination/pagination.d.ts.map +1 -1
- package/dist/content/separator/separator.css.cjs +1 -1
- package/dist/content/separator/separator.css.js +1 -1
- package/dist/content/separator/separator.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/stepper.d.ts.map +1 -1
- package/dist/content/table/table.css.cjs +1 -1
- package/dist/content/table/table.css.js +1 -1
- package/dist/content/text/text.css.cjs +1 -1
- package/dist/content/text/text.css.js +1 -1
- package/dist/copy-command.cjs.map +1 -1
- package/dist/copy-command.js.map +1 -1
- package/dist/core/checkable.cjs +1 -1
- package/dist/core/checkable.cjs.map +1 -1
- package/dist/core/checkable.d.ts.map +1 -1
- package/dist/core/checkable.js +4 -4
- package/dist/core/checkable.js.map +1 -1
- package/dist/core/choice-field.cjs +1 -1
- package/dist/core/choice-field.cjs.map +1 -1
- package/dist/core/choice-field.d.ts.map +1 -1
- package/dist/core/choice-field.js +1 -2
- package/dist/core/choice-field.js.map +1 -1
- package/dist/core/date-picker.cjs +1 -1
- package/dist/core/date-picker.cjs.map +1 -1
- package/dist/core/date-picker.d.ts.map +1 -1
- package/dist/core/date-picker.js +3 -3
- package/dist/core/date-picker.js.map +1 -1
- package/dist/core/index.d.ts +17 -17
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/option-list.cjs +1 -1
- package/dist/core/option-list.cjs.map +1 -1
- package/dist/core/option-list.d.ts.map +1 -1
- package/dist/core/option-list.js +4 -4
- package/dist/core/option-list.js.map +1 -1
- package/dist/core/ref-callback.cjs +1 -1
- package/dist/core/ref-callback.cjs.map +1 -1
- package/dist/core/ref-callback.d.ts.map +1 -1
- package/dist/core/ref-callback.js +1 -1
- package/dist/core/ref-callback.js.map +1 -1
- package/dist/core/signals.cjs +1 -1
- package/dist/core/signals.cjs.map +1 -1
- package/dist/core/signals.d.ts.map +1 -1
- package/dist/core/signals.js +1 -2
- package/dist/core/signals.js.map +1 -1
- package/dist/core/slider.cjs.map +1 -1
- package/dist/core/slider.d.ts.map +1 -1
- package/dist/core/slider.js.map +1 -1
- package/dist/core/spinner.cjs.map +1 -1
- package/dist/core/spinner.d.ts.map +1 -1
- package/dist/core/spinner.js.map +1 -1
- package/dist/core/text-field.cjs +1 -1
- package/dist/core/text-field.cjs.map +1 -1
- package/dist/core/text-field.js +1 -1
- package/dist/core/text-field.js.map +1 -1
- package/dist/custom-elements.json +6036 -6036
- package/dist/datagrid.cjs +114 -114
- package/dist/datagrid.cjs.map +1 -1
- package/dist/datagrid.js +42 -43
- package/dist/datagrid.js.map +1 -1
- package/dist/date-picker.cjs.map +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/accordion.d.ts.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/index.d.ts +6 -6
- package/dist/disclosure/index.d.ts.map +1 -1
- package/dist/disclosure/tab-item/tab-item.css.cjs.map +1 -1
- package/dist/disclosure/tab-item/tab-item.css.js.map +1 -1
- package/dist/disclosure/tab-item/tab-item.d.ts.map +1 -1
- package/dist/disclosure/tabs/tabs.css.cjs +1 -1
- package/dist/disclosure/tabs/tabs.css.cjs.map +1 -1
- package/dist/disclosure/tabs/tabs.css.js +1 -1
- package/dist/disclosure/tabs/tabs.css.js.map +1 -1
- package/dist/disclosure/tabs/tabs.d.ts.map +1 -1
- package/dist/drawer.cjs +5 -5
- package/dist/drawer.cjs.map +1 -1
- package/dist/drawer.js +26 -26
- package/dist/drawer.js.map +1 -1
- package/dist/feedback/alert/alert.css.cjs +1 -1
- package/dist/feedback/alert/alert.css.js +1 -1
- package/dist/feedback/async/async.d.ts +1 -1
- package/dist/feedback/async/async.d.ts.map +1 -1
- package/dist/feedback/badge/badge.css.cjs +1 -1
- package/dist/feedback/badge/badge.css.js +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.map +1 -1
- package/dist/feedback/index.d.ts +12 -12
- package/dist/feedback/index.d.ts.map +1 -1
- package/dist/feedback/progress/progress.d.ts.map +1 -1
- package/dist/feedback/skeleton/skeleton.d.ts.map +1 -1
- package/dist/feedback/toast/index.d.ts +1 -1
- package/dist/feedback/toast/index.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.map +1 -1
- package/dist/file-input.cjs +67 -67
- package/dist/file-input.cjs.map +1 -1
- package/dist/file-input.js +129 -130
- package/dist/file-input.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 +21 -21
- package/dist/input.cjs.map +1 -1
- package/dist/input.js +58 -58
- package/dist/input.js.map +1 -1
- package/dist/inputs/button/button.css.cjs +1 -1
- package/dist/inputs/button/button.css.js +1 -1
- package/dist/inputs/button/button.d.ts.map +1 -1
- package/dist/inputs/button-group/button-group.css.cjs.map +1 -1
- package/dist/inputs/button-group/button-group.css.js.map +1 -1
- package/dist/inputs/button-group/button-group.d.ts +1 -1
- package/dist/inputs/button-group/button-group.d.ts.map +1 -1
- package/dist/inputs/calendar/calendar.css.cjs +1 -1
- package/dist/inputs/calendar/calendar.css.cjs.map +1 -1
- package/dist/inputs/calendar/calendar.css.js +1 -1
- package/dist/inputs/calendar/calendar.css.js.map +1 -1
- package/dist/inputs/calendar/calendar.d.ts.map +1 -1
- package/dist/inputs/checkbox/checkbox.css.cjs +1 -1
- package/dist/inputs/checkbox/checkbox.css.js +1 -1
- package/dist/inputs/checkbox/checkbox.d.ts.map +1 -1
- package/dist/inputs/checkbox-group/checkbox-group.d.ts +1 -1
- package/dist/inputs/checkbox-group/checkbox-group.d.ts.map +1 -1
- package/dist/inputs/combobox/combobox.css.cjs +1 -1
- package/dist/inputs/combobox/combobox.css.js +1 -1
- package/dist/inputs/combobox/combobox.d.ts.map +1 -1
- package/dist/inputs/datagrid/datagrid-column.cjs.map +1 -1
- package/dist/inputs/datagrid/datagrid-column.d.ts.map +1 -1
- package/dist/inputs/datagrid/datagrid-column.js.map +1 -1
- package/dist/inputs/datagrid/datagrid-model.cjs +1 -1
- package/dist/inputs/datagrid/datagrid-model.cjs.map +1 -1
- package/dist/inputs/datagrid/datagrid-model.d.ts.map +1 -1
- package/dist/inputs/datagrid/datagrid-model.js +1 -2
- package/dist/inputs/datagrid/datagrid-model.js.map +1 -1
- package/dist/inputs/datagrid/datagrid.css.cjs +1 -1
- package/dist/inputs/datagrid/datagrid.css.cjs.map +1 -1
- package/dist/inputs/datagrid/datagrid.css.js +1 -1
- package/dist/inputs/datagrid/datagrid.css.js.map +1 -1
- package/dist/inputs/datagrid/datagrid.d.ts +1 -1
- package/dist/inputs/datagrid/datagrid.d.ts.map +1 -1
- package/dist/inputs/date-picker/date-picker.css.cjs +1 -1
- package/dist/inputs/date-picker/date-picker.css.cjs.map +1 -1
- package/dist/inputs/date-picker/date-picker.css.js +1 -1
- package/dist/inputs/date-picker/date-picker.css.js.map +1 -1
- package/dist/inputs/date-picker/date-picker.d.ts.map +1 -1
- package/dist/inputs/file-input/file-input-upload.cjs +1 -1
- package/dist/inputs/file-input/file-input-upload.cjs.map +1 -1
- package/dist/inputs/file-input/file-input-upload.d.ts.map +1 -1
- package/dist/inputs/file-input/file-input-upload.js +2 -3
- package/dist/inputs/file-input/file-input-upload.js.map +1 -1
- package/dist/inputs/file-input/file-input.css.cjs +1 -1
- package/dist/inputs/file-input/file-input.css.js +1 -1
- package/dist/inputs/file-input/file-input.d.ts.map +1 -1
- package/dist/inputs/index.d.ts +28 -28
- package/dist/inputs/index.d.ts.map +1 -1
- package/dist/inputs/input/input.css.cjs +1 -1
- package/dist/inputs/input/input.css.js +1 -1
- package/dist/inputs/input/input.d.ts.map +1 -1
- package/dist/inputs/message-composer/message-composer.css.cjs +1 -1
- package/dist/inputs/message-composer/message-composer.css.js +1 -1
- package/dist/inputs/message-composer/message-composer.d.ts +1 -1
- package/dist/inputs/message-composer/message-composer.d.ts.map +1 -1
- package/dist/inputs/number-input/number-input.d.ts.map +1 -1
- package/dist/inputs/otp-input/otp-input.d.ts.map +1 -1
- package/dist/inputs/radio/radio.css.cjs +1 -1
- package/dist/inputs/radio/radio.css.js +1 -1
- package/dist/inputs/radio/radio.d.ts.map +1 -1
- package/dist/inputs/radio-group/radio-group.d.ts +2 -2
- package/dist/inputs/radio-group/radio-group.d.ts.map +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.js +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.map +1 -1
- package/dist/inputs/shared/field-binding.js.map +1 -1
- package/dist/inputs/shared/templates.cjs.map +1 -1
- package/dist/inputs/shared/templates.d.ts.map +1 -1
- package/dist/inputs/shared/templates.js.map +1 -1
- package/dist/inputs/slider/slider.d.ts.map +1 -1
- package/dist/inputs/switch/switch.css.cjs +1 -1
- package/dist/inputs/switch/switch.css.js +1 -1
- package/dist/inputs/switch/switch.d.ts.map +1 -1
- package/dist/inputs/textarea/textarea.css.cjs +1 -1
- package/dist/inputs/textarea/textarea.css.js +1 -1
- package/dist/inputs/textarea/textarea.d.ts.map +1 -1
- package/dist/inputs/time-picker/time-picker.css.cjs +1 -1
- package/dist/inputs/time-picker/time-picker.css.cjs.map +1 -1
- package/dist/inputs/time-picker/time-picker.css.js +1 -1
- package/dist/inputs/time-picker/time-picker.css.js.map +1 -1
- package/dist/inputs/time-picker/time-picker.d.ts.map +1 -1
- package/dist/layout/box/box.d.ts.map +1 -1
- package/dist/layout/grid/grid.d.ts.map +1 -1
- package/dist/layout/index.d.ts +6 -6
- package/dist/layout/index.d.ts.map +1 -1
- package/dist/layout/navbar/navbar.css.cjs +1 -1
- package/dist/layout/navbar/navbar.css.js +1 -1
- package/dist/layout/navbar/navbar.d.ts.map +1 -1
- package/dist/layout/sidebar/sidebar-group.css.cjs +1 -1
- package/dist/layout/sidebar/sidebar-group.css.cjs.map +1 -1
- package/dist/layout/sidebar/sidebar-group.css.js +1 -1
- package/dist/layout/sidebar/sidebar-group.css.js.map +1 -1
- package/dist/layout/sidebar/sidebar.css.cjs +1 -1
- package/dist/layout/sidebar/sidebar.css.cjs.map +1 -1
- package/dist/layout/sidebar/sidebar.css.js +1 -1
- package/dist/layout/sidebar/sidebar.css.js.map +1 -1
- 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 +2 -2
- package/dist/list.cjs.map +1 -1
- package/dist/list.js +15 -16
- package/dist/list.js.map +1 -1
- package/dist/marquee.cjs +1 -1
- package/dist/marquee.cjs.map +1 -1
- package/dist/marquee.js +1 -1
- package/dist/marquee.js.map +1 -1
- package/dist/menu.cjs +5 -5
- package/dist/menu.cjs.map +1 -1
- package/dist/menu.js +38 -39
- package/dist/menu.js.map +1 -1
- package/dist/message-composer.cjs +16 -16
- package/dist/message-composer.cjs.map +1 -1
- package/dist/message-composer.js +61 -61
- package/dist/message-composer.js.map +1 -1
- package/dist/navbar.cjs +9 -9
- package/dist/navbar.cjs.map +1 -1
- package/dist/navbar.js +1 -2
- package/dist/navbar.js.map +1 -1
- package/dist/navigation-menu.cjs +5 -5
- package/dist/navigation-menu.cjs.map +1 -1
- package/dist/navigation-menu.js +33 -34
- package/dist/navigation-menu.js.map +1 -1
- package/dist/number-input.cjs +24 -24
- package/dist/number-input.cjs.map +1 -1
- package/dist/number-input.js +41 -42
- package/dist/number-input.js.map +1 -1
- package/dist/otp-input.cjs +13 -13
- package/dist/otp-input.cjs.map +1 -1
- package/dist/otp-input.js +32 -33
- 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.map +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.map +1 -1
- package/dist/overlay/dialog/dialog.css.cjs +1 -1
- package/dist/overlay/dialog/dialog.css.js +1 -1
- package/dist/overlay/dialog/dialog.d.ts.map +1 -1
- package/dist/overlay/drawer/drawer.css.cjs +1 -1
- package/dist/overlay/drawer/drawer.css.js +1 -1
- package/dist/overlay/drawer/drawer.d.ts +2 -2
- package/dist/overlay/drawer/drawer.d.ts.map +1 -1
- package/dist/overlay/index.d.ts +6 -6
- package/dist/overlay/index.d.ts.map +1 -1
- package/dist/overlay/menu/menu.css.cjs +1 -1
- package/dist/overlay/menu/menu.css.js +1 -1
- package/dist/overlay/menu/menu.d.ts +2 -2
- package/dist/overlay/menu/menu.d.ts.map +1 -1
- package/dist/overlay/navigation-menu/navigation-menu.d.ts.map +1 -1
- package/dist/overlay/popover/popover.d.ts +1 -1
- package/dist/overlay/popover/popover.d.ts.map +1 -1
- package/dist/overlay/shared/use-dialog.cjs +1 -1
- package/dist/overlay/shared/use-dialog.cjs.map +1 -1
- package/dist/overlay/shared/use-dialog.d.ts.map +1 -1
- package/dist/overlay/shared/use-dialog.js +4 -5
- package/dist/overlay/shared/use-dialog.js.map +1 -1
- package/dist/overlay/shared/use-floating-trigger.cjs +1 -1
- package/dist/overlay/shared/use-floating-trigger.cjs.map +1 -1
- package/dist/overlay/shared/use-floating-trigger.d.ts.map +1 -1
- package/dist/overlay/shared/use-floating-trigger.js +1 -2
- package/dist/overlay/shared/use-floating-trigger.js.map +1 -1
- package/dist/overlay/tooltip/tooltip.d.ts +1 -1
- package/dist/overlay/tooltip/tooltip.d.ts.map +1 -1
- package/dist/pagination.cjs.map +1 -1
- package/dist/pagination.js.map +1 -1
- package/dist/popover.cjs +1 -1
- package/dist/popover.cjs.map +1 -1
- package/dist/popover.js +0 -1
- package/dist/popover.js.map +1 -1
- package/dist/progress.cjs.map +1 -1
- package/dist/progress.js.map +1 -1
- package/dist/radio-group.cjs +5 -5
- package/dist/radio-group.cjs.map +1 -1
- package/dist/radio-group.js +26 -27
- package/dist/radio-group.js.map +1 -1
- package/dist/radio.cjs +2 -2
- package/dist/radio.cjs.map +1 -1
- package/dist/radio.js +41 -41
- package/dist/radio.js.map +1 -1
- package/dist/rating.cjs +4 -4
- package/dist/rating.cjs.map +1 -1
- package/dist/rating.js +36 -36
- package/dist/rating.js.map +1 -1
- package/dist/refine.cjs +686 -686
- package/dist/refine.cjs.map +1 -1
- package/dist/refine.iife.js +686 -686
- package/dist/refine.iife.js.map +1 -1
- package/dist/refine.js +737 -737
- package/dist/refine.js.map +1 -1
- package/dist/select.cjs +42 -42
- package/dist/select.cjs.map +1 -1
- package/dist/select.js +146 -147
- package/dist/select.js.map +1 -1
- package/dist/separator.cjs.map +1 -1
- package/dist/separator.js.map +1 -1
- package/dist/sidebar.cjs +17 -17
- package/dist/sidebar.cjs.map +1 -1
- package/dist/sidebar.js +7 -8
- package/dist/sidebar.js.map +1 -1
- package/dist/skeleton.cjs +3 -3
- package/dist/skeleton.cjs.map +1 -1
- package/dist/skeleton.js +1 -2
- package/dist/skeleton.js.map +1 -1
- package/dist/slider.cjs +12 -12
- package/dist/slider.cjs.map +1 -1
- package/dist/slider.js +54 -55
- package/dist/slider.js.map +1 -1
- package/dist/step.cjs.map +1 -1
- package/dist/step.js.map +1 -1
- package/dist/stepper.cjs +2 -2
- package/dist/stepper.cjs.map +1 -1
- package/dist/stepper.js +8 -7
- package/dist/stepper.js.map +1 -1
- package/dist/styles/index.d.ts +2 -2
- package/dist/styles/index.d.ts.map +1 -1
- package/dist/styles/preflight.css +1 -1
- package/dist/styles/theme.css +15 -30
- package/dist/switch.cjs +3 -3
- package/dist/switch.cjs.map +1 -1
- package/dist/switch.js +28 -28
- package/dist/switch.js.map +1 -1
- package/dist/tab-item.cjs +2 -2
- package/dist/tab-item.cjs.map +1 -1
- package/dist/tab-item.js +21 -21
- package/dist/tab-item.js.map +1 -1
- package/dist/tab-panel.cjs +2 -2
- package/dist/tab-panel.cjs.map +1 -1
- package/dist/tab-panel.js +9 -9
- package/dist/tab-panel.js.map +1 -1
- package/dist/table.cjs +1 -1
- package/dist/table.cjs.map +1 -1
- package/dist/table.js +1 -1
- package/dist/table.js.map +1 -1
- package/dist/tabs.cjs +6 -6
- package/dist/tabs.cjs.map +1 -1
- package/dist/tabs.js +14 -15
- package/dist/tabs.js.map +1 -1
- package/dist/textarea.cjs +11 -11
- package/dist/textarea.cjs.map +1 -1
- package/dist/textarea.js +59 -59
- package/dist/textarea.js.map +1 -1
- package/dist/time-picker.cjs.map +1 -1
- package/dist/time-picker.js.map +1 -1
- package/dist/toast.cjs +16 -16
- package/dist/toast.cjs.map +1 -1
- package/dist/toast.js +20 -21
- package/dist/toast.js.map +1 -1
- package/dist/tooltip.cjs.map +1 -1
- package/dist/tooltip.js.map +1 -1
- package/dist/typing-indicator.cjs +1 -1
- package/dist/typing-indicator.cjs.map +1 -1
- package/dist/typing-indicator.js +1 -1
- package/dist/typing-indicator.js.map +1 -1
- package/package.json +96 -97
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-message.cjs","names":[],"sources":["../src/content/chat-message/chat-message.ts"],"sourcesContent":["import { define, html, onEvent, onMounted, prop, ref, useEmit, useSlots } from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\nimport { watch } from '@vielzeug/ripple/watch';\n\nimport { announce } from '../../core';\nimport { reducedMotionMixin } from '../../styles';\nimport '../icon/icon';\nimport componentStyles from './chat-message.css?inline';\n\nexport type ChatMessageSender = 'assistant' | 'system' | 'user';\nexport type ChatMessageStatus = 'error' | 'sending' | 'sent';\n\nconst SENDER_LABELS: Record<ChatMessageSender, string> = {\n assistant: 'Assistant',\n system: 'System',\n user: 'You',\n};\n\n/** Events emitted by the chat-message component */\nexport type OreChatMessageEvents = {\n /** Fired when the retry action is activated on a `status=\"error\"` message */\n retry: { originalEvent?: Event };\n};\n\n/** Chat message component properties */\nexport type OreChatMessageProps = {\n /** Error detail shown beneath the bubble; only visible when `status=\"error\"` */\n error?: string;\n /** Display name shown above the bubble (falls back to a generic label per `sender`) */\n name?: string;\n /** Who sent the message — controls alignment and bubble styling */\n sender?: ChatMessageSender;\n /** Delivery status for outgoing messages — shows an inline indicator and, for `\"error\"`, a retry action */\n status?: ChatMessageStatus;\n /** Append a blinking cursor after the content, for a message still streaming in */\n streaming?: boolean;\n /** ISO 8601 timestamp; rendered as a localized short time in a semantic `<time>` element */\n timestamp?: string;\n};\n\n/**\n * A single message bubble for chat/conversation UIs — sender-aware alignment, an optional\n * avatar slot, delivery status (sending/sent/error with retry), and a streaming cursor for\n * assistant messages still generating. Content is provided via the default slot, so any\n * markdown-to-HTML rendering stays the consumer's choice.\n *\n * The default slot's leading/trailing whitespace-only text nodes are trimmed in place once\n * per slot assignment (mount, and again on `slotchange`) — pretty-printed HTML's\n * indentation would otherwise render as blank lines, since the bubble preserves line breaks\n * (`white-space: pre-wrap`) for genuine multi-paragraph replies. This mutates those specific\n * text nodes' `textContent` directly; it never touches nodes appended afterward (e.g. by\n * `el.textContent += token` while streaming), only the ones present at assignment time.\n *\n * @element ore-chat-message\n *\n * @attr {string} sender - Who sent the message: 'user' | 'assistant' | 'system' (default 'assistant')\n * @attr {string} name - Display name shown above the bubble\n * @attr {string} timestamp - ISO 8601 timestamp, rendered as a localized short time\n * @attr {string} status - Delivery status: 'sending' | 'sent' | 'error'\n * @attr {string} error - Error detail shown beneath the bubble when status=\"error\"\n * @attr {boolean} streaming - Append a blinking cursor after the content\n *\n * @fires retry - Fired when the retry action is activated. detail: { originalEvent }\n *\n * @slot - Message content\n * @slot avatar - Avatar element (e.g. `<ore-avatar>`)\n * @slot actions - Action buttons shown beneath the message (copy, regenerate, feedback, …)\n *\n * @cssprop --chat-message-bg - Bubble background color (assistant/system)\n * @cssprop --chat-message-color - Bubble text color (assistant/system)\n * @cssprop --chat-message-user-bg - Bubble background color (user)\n * @cssprop --chat-message-user-color - Bubble text color (user)\n * @cssprop --chat-message-radius - Bubble border radius\n * @cssprop --chat-message-max-width - Maximum bubble width\n *\n * @part row - Root row container (avatar + column)\n * @part avatar - Avatar slot container\n * @part column - Column containing name, bubble, meta, and actions\n * @part name - Sender display name\n * @part bubble - Message bubble container\n * @part content - Content container inside the bubble\n * @part cursor - Blinking streaming cursor\n * @part meta - Row of timestamp, status, and error text below the bubble\n * @part timestamp - Timestamp `<time>` element\n * @part status - Status indicator\n * @part error - Error text\n * @part retry - Retry button (status=\"error\" only)\n * @part actions - Actions slot container\n *\n * @example\n * ```html\n * <ore-chat-message sender=\"user\" timestamp=\"2024-01-01T12:00:00Z\" status=\"sent\">\n * What's the weather like today?\n * </ore-chat-message>\n *\n * <ore-chat-message sender=\"assistant\" name=\"Assistant\" streaming>\n * Let me check that for you\n * </ore-chat-message>\n * ```\n */\nexport const CHAT_MESSAGE_TAG = 'ore-chat-message' as const;\ndefine<OreChatMessageProps>(CHAT_MESSAGE_TAG, {\n props: {\n error: prop.string(),\n name: prop.string(),\n sender: prop.oneOf(['user', 'assistant', 'system'] as const, 'assistant'),\n status: prop.string<ChatMessageStatus>(),\n streaming: prop.bool(false),\n timestamp: prop.string(),\n },\n setup(props) {\n const emit = useEmit<OreChatMessageEvents>();\n const slots = useSlots();\n\n const senderLabel = () => SENDER_LABELS[props.sender.value ?? 'assistant'];\n\n const bubbleLabel = computed(() => `Message from ${props.name.value || senderLabel()}`);\n\n const formattedTime = computed(() => {\n const raw = props.timestamp.value;\n\n if (!raw) return '';\n\n const date = new Date(raw);\n\n if (Number.isNaN(date.getTime())) return '';\n\n return new Intl.DateTimeFormat(undefined, { hour: 'numeric', minute: '2-digit' }).format(date);\n });\n\n const hasMeta = computed(\n () => Boolean(formattedTime.value) || Boolean(props.status.value) || Boolean(props.error.value),\n );\n\n // Announce delivery failures — the visible retry button and error text are always present\n // for sighted users, but a failed send is exactly the kind of state change a screen\n // reader user could otherwise miss entirely. Keyed on `error` text too (not just\n // `status`) so a retry that fails again with a *different* reason re-announces even\n // though `status` never left `\"error\"` in between; a second failure with the identical\n // message doesn't re-fire, since the source value hasn't actually changed.\n watch(\n () => (props.status.value === 'error' ? (props.error.value ?? '') : null),\n (errorText) => {\n if (errorText !== null) {\n announce(`Message failed to send${errorText ? `: ${errorText}` : ''}`, { politeness: 'assertive' });\n }\n },\n );\n\n function handleRetry(e: Event): void {\n emit('retry', { originalEvent: e });\n }\n\n // ── Trim author-time indentation whitespace from the default slot ──\n // `.content` uses `white-space: pre-wrap` so genuine multi-paragraph replies keep their\n // line breaks — but that also preserves the leading/trailing newline + indentation from\n // pretty-printed HTML (`<ore-chat-message>\\n Hello\\n</ore-chat-message>`), rendering as\n // visible blank lines around the text. Trim only the outermost edges once per slot\n // assignment; appending tokens to an existing text node for streaming doesn't re-fire\n // `slotchange`, so this never interferes with in-progress streaming updates.\n //\n // A named-slotted sibling (e.g. `<ore-avatar slot=\"avatar\">` between the opening tag and\n // the message text) splits the default slot's light-DOM text into *multiple* text nodes\n // — text nodes can't target a named slot, so each run on either side of the element is\n // assigned separately. The \"real\" content can start on a later node than index 0 (it's\n // still preceded by its own leading indentation), so this walks inward from each end,\n // fully clearing whitespace-only nodes and stopping at the first node with real content\n // on each side — rather than only touching the very first/last assigned node.\n const contentSlotRef = ref<HTMLSlotElement>();\n\n function trimSlotEdgeWhitespace(): void {\n const nodes = contentSlotRef.value?.assignedNodes({ flatten: true });\n\n if (!nodes || nodes.length === 0) return;\n\n for (const node of nodes) {\n if (node.nodeType !== Node.TEXT_NODE) break;\n\n const trimmed = (node.textContent ?? '').replace(/^\\s+/, '');\n\n node.textContent = trimmed;\n\n if (trimmed !== '') break;\n }\n\n for (let i = nodes.length - 1; i >= 0; i--) {\n const node = nodes[i];\n\n if (node.nodeType !== Node.TEXT_NODE) break;\n\n const trimmed = (node.textContent ?? '').replace(/\\s+$/, '');\n\n node.textContent = trimmed;\n\n if (trimmed !== '') break;\n }\n }\n\n onMounted(() => {\n trimSlotEdgeWhitespace();\n\n const slotEl = contentSlotRef.value;\n\n if (slotEl) onEvent(slotEl, 'slotchange', trimSlotEdgeWhitespace);\n });\n\n return html`\n <div class=\"row\" part=\"row\">\n <span class=\"avatar\" part=\"avatar\" ?hidden=\"${() => !slots.has('avatar').value}\">\n <slot name=\"avatar\"></slot>\n </span>\n <div class=\"column\" part=\"column\">\n <span class=\"name\" part=\"name\" ?hidden=\"${() => !props.name.value}\">${props.name}</span>\n <div class=\"bubble\" part=\"bubble\" role=\"article\" aria-label=\"${bubbleLabel}\">\n <div class=\"content\" part=\"content\">\n <slot class=\"content-slot\" ref=\"${contentSlotRef}\"></slot>\n <span class=\"cursor\" part=\"cursor\" aria-hidden=\"true\" ?hidden=\"${() => !props.streaming.value}\"></span>\n </div>\n </div>\n <div class=\"meta\" part=\"meta\" ?hidden=\"${() => !hasMeta.value}\">\n <time\n class=\"timestamp\"\n part=\"timestamp\"\n datetime=\"${props.timestamp}\"\n ?hidden=\"${() => !formattedTime.value}\">\n ${formattedTime}\n </time>\n <span class=\"status\" part=\"status\" data-status=\"${props.status}\" ?hidden=\"${() => !props.status.value}\">\n ${() => {\n switch (props.status.value) {\n case 'error':\n return html`\n <ore-icon name=\"alert-circle\" size=\"12\" stroke-width=\"2.5\" aria-hidden=\"true\"></ore-icon>\n `;\n case 'sending':\n return html`\n <span class=\"spinner\" aria-hidden=\"true\"></span>\n `;\n case 'sent':\n return html`\n <ore-icon name=\"check\" size=\"12\" stroke-width=\"2.5\" aria-hidden=\"true\"></ore-icon>\n `;\n default:\n return '';\n }\n }}\n </span>\n <span class=\"error-text\" part=\"error\" role=\"alert\" ?hidden=\"${() => !props.error.value}\">\n ${props.error}\n </span>\n <button\n class=\"retry\"\n part=\"retry\"\n type=\"button\"\n ?hidden=\"${() => props.status.value !== 'error'}\"\n @click=\"${handleRetry}\">\n Retry\n </button>\n </div>\n <div class=\"actions\" part=\"actions\" ?hidden=\"${() => !slots.has('actions').value}\">\n <slot name=\"actions\"></slot>\n </div>\n </div>\n </div>\n `;\n },\n styles: [reducedMotionMixin, componentStyles],\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"chat-message.cjs","names":[],"sources":["../src/content/chat-message/chat-message.ts"],"sourcesContent":["import { define, html, onEvent, onMounted, prop, ref, useEmit, useSlots } from '@vielzeug/ore';\nimport { computed, watch } from '@vielzeug/ripple';\n\nimport { announce } from '../../core';\nimport { reducedMotionMixin } from '../../styles';\nimport '../icon/icon';\nimport componentStyles from './chat-message.css?inline';\n\nexport type ChatMessageSender = 'assistant' | 'system' | 'user';\nexport type ChatMessageStatus = 'error' | 'sending' | 'sent';\n\nconst SENDER_LABELS: Record<ChatMessageSender, string> = {\n assistant: 'Assistant',\n system: 'System',\n user: 'You',\n};\n\n/** Events emitted by the chat-message component */\nexport type OreChatMessageEvents = {\n /** Fired when the retry action is activated on a `status=\"error\"` message */\n retry: { originalEvent?: Event };\n};\n\n/** Chat message component properties */\nexport type OreChatMessageProps = {\n /** Error detail shown beneath the bubble; only visible when `status=\"error\"` */\n error?: string;\n /** Display name shown above the bubble (falls back to a generic label per `sender`) */\n name?: string;\n /** Who sent the message — controls alignment and bubble styling */\n sender?: ChatMessageSender;\n /** Delivery status for outgoing messages — shows an inline indicator and, for `\"error\"`, a retry action */\n status?: ChatMessageStatus;\n /** Append a blinking cursor after the content, for a message still streaming in */\n streaming?: boolean;\n /** ISO 8601 timestamp; rendered as a localized short time in a semantic `<time>` element */\n timestamp?: string;\n};\n\n/**\n * A single message bubble for chat/conversation UIs — sender-aware alignment, an optional\n * avatar slot, delivery status (sending/sent/error with retry), and a streaming cursor for\n * assistant messages still generating. Content is provided via the default slot, so any\n * markdown-to-HTML rendering stays the consumer's choice.\n *\n * The default slot's leading/trailing whitespace-only text nodes are trimmed in place once\n * per slot assignment (mount, and again on `slotchange`) — pretty-printed HTML's\n * indentation would otherwise render as blank lines, since the bubble preserves line breaks\n * (`white-space: pre-wrap`) for genuine multi-paragraph replies. This mutates those specific\n * text nodes' `textContent` directly; it never touches nodes appended afterward (e.g. by\n * `el.textContent += token` while streaming), only the ones present at assignment time.\n *\n * @element ore-chat-message\n *\n * @attr {string} sender - Who sent the message: 'user' | 'assistant' | 'system' (default 'assistant')\n * @attr {string} name - Display name shown above the bubble\n * @attr {string} timestamp - ISO 8601 timestamp, rendered as a localized short time\n * @attr {string} status - Delivery status: 'sending' | 'sent' | 'error'\n * @attr {string} error - Error detail shown beneath the bubble when status=\"error\"\n * @attr {boolean} streaming - Append a blinking cursor after the content\n *\n * @fires retry - Fired when the retry action is activated. detail: { originalEvent }\n *\n * @slot - Message content\n * @slot avatar - Avatar element (e.g. `<ore-avatar>`)\n * @slot actions - Action buttons shown beneath the message (copy, regenerate, feedback, …)\n *\n * @cssprop --chat-message-bg - Bubble background color (assistant/system)\n * @cssprop --chat-message-color - Bubble text color (assistant/system)\n * @cssprop --chat-message-user-bg - Bubble background color (user)\n * @cssprop --chat-message-user-color - Bubble text color (user)\n * @cssprop --chat-message-radius - Bubble border radius\n * @cssprop --chat-message-max-width - Maximum bubble width\n *\n * @part row - Root row container (avatar + column)\n * @part avatar - Avatar slot container\n * @part column - Column containing name, bubble, meta, and actions\n * @part name - Sender display name\n * @part bubble - Message bubble container\n * @part content - Content container inside the bubble\n * @part cursor - Blinking streaming cursor\n * @part meta - Row of timestamp, status, and error text below the bubble\n * @part timestamp - Timestamp `<time>` element\n * @part status - Status indicator\n * @part error - Error text\n * @part retry - Retry button (status=\"error\" only)\n * @part actions - Actions slot container\n *\n * @example\n * ```html\n * <ore-chat-message sender=\"user\" timestamp=\"2024-01-01T12:00:00Z\" status=\"sent\">\n * What's the weather like today?\n * </ore-chat-message>\n *\n * <ore-chat-message sender=\"assistant\" name=\"Assistant\" streaming>\n * Let me check that for you\n * </ore-chat-message>\n * ```\n */\nexport const CHAT_MESSAGE_TAG = 'ore-chat-message' as const;\ndefine<OreChatMessageProps>(CHAT_MESSAGE_TAG, {\n props: {\n error: prop.string(),\n name: prop.string(),\n sender: prop.oneOf(['user', 'assistant', 'system'] as const, 'assistant'),\n status: prop.string<ChatMessageStatus>(),\n streaming: prop.bool(false),\n timestamp: prop.string(),\n },\n setup(props) {\n const emit = useEmit<OreChatMessageEvents>();\n const slots = useSlots();\n\n const senderLabel = () => SENDER_LABELS[props.sender.value ?? 'assistant'];\n\n const bubbleLabel = computed(() => `Message from ${props.name.value || senderLabel()}`);\n\n const formattedTime = computed(() => {\n const raw = props.timestamp.value;\n\n if (!raw) return '';\n\n const date = new Date(raw);\n\n if (Number.isNaN(date.getTime())) return '';\n\n return new Intl.DateTimeFormat(undefined, { hour: 'numeric', minute: '2-digit' }).format(date);\n });\n\n const hasMeta = computed(\n () => Boolean(formattedTime.value) || Boolean(props.status.value) || Boolean(props.error.value),\n );\n\n // Announce delivery failures — the visible retry button and error text are always present\n // for sighted users, but a failed send is exactly the kind of state change a screen\n // reader user could otherwise miss entirely. Keyed on `error` text too (not just\n // `status`) so a retry that fails again with a *different* reason re-announces even\n // though `status` never left `\"error\"` in between; a second failure with the identical\n // message doesn't re-fire, since the source value hasn't actually changed.\n watch(\n () => (props.status.value === 'error' ? (props.error.value ?? '') : null),\n (errorText) => {\n if (errorText !== null) {\n announce(`Message failed to send${errorText ? `: ${errorText}` : ''}`, { politeness: 'assertive' });\n }\n },\n );\n\n function handleRetry(e: Event): void {\n emit('retry', { originalEvent: e });\n }\n\n // ── Trim author-time indentation whitespace from the default slot ──\n // `.content` uses `white-space: pre-wrap` so genuine multi-paragraph replies keep their\n // line breaks — but that also preserves the leading/trailing newline + indentation from\n // pretty-printed HTML (`<ore-chat-message>\\n Hello\\n</ore-chat-message>`), rendering as\n // visible blank lines around the text. Trim only the outermost edges once per slot\n // assignment; appending tokens to an existing text node for streaming doesn't re-fire\n // `slotchange`, so this never interferes with in-progress streaming updates.\n //\n // A named-slotted sibling (e.g. `<ore-avatar slot=\"avatar\">` between the opening tag and\n // the message text) splits the default slot's light-DOM text into *multiple* text nodes\n // — text nodes can't target a named slot, so each run on either side of the element is\n // assigned separately. The \"real\" content can start on a later node than index 0 (it's\n // still preceded by its own leading indentation), so this walks inward from each end,\n // fully clearing whitespace-only nodes and stopping at the first node with real content\n // on each side — rather than only touching the very first/last assigned node.\n const contentSlotRef = ref<HTMLSlotElement>();\n\n function trimSlotEdgeWhitespace(): void {\n const nodes = contentSlotRef.value?.assignedNodes({ flatten: true });\n\n if (!nodes || nodes.length === 0) return;\n\n for (const node of nodes) {\n if (node.nodeType !== Node.TEXT_NODE) break;\n\n const trimmed = (node.textContent ?? '').replace(/^\\s+/, '');\n\n node.textContent = trimmed;\n\n if (trimmed !== '') break;\n }\n\n for (let i = nodes.length - 1; i >= 0; i--) {\n const node = nodes[i];\n\n if (node.nodeType !== Node.TEXT_NODE) break;\n\n const trimmed = (node.textContent ?? '').replace(/\\s+$/, '');\n\n node.textContent = trimmed;\n\n if (trimmed !== '') break;\n }\n }\n\n onMounted(() => {\n trimSlotEdgeWhitespace();\n\n const slotEl = contentSlotRef.value;\n\n if (slotEl) onEvent(slotEl, 'slotchange', trimSlotEdgeWhitespace);\n });\n\n return html`\n <div class=\"row\" part=\"row\">\n <span class=\"avatar\" part=\"avatar\" ?hidden=\"${() => !slots.has('avatar').value}\">\n <slot name=\"avatar\"></slot>\n </span>\n <div class=\"column\" part=\"column\">\n <span class=\"name\" part=\"name\" ?hidden=\"${() => !props.name.value}\">${props.name}</span>\n <div class=\"bubble\" part=\"bubble\" role=\"article\" aria-label=\"${bubbleLabel}\">\n <div class=\"content\" part=\"content\">\n <slot class=\"content-slot\" ref=\"${contentSlotRef}\"></slot>\n <span class=\"cursor\" part=\"cursor\" aria-hidden=\"true\" ?hidden=\"${() => !props.streaming.value}\"></span>\n </div>\n </div>\n <div class=\"meta\" part=\"meta\" ?hidden=\"${() => !hasMeta.value}\">\n <time\n class=\"timestamp\"\n part=\"timestamp\"\n datetime=\"${props.timestamp}\"\n ?hidden=\"${() => !formattedTime.value}\">\n ${formattedTime}\n </time>\n <span class=\"status\" part=\"status\" data-status=\"${props.status}\" ?hidden=\"${() => !props.status.value}\">\n ${() => {\n switch (props.status.value) {\n case 'error':\n return html`\n <ore-icon name=\"alert-circle\" size=\"12\" stroke-width=\"2.5\" aria-hidden=\"true\"></ore-icon>\n `;\n case 'sending':\n return html`\n <span class=\"spinner\" aria-hidden=\"true\"></span>\n `;\n case 'sent':\n return html`\n <ore-icon name=\"check\" size=\"12\" stroke-width=\"2.5\" aria-hidden=\"true\"></ore-icon>\n `;\n default:\n return '';\n }\n }}\n </span>\n <span class=\"error-text\" part=\"error\" role=\"alert\" ?hidden=\"${() => !props.error.value}\">\n ${props.error}\n </span>\n <button\n class=\"retry\"\n part=\"retry\"\n type=\"button\"\n ?hidden=\"${() => props.status.value !== 'error'}\"\n @click=\"${handleRetry}\">\n Retry\n </button>\n </div>\n <div class=\"actions\" part=\"actions\" ?hidden=\"${() => !slots.has('actions').value}\">\n <slot name=\"actions\"></slot>\n </div>\n </div>\n </div>\n `;\n },\n styles: [reducedMotionMixin, componentStyles],\n});\n"],"mappings":"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"}
|
package/dist/chat-message.js
CHANGED
|
@@ -2,8 +2,7 @@ import { reducedMotionMixin as e } from "./styles/mixins/accessibility.css.js";
|
|
|
2
2
|
import { announce as t } from "./core/announcer.js";
|
|
3
3
|
import n from "./content/chat-message/chat-message.css.js";
|
|
4
4
|
import { define as r, html as i, onEvent as a, onMounted as o, prop as s, ref as c, useEmit as l, useSlots as u } from "@vielzeug/ore";
|
|
5
|
-
import { computed as d } from "@vielzeug/ripple";
|
|
6
|
-
import { watch as f } from "@vielzeug/ripple/watch";
|
|
5
|
+
import { computed as d, watch as f } from "@vielzeug/ripple";
|
|
7
6
|
//#region src/content/chat-message/chat-message.ts
|
|
8
7
|
var p = {
|
|
9
8
|
assistant: "Assistant",
|
package/dist/chat-message.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-message.js","names":[],"sources":["../src/content/chat-message/chat-message.ts"],"sourcesContent":["import { define, html, onEvent, onMounted, prop, ref, useEmit, useSlots } from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\nimport { watch } from '@vielzeug/ripple/watch';\n\nimport { announce } from '../../core';\nimport { reducedMotionMixin } from '../../styles';\nimport '../icon/icon';\nimport componentStyles from './chat-message.css?inline';\n\nexport type ChatMessageSender = 'assistant' | 'system' | 'user';\nexport type ChatMessageStatus = 'error' | 'sending' | 'sent';\n\nconst SENDER_LABELS: Record<ChatMessageSender, string> = {\n assistant: 'Assistant',\n system: 'System',\n user: 'You',\n};\n\n/** Events emitted by the chat-message component */\nexport type OreChatMessageEvents = {\n /** Fired when the retry action is activated on a `status=\"error\"` message */\n retry: { originalEvent?: Event };\n};\n\n/** Chat message component properties */\nexport type OreChatMessageProps = {\n /** Error detail shown beneath the bubble; only visible when `status=\"error\"` */\n error?: string;\n /** Display name shown above the bubble (falls back to a generic label per `sender`) */\n name?: string;\n /** Who sent the message — controls alignment and bubble styling */\n sender?: ChatMessageSender;\n /** Delivery status for outgoing messages — shows an inline indicator and, for `\"error\"`, a retry action */\n status?: ChatMessageStatus;\n /** Append a blinking cursor after the content, for a message still streaming in */\n streaming?: boolean;\n /** ISO 8601 timestamp; rendered as a localized short time in a semantic `<time>` element */\n timestamp?: string;\n};\n\n/**\n * A single message bubble for chat/conversation UIs — sender-aware alignment, an optional\n * avatar slot, delivery status (sending/sent/error with retry), and a streaming cursor for\n * assistant messages still generating. Content is provided via the default slot, so any\n * markdown-to-HTML rendering stays the consumer's choice.\n *\n * The default slot's leading/trailing whitespace-only text nodes are trimmed in place once\n * per slot assignment (mount, and again on `slotchange`) — pretty-printed HTML's\n * indentation would otherwise render as blank lines, since the bubble preserves line breaks\n * (`white-space: pre-wrap`) for genuine multi-paragraph replies. This mutates those specific\n * text nodes' `textContent` directly; it never touches nodes appended afterward (e.g. by\n * `el.textContent += token` while streaming), only the ones present at assignment time.\n *\n * @element ore-chat-message\n *\n * @attr {string} sender - Who sent the message: 'user' | 'assistant' | 'system' (default 'assistant')\n * @attr {string} name - Display name shown above the bubble\n * @attr {string} timestamp - ISO 8601 timestamp, rendered as a localized short time\n * @attr {string} status - Delivery status: 'sending' | 'sent' | 'error'\n * @attr {string} error - Error detail shown beneath the bubble when status=\"error\"\n * @attr {boolean} streaming - Append a blinking cursor after the content\n *\n * @fires retry - Fired when the retry action is activated. detail: { originalEvent }\n *\n * @slot - Message content\n * @slot avatar - Avatar element (e.g. `<ore-avatar>`)\n * @slot actions - Action buttons shown beneath the message (copy, regenerate, feedback, …)\n *\n * @cssprop --chat-message-bg - Bubble background color (assistant/system)\n * @cssprop --chat-message-color - Bubble text color (assistant/system)\n * @cssprop --chat-message-user-bg - Bubble background color (user)\n * @cssprop --chat-message-user-color - Bubble text color (user)\n * @cssprop --chat-message-radius - Bubble border radius\n * @cssprop --chat-message-max-width - Maximum bubble width\n *\n * @part row - Root row container (avatar + column)\n * @part avatar - Avatar slot container\n * @part column - Column containing name, bubble, meta, and actions\n * @part name - Sender display name\n * @part bubble - Message bubble container\n * @part content - Content container inside the bubble\n * @part cursor - Blinking streaming cursor\n * @part meta - Row of timestamp, status, and error text below the bubble\n * @part timestamp - Timestamp `<time>` element\n * @part status - Status indicator\n * @part error - Error text\n * @part retry - Retry button (status=\"error\" only)\n * @part actions - Actions slot container\n *\n * @example\n * ```html\n * <ore-chat-message sender=\"user\" timestamp=\"2024-01-01T12:00:00Z\" status=\"sent\">\n * What's the weather like today?\n * </ore-chat-message>\n *\n * <ore-chat-message sender=\"assistant\" name=\"Assistant\" streaming>\n * Let me check that for you\n * </ore-chat-message>\n * ```\n */\nexport const CHAT_MESSAGE_TAG = 'ore-chat-message' as const;\ndefine<OreChatMessageProps>(CHAT_MESSAGE_TAG, {\n props: {\n error: prop.string(),\n name: prop.string(),\n sender: prop.oneOf(['user', 'assistant', 'system'] as const, 'assistant'),\n status: prop.string<ChatMessageStatus>(),\n streaming: prop.bool(false),\n timestamp: prop.string(),\n },\n setup(props) {\n const emit = useEmit<OreChatMessageEvents>();\n const slots = useSlots();\n\n const senderLabel = () => SENDER_LABELS[props.sender.value ?? 'assistant'];\n\n const bubbleLabel = computed(() => `Message from ${props.name.value || senderLabel()}`);\n\n const formattedTime = computed(() => {\n const raw = props.timestamp.value;\n\n if (!raw) return '';\n\n const date = new Date(raw);\n\n if (Number.isNaN(date.getTime())) return '';\n\n return new Intl.DateTimeFormat(undefined, { hour: 'numeric', minute: '2-digit' }).format(date);\n });\n\n const hasMeta = computed(\n () => Boolean(formattedTime.value) || Boolean(props.status.value) || Boolean(props.error.value),\n );\n\n // Announce delivery failures — the visible retry button and error text are always present\n // for sighted users, but a failed send is exactly the kind of state change a screen\n // reader user could otherwise miss entirely. Keyed on `error` text too (not just\n // `status`) so a retry that fails again with a *different* reason re-announces even\n // though `status` never left `\"error\"` in between; a second failure with the identical\n // message doesn't re-fire, since the source value hasn't actually changed.\n watch(\n () => (props.status.value === 'error' ? (props.error.value ?? '') : null),\n (errorText) => {\n if (errorText !== null) {\n announce(`Message failed to send${errorText ? `: ${errorText}` : ''}`, { politeness: 'assertive' });\n }\n },\n );\n\n function handleRetry(e: Event): void {\n emit('retry', { originalEvent: e });\n }\n\n // ── Trim author-time indentation whitespace from the default slot ──\n // `.content` uses `white-space: pre-wrap` so genuine multi-paragraph replies keep their\n // line breaks — but that also preserves the leading/trailing newline + indentation from\n // pretty-printed HTML (`<ore-chat-message>\\n Hello\\n</ore-chat-message>`), rendering as\n // visible blank lines around the text. Trim only the outermost edges once per slot\n // assignment; appending tokens to an existing text node for streaming doesn't re-fire\n // `slotchange`, so this never interferes with in-progress streaming updates.\n //\n // A named-slotted sibling (e.g. `<ore-avatar slot=\"avatar\">` between the opening tag and\n // the message text) splits the default slot's light-DOM text into *multiple* text nodes\n // — text nodes can't target a named slot, so each run on either side of the element is\n // assigned separately. The \"real\" content can start on a later node than index 0 (it's\n // still preceded by its own leading indentation), so this walks inward from each end,\n // fully clearing whitespace-only nodes and stopping at the first node with real content\n // on each side — rather than only touching the very first/last assigned node.\n const contentSlotRef = ref<HTMLSlotElement>();\n\n function trimSlotEdgeWhitespace(): void {\n const nodes = contentSlotRef.value?.assignedNodes({ flatten: true });\n\n if (!nodes || nodes.length === 0) return;\n\n for (const node of nodes) {\n if (node.nodeType !== Node.TEXT_NODE) break;\n\n const trimmed = (node.textContent ?? '').replace(/^\\s+/, '');\n\n node.textContent = trimmed;\n\n if (trimmed !== '') break;\n }\n\n for (let i = nodes.length - 1; i >= 0; i--) {\n const node = nodes[i];\n\n if (node.nodeType !== Node.TEXT_NODE) break;\n\n const trimmed = (node.textContent ?? '').replace(/\\s+$/, '');\n\n node.textContent = trimmed;\n\n if (trimmed !== '') break;\n }\n }\n\n onMounted(() => {\n trimSlotEdgeWhitespace();\n\n const slotEl = contentSlotRef.value;\n\n if (slotEl) onEvent(slotEl, 'slotchange', trimSlotEdgeWhitespace);\n });\n\n return html`\n <div class=\"row\" part=\"row\">\n <span class=\"avatar\" part=\"avatar\" ?hidden=\"${() => !slots.has('avatar').value}\">\n <slot name=\"avatar\"></slot>\n </span>\n <div class=\"column\" part=\"column\">\n <span class=\"name\" part=\"name\" ?hidden=\"${() => !props.name.value}\">${props.name}</span>\n <div class=\"bubble\" part=\"bubble\" role=\"article\" aria-label=\"${bubbleLabel}\">\n <div class=\"content\" part=\"content\">\n <slot class=\"content-slot\" ref=\"${contentSlotRef}\"></slot>\n <span class=\"cursor\" part=\"cursor\" aria-hidden=\"true\" ?hidden=\"${() => !props.streaming.value}\"></span>\n </div>\n </div>\n <div class=\"meta\" part=\"meta\" ?hidden=\"${() => !hasMeta.value}\">\n <time\n class=\"timestamp\"\n part=\"timestamp\"\n datetime=\"${props.timestamp}\"\n ?hidden=\"${() => !formattedTime.value}\">\n ${formattedTime}\n </time>\n <span class=\"status\" part=\"status\" data-status=\"${props.status}\" ?hidden=\"${() => !props.status.value}\">\n ${() => {\n switch (props.status.value) {\n case 'error':\n return html`\n <ore-icon name=\"alert-circle\" size=\"12\" stroke-width=\"2.5\" aria-hidden=\"true\"></ore-icon>\n `;\n case 'sending':\n return html`\n <span class=\"spinner\" aria-hidden=\"true\"></span>\n `;\n case 'sent':\n return html`\n <ore-icon name=\"check\" size=\"12\" stroke-width=\"2.5\" aria-hidden=\"true\"></ore-icon>\n `;\n default:\n return '';\n }\n }}\n </span>\n <span class=\"error-text\" part=\"error\" role=\"alert\" ?hidden=\"${() => !props.error.value}\">\n ${props.error}\n </span>\n <button\n class=\"retry\"\n part=\"retry\"\n type=\"button\"\n ?hidden=\"${() => props.status.value !== 'error'}\"\n @click=\"${handleRetry}\">\n Retry\n </button>\n </div>\n <div class=\"actions\" part=\"actions\" ?hidden=\"${() => !slots.has('actions').value}\">\n <slot name=\"actions\"></slot>\n </div>\n </div>\n </div>\n `;\n },\n styles: [reducedMotionMixin, componentStyles],\n});\n"],"mappings":";;;;;;;AAYA,IAAM,IAAmD;CACvD,WAAW;CACX,QAAQ;CACR,MAAM;AACR,GAoFa,IAAmB;AAChC,EAA4B,GAAkB;CAC5C,OAAO;EACL,OAAO,EAAK,OAAO;EACnB,MAAM,EAAK,OAAO;EAClB,QAAQ,EAAK,MAAM;GAAC;GAAQ;GAAa;EAAQ,GAAY,WAAW;EACxE,QAAQ,EAAK,OAA0B;EACvC,WAAW,EAAK,KAAK,EAAK;EAC1B,WAAW,EAAK,OAAO;CACzB;CACA,MAAM,GAAO;EACX,IAAM,IAAO,EAA8B,GACrC,IAAQ,EAAS,GAEjB,UAAoB,EAAc,EAAM,OAAO,SAAS,cAExD,IAAc,QAAe,gBAAgB,EAAM,KAAK,SAAS,EAAY,GAAG,GAEhF,IAAgB,QAAe;GACnC,IAAM,IAAM,EAAM,UAAU;GAE5B,IAAI,CAAC,GAAK,OAAO;GAEjB,IAAM,IAAO,IAAI,KAAK,CAAG;GAIzB,OAFI,OAAO,MAAM,EAAK,QAAQ,CAAC,IAAU,KAElC,IAAI,KAAK,eAAe,KAAA,GAAW;IAAE,MAAM;IAAW,QAAQ;GAAU,CAAC,CAAC,CAAC,OAAO,CAAI;EAC/F,CAAC,GAEK,IAAU,QACR,EAAQ,EAAc,SAAU,EAAQ,EAAM,OAAO,SAAU,EAAQ,EAAM,MAAM,KAC3F;EAQA,QACS,EAAM,OAAO,UAAU,UAAW,EAAM,MAAM,SAAS,KAAM,OACnE,MAAc;GACb,AAAI,MAAc,QAChB,EAAS,yBAAyB,IAAY,KAAK,MAAc,MAAM,EAAE,YAAY,YAAY,CAAC;EAEtG,CACF;EAEA,SAAS,EAAY,GAAgB;GACnC,EAAK,SAAS,EAAE,eAAe,EAAE,CAAC;EACpC;EAiBA,IAAM,IAAiB,EAAqB;EAE5C,SAAS,IAA+B;GACtC,IAAM,IAAQ,EAAe,OAAO,cAAc,EAAE,SAAS,GAAK,CAAC;GAE/D,OAAC,KAAS,EAAM,WAAW,IAE/B;SAAK,IAAM,KAAQ,GAAO;KACxB,IAAI,EAAK,aAAa,KAAK,WAAW;KAEtC,IAAM,KAAW,EAAK,eAAe,GAAA,CAAI,QAAQ,QAAQ,EAAE;KAI3D,IAFA,EAAK,cAAc,GAEf,MAAY,IAAI;IACtB;IAEA,KAAK,IAAI,IAAI,EAAM,SAAS,GAAG,KAAK,GAAG,KAAK;KAC1C,IAAM,IAAO,EAAM;KAEnB,IAAI,EAAK,aAAa,KAAK,WAAW;KAEtC,IAAM,KAAW,EAAK,eAAe,GAAA,CAAI,QAAQ,QAAQ,EAAE;KAI3D,IAFA,EAAK,cAAc,GAEf,MAAY,IAAI;IACtB;GAZA;EAaF;EAUA,OARA,QAAgB;GACd,EAAuB;GAEvB,IAAM,IAAS,EAAe;GAE9B,AAAI,KAAQ,EAAQ,GAAQ,cAAc,CAAsB;EAClE,CAAC,GAEM,CAAI;;4DAE6C,CAAC,EAAM,IAAI,QAAQ,CAAC,CAAC,MAAM;;;;0DAI7B,CAAC,EAAM,KAAK,MAAM,IAAI,EAAM,KAAK;yEAClB,EAAY;;gDAErC,EAAe;qFACsB,CAAC,EAAM,UAAU,MAAM;;;yDAGnD,CAAC,EAAQ,MAAM;;;;0BAI9C,EAAM,UAAU;+BACX,CAAC,EAAc,MAAM;gBACpC,EAAc;;8DAEgC,EAAM,OAAO,mBAAmB,CAAC,EAAM,OAAO,MAAM;sBAC5F;GACN,QAAQ,EAAM,OAAO,OAArB;IACE,KAAK,SACH,OAAO,CAAI;;;IAGb,KAAK,WACH,OAAO,CAAI;;;IAGb,KAAK,QACH,OAAO,CAAI;;;IAGb,SACE,OAAO;GACX;EACF,EAAE;;gFAEgE,CAAC,EAAM,MAAM,MAAM;gBACnF,EAAM,MAAM;;;;;;+BAMG,EAAM,OAAO,UAAU,QAAQ;wBACtC,EAAY;;;;+DAI2B,CAAC,EAAM,IAAI,SAAS,CAAC,CAAC,MAAM;;;;;;CAMzF;CACA,QAAQ,CAAC,GAAoB,CAAe;AAC9C,CAAC"}
|
|
1
|
+
{"version":3,"file":"chat-message.js","names":[],"sources":["../src/content/chat-message/chat-message.ts"],"sourcesContent":["import { define, html, onEvent, onMounted, prop, ref, useEmit, useSlots } from '@vielzeug/ore';\nimport { computed, watch } from '@vielzeug/ripple';\n\nimport { announce } from '../../core';\nimport { reducedMotionMixin } from '../../styles';\nimport '../icon/icon';\nimport componentStyles from './chat-message.css?inline';\n\nexport type ChatMessageSender = 'assistant' | 'system' | 'user';\nexport type ChatMessageStatus = 'error' | 'sending' | 'sent';\n\nconst SENDER_LABELS: Record<ChatMessageSender, string> = {\n assistant: 'Assistant',\n system: 'System',\n user: 'You',\n};\n\n/** Events emitted by the chat-message component */\nexport type OreChatMessageEvents = {\n /** Fired when the retry action is activated on a `status=\"error\"` message */\n retry: { originalEvent?: Event };\n};\n\n/** Chat message component properties */\nexport type OreChatMessageProps = {\n /** Error detail shown beneath the bubble; only visible when `status=\"error\"` */\n error?: string;\n /** Display name shown above the bubble (falls back to a generic label per `sender`) */\n name?: string;\n /** Who sent the message — controls alignment and bubble styling */\n sender?: ChatMessageSender;\n /** Delivery status for outgoing messages — shows an inline indicator and, for `\"error\"`, a retry action */\n status?: ChatMessageStatus;\n /** Append a blinking cursor after the content, for a message still streaming in */\n streaming?: boolean;\n /** ISO 8601 timestamp; rendered as a localized short time in a semantic `<time>` element */\n timestamp?: string;\n};\n\n/**\n * A single message bubble for chat/conversation UIs — sender-aware alignment, an optional\n * avatar slot, delivery status (sending/sent/error with retry), and a streaming cursor for\n * assistant messages still generating. Content is provided via the default slot, so any\n * markdown-to-HTML rendering stays the consumer's choice.\n *\n * The default slot's leading/trailing whitespace-only text nodes are trimmed in place once\n * per slot assignment (mount, and again on `slotchange`) — pretty-printed HTML's\n * indentation would otherwise render as blank lines, since the bubble preserves line breaks\n * (`white-space: pre-wrap`) for genuine multi-paragraph replies. This mutates those specific\n * text nodes' `textContent` directly; it never touches nodes appended afterward (e.g. by\n * `el.textContent += token` while streaming), only the ones present at assignment time.\n *\n * @element ore-chat-message\n *\n * @attr {string} sender - Who sent the message: 'user' | 'assistant' | 'system' (default 'assistant')\n * @attr {string} name - Display name shown above the bubble\n * @attr {string} timestamp - ISO 8601 timestamp, rendered as a localized short time\n * @attr {string} status - Delivery status: 'sending' | 'sent' | 'error'\n * @attr {string} error - Error detail shown beneath the bubble when status=\"error\"\n * @attr {boolean} streaming - Append a blinking cursor after the content\n *\n * @fires retry - Fired when the retry action is activated. detail: { originalEvent }\n *\n * @slot - Message content\n * @slot avatar - Avatar element (e.g. `<ore-avatar>`)\n * @slot actions - Action buttons shown beneath the message (copy, regenerate, feedback, …)\n *\n * @cssprop --chat-message-bg - Bubble background color (assistant/system)\n * @cssprop --chat-message-color - Bubble text color (assistant/system)\n * @cssprop --chat-message-user-bg - Bubble background color (user)\n * @cssprop --chat-message-user-color - Bubble text color (user)\n * @cssprop --chat-message-radius - Bubble border radius\n * @cssprop --chat-message-max-width - Maximum bubble width\n *\n * @part row - Root row container (avatar + column)\n * @part avatar - Avatar slot container\n * @part column - Column containing name, bubble, meta, and actions\n * @part name - Sender display name\n * @part bubble - Message bubble container\n * @part content - Content container inside the bubble\n * @part cursor - Blinking streaming cursor\n * @part meta - Row of timestamp, status, and error text below the bubble\n * @part timestamp - Timestamp `<time>` element\n * @part status - Status indicator\n * @part error - Error text\n * @part retry - Retry button (status=\"error\" only)\n * @part actions - Actions slot container\n *\n * @example\n * ```html\n * <ore-chat-message sender=\"user\" timestamp=\"2024-01-01T12:00:00Z\" status=\"sent\">\n * What's the weather like today?\n * </ore-chat-message>\n *\n * <ore-chat-message sender=\"assistant\" name=\"Assistant\" streaming>\n * Let me check that for you\n * </ore-chat-message>\n * ```\n */\nexport const CHAT_MESSAGE_TAG = 'ore-chat-message' as const;\ndefine<OreChatMessageProps>(CHAT_MESSAGE_TAG, {\n props: {\n error: prop.string(),\n name: prop.string(),\n sender: prop.oneOf(['user', 'assistant', 'system'] as const, 'assistant'),\n status: prop.string<ChatMessageStatus>(),\n streaming: prop.bool(false),\n timestamp: prop.string(),\n },\n setup(props) {\n const emit = useEmit<OreChatMessageEvents>();\n const slots = useSlots();\n\n const senderLabel = () => SENDER_LABELS[props.sender.value ?? 'assistant'];\n\n const bubbleLabel = computed(() => `Message from ${props.name.value || senderLabel()}`);\n\n const formattedTime = computed(() => {\n const raw = props.timestamp.value;\n\n if (!raw) return '';\n\n const date = new Date(raw);\n\n if (Number.isNaN(date.getTime())) return '';\n\n return new Intl.DateTimeFormat(undefined, { hour: 'numeric', minute: '2-digit' }).format(date);\n });\n\n const hasMeta = computed(\n () => Boolean(formattedTime.value) || Boolean(props.status.value) || Boolean(props.error.value),\n );\n\n // Announce delivery failures — the visible retry button and error text are always present\n // for sighted users, but a failed send is exactly the kind of state change a screen\n // reader user could otherwise miss entirely. Keyed on `error` text too (not just\n // `status`) so a retry that fails again with a *different* reason re-announces even\n // though `status` never left `\"error\"` in between; a second failure with the identical\n // message doesn't re-fire, since the source value hasn't actually changed.\n watch(\n () => (props.status.value === 'error' ? (props.error.value ?? '') : null),\n (errorText) => {\n if (errorText !== null) {\n announce(`Message failed to send${errorText ? `: ${errorText}` : ''}`, { politeness: 'assertive' });\n }\n },\n );\n\n function handleRetry(e: Event): void {\n emit('retry', { originalEvent: e });\n }\n\n // ── Trim author-time indentation whitespace from the default slot ──\n // `.content` uses `white-space: pre-wrap` so genuine multi-paragraph replies keep their\n // line breaks — but that also preserves the leading/trailing newline + indentation from\n // pretty-printed HTML (`<ore-chat-message>\\n Hello\\n</ore-chat-message>`), rendering as\n // visible blank lines around the text. Trim only the outermost edges once per slot\n // assignment; appending tokens to an existing text node for streaming doesn't re-fire\n // `slotchange`, so this never interferes with in-progress streaming updates.\n //\n // A named-slotted sibling (e.g. `<ore-avatar slot=\"avatar\">` between the opening tag and\n // the message text) splits the default slot's light-DOM text into *multiple* text nodes\n // — text nodes can't target a named slot, so each run on either side of the element is\n // assigned separately. The \"real\" content can start on a later node than index 0 (it's\n // still preceded by its own leading indentation), so this walks inward from each end,\n // fully clearing whitespace-only nodes and stopping at the first node with real content\n // on each side — rather than only touching the very first/last assigned node.\n const contentSlotRef = ref<HTMLSlotElement>();\n\n function trimSlotEdgeWhitespace(): void {\n const nodes = contentSlotRef.value?.assignedNodes({ flatten: true });\n\n if (!nodes || nodes.length === 0) return;\n\n for (const node of nodes) {\n if (node.nodeType !== Node.TEXT_NODE) break;\n\n const trimmed = (node.textContent ?? '').replace(/^\\s+/, '');\n\n node.textContent = trimmed;\n\n if (trimmed !== '') break;\n }\n\n for (let i = nodes.length - 1; i >= 0; i--) {\n const node = nodes[i];\n\n if (node.nodeType !== Node.TEXT_NODE) break;\n\n const trimmed = (node.textContent ?? '').replace(/\\s+$/, '');\n\n node.textContent = trimmed;\n\n if (trimmed !== '') break;\n }\n }\n\n onMounted(() => {\n trimSlotEdgeWhitespace();\n\n const slotEl = contentSlotRef.value;\n\n if (slotEl) onEvent(slotEl, 'slotchange', trimSlotEdgeWhitespace);\n });\n\n return html`\n <div class=\"row\" part=\"row\">\n <span class=\"avatar\" part=\"avatar\" ?hidden=\"${() => !slots.has('avatar').value}\">\n <slot name=\"avatar\"></slot>\n </span>\n <div class=\"column\" part=\"column\">\n <span class=\"name\" part=\"name\" ?hidden=\"${() => !props.name.value}\">${props.name}</span>\n <div class=\"bubble\" part=\"bubble\" role=\"article\" aria-label=\"${bubbleLabel}\">\n <div class=\"content\" part=\"content\">\n <slot class=\"content-slot\" ref=\"${contentSlotRef}\"></slot>\n <span class=\"cursor\" part=\"cursor\" aria-hidden=\"true\" ?hidden=\"${() => !props.streaming.value}\"></span>\n </div>\n </div>\n <div class=\"meta\" part=\"meta\" ?hidden=\"${() => !hasMeta.value}\">\n <time\n class=\"timestamp\"\n part=\"timestamp\"\n datetime=\"${props.timestamp}\"\n ?hidden=\"${() => !formattedTime.value}\">\n ${formattedTime}\n </time>\n <span class=\"status\" part=\"status\" data-status=\"${props.status}\" ?hidden=\"${() => !props.status.value}\">\n ${() => {\n switch (props.status.value) {\n case 'error':\n return html`\n <ore-icon name=\"alert-circle\" size=\"12\" stroke-width=\"2.5\" aria-hidden=\"true\"></ore-icon>\n `;\n case 'sending':\n return html`\n <span class=\"spinner\" aria-hidden=\"true\"></span>\n `;\n case 'sent':\n return html`\n <ore-icon name=\"check\" size=\"12\" stroke-width=\"2.5\" aria-hidden=\"true\"></ore-icon>\n `;\n default:\n return '';\n }\n }}\n </span>\n <span class=\"error-text\" part=\"error\" role=\"alert\" ?hidden=\"${() => !props.error.value}\">\n ${props.error}\n </span>\n <button\n class=\"retry\"\n part=\"retry\"\n type=\"button\"\n ?hidden=\"${() => props.status.value !== 'error'}\"\n @click=\"${handleRetry}\">\n Retry\n </button>\n </div>\n <div class=\"actions\" part=\"actions\" ?hidden=\"${() => !slots.has('actions').value}\">\n <slot name=\"actions\"></slot>\n </div>\n </div>\n </div>\n `;\n },\n styles: [reducedMotionMixin, componentStyles],\n});\n"],"mappings":"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"}
|
package/dist/checkbox-group.cjs
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./styles/mixins/states.css.cjs"),t=require("./core/choice-field.cjs"),n=require("./core/light-dom.cjs"),r=require("./core/ore.cjs"),i=require("./shared/prop-bundles.cjs"),a=require("./inputs/checkbox-group/checkbox-group.css.cjs");let o=require("@vielzeug/ore"),s=require("@vielzeug/ripple");var c=(0,o.createContext)(`CheckboxGroupContext`),l=`ore-checkbox-group`;(0,o.define)(l,{formAssociated:!0,props:{...i.themableBundle,...i.sizableBundle,...i.disablableBundle,error:o.prop.string(),helper:o.prop.string(),label:o.prop.string(),name:o.prop.string(),orientation:o.prop.string(`vertical`),required:o.prop.bool(!1),values:{...o.prop.string(),reflect:!1}},setup(e){let i=(0,o.getHost)(),a=(0,o.useEmit)(),l=(0,o.useSlots)(),u=o.watchEffect,d=t.createChoiceField({disabled:e.disabled,error:e.error,helper:e.helper,multiple:(0,s.signal)(!0),prefix:`checkbox-group`,required:e.required,signal:r.lifecycleSignal(o.onCleanup),value:e.values});d.attachFormField((0,o.useField)({disabled:d.disabled,onReset:d.reset,toFormValue:e=>e,validationMessage:d.validationMessage,validity:d.validity,value:d.formValue}));let f=d.selectedValues,p=()=>n.getLightChildrenByTag(i,`ore-checkbox`),m=e=>n.getChoiceLabel(p(),e),h=e=>{let t=f.value,n=t.map(m);a(`change`,{labels:n,originalEvent:e,values:t})},g=(e,t)=>{d.toggleValue(e),d.triggerValidation(`change`),h(t)};(0,o.provide)(c,{color:e.color,disabled:(0,s.computed)(()=>!!e.disabled.value),size:e.size,toggle:g,values:f});let _=()=>{let t=f.value,n=e.color.value,r=e.size.value,i=e.disabled.value,a=p();for(let e of a){let a=e.getAttribute(`value`)??``;e.toggleAttribute(`checked`,t.includes(a)),n?e.setAttribute(`color`,n):e.removeAttribute(`color`),r?e.setAttribute(`size`,r):e.removeAttribute(`size`),e.toggleAttribute(`disabled`,!!i)}};u(()=>{l.elements().value,_()}),u(()=>{l.elements().value;let e=p().map(e=>{let t=t=>{t.stopPropagation();let n=(e.getAttribute(`value`)??``).trim();n&&g(n,t)};return e.addEventListener(`change`,t),()=>{e.removeEventListener(`change`,t)}});return()=>{for(let t of e)t()}});let v=(0,o.createStableId)(`checkbox-group-legend`),y=`${v}-error`,b=`${v}-helper`,x=()=>!!e.error.value,S=()=>!!e.helper.value&&!x();return(0,o.bind)({attr:{size:e.size,values:d.formValue}}),o.html`
|
|
2
2
|
<fieldset
|
|
3
3
|
role="group"
|
|
4
|
-
aria-required="${()=>String(!!
|
|
4
|
+
aria-required="${()=>String(!!e.required.value)}"
|
|
5
5
|
aria-invalid="${()=>String(x())}"
|
|
6
6
|
aria-errormessage="${()=>x()?y:null}"
|
|
7
7
|
aria-describedby="${()=>x()?y:S()?b:null}">
|
|
8
|
-
<legend id="${v}" ?hidden=${()=>!
|
|
9
|
-
${
|
|
8
|
+
<legend id="${v}" ?hidden=${()=>!e.label.value}>
|
|
9
|
+
${e.label}${(0,o.when)(()=>!!e.required.value,()=>o.html`
|
|
10
10
|
<span aria-hidden="true">*</span>
|
|
11
11
|
`)}
|
|
12
12
|
</legend>
|
|
13
13
|
<div class="checkbox-group-items" part="items">
|
|
14
14
|
<slot></slot>
|
|
15
15
|
</div>
|
|
16
|
-
<div class="error-text" id="${y}" role="alert" ?hidden=${()=>!x()}>${
|
|
17
|
-
<div class="helper-text" id="${b}" ?hidden=${()=>!S()}>${
|
|
16
|
+
<div class="error-text" id="${y}" role="alert" ?hidden=${()=>!x()}>${e.error}</div>
|
|
17
|
+
<div class="helper-text" id="${b}" ?hidden=${()=>!S()}>${e.helper}</div>
|
|
18
18
|
</fieldset>
|
|
19
|
-
`},styles:[
|
|
19
|
+
`},styles:[e.disabledStateMixin,a.default]}),exports.CHECKBOX_GROUP_CTX=c,exports.CHECKBOX_GROUP_TAG=l;
|
|
20
20
|
//# sourceMappingURL=checkbox-group.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkbox-group.cjs","names":[],"sources":["../src/inputs/checkbox-group/checkbox-group.ts"],"sourcesContent":["import {\n createContext,\n createStableId,\n define,\n html,\n prop,\n bind,\n getHost,\n onCleanup,\n provide,\n useEmit,\n useSlots,\n watchEffect,\n when,\n} from '@vielzeug/ore';\nimport { useField } from '@vielzeug/ore';\nimport { computed, type Readable, signal } from '@vielzeug/ripple';\n\nimport type { ComponentSize, ThemeColor } from '../../types';\n\nimport {\n type ChoiceChangeDetail,\n lifecycleSignal,\n createChoiceField,\n getChoiceLabel,\n getLightChildrenByTag,\n} from '../../core';\nimport { disablableBundle, sizableBundle, themableBundle } from '../../shared';\nimport { disabledStateMixin } from '../../styles';\nimport componentStyles from './checkbox-group.css?inline';\n\n// ─── Context ──────────────────────────────────────────────────────────────────\n\nexport type CheckboxGroupContext = {\n color: Readable<ThemeColor | undefined>;\n disabled: Readable<boolean>;\n size: Readable<ComponentSize | undefined>;\n toggle: (value: string, originalEvent?: Event) => void;\n values: Readable<string[]>;\n};\n\nexport const CHECKBOX_GROUP_CTX = createContext<CheckboxGroupContext>('CheckboxGroupContext');\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport type OreCheckboxGroupProps = {\n /** Theme color — propagated to all child ore-checkbox elements */\n color?: ThemeColor;\n /** Disable all checkboxes in the group */\n disabled?: boolean;\n /** Error message shown below the group */\n error?: string;\n /** Helper text shown below the group */\n helper?: string;\n /** Legend / label for the fieldset. Required for accessibility. */\n label?: string;\n /** Form field name used during submission */\n name?: string;\n /** Layout direction of the checkbox options */\n orientation?: 'vertical' | 'horizontal';\n /** Mark the group as required */\n required?: boolean;\n /** Size — propagated to all child ore-checkbox elements */\n size?: ComponentSize;\n /** Comma-separated list of currently checked values */\n values?: string;\n};\n\nexport type OreCheckboxGroupEvents = {\n change: ChoiceChangeDetail;\n};\n\n/**\n * A fieldset wrapper that groups `ore-checkbox` elements, provides shared\n * `color` and `size` via context, and manages multi-value selection state.\n *\n * @element ore-checkbox-group\n *\n * @attr {string} label - Legend text (required for a11y)\n * @attr {string} values - Comma-separated list of checked values\n * @attr {boolean} disabled - Disable all checkboxes in the group\n * @attr {string} error - Error message\n * @attr {string} helper - Helper text\n * @attr {string} name - Form field name\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} orientation - Layout: 'vertical' | 'horizontal'\n * @attr {boolean} required - Required field\n *\n * @fires change - Emitted when selection changes. detail: { value: string, values: string[], labels: string[], originalEvent?: Event }\n *\n * @slot - Place `ore-checkbox` elements here\n *\n * @cssprop --checkbox-group-direction - Flex direction of the items list ('row' | 'column')\n * @cssprop --checkbox-group-gap - Gap between checkbox items\n * @part items - Items container.\n * @example\n * ```html\n * <ore-checkbox-group name=\"fruits\" label=\"Favourite fruits\" required>\n * <ore-checkbox value=\"apple\">Apple</ore-checkbox>\n * <ore-checkbox value=\"banana\">Banana</ore-checkbox>\n * <ore-checkbox value=\"cherry\">Cherry</ore-checkbox>\n * </ore-checkbox-group>\n * <ore-checkbox-group name=\"options\" orientation=\"horizontal\" color=\"primary\">\n * <ore-checkbox value=\"a\">Option A</ore-checkbox>\n * <ore-checkbox value=\"b\">Option B</ore-checkbox>\n * </ore-checkbox-group>\n * ```\n */\nexport const CHECKBOX_GROUP_TAG = 'ore-checkbox-group' as const;\ndefine<OreCheckboxGroupProps>(CHECKBOX_GROUP_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n error: prop.string(),\n helper: prop.string(),\n label: prop.string(),\n name: prop.string(),\n orientation: prop.string('vertical'),\n required: prop.bool(false),\n // Not auto-reflected (`reflect: false`) — the derived, interaction-updated selection\n // (`choice.formValue`) is the single writer for this attribute, via `bind()` below;\n // letting `prop.string()`'s own default reflection also write the raw incoming value\n // would leave two effects racing to set the same attribute from different sources.\n values: { ...prop.string(), reflect: false },\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreCheckboxGroupEvents>();\n const slots = useSlots();\n const watch = watchEffect;\n\n const choice = createChoiceField({\n disabled: props.disabled,\n error: props.error,\n helper: props.helper,\n multiple: signal(true),\n prefix: 'checkbox-group',\n required: props.required,\n signal: lifecycleSignal(onCleanup),\n value: props.values,\n });\n\n choice.attachFormField(\n useField<string>({\n disabled: choice.disabled,\n onReset: choice.reset,\n toFormValue: (v) => v,\n validationMessage: choice.validationMessage,\n validity: choice.validity,\n value: choice.formValue,\n }),\n );\n\n const checkedValues = choice.selectedValues;\n\n const getCheckboxes = (): HTMLElement[] => getLightChildrenByTag(el, 'ore-checkbox');\n const getLabelForValue = (value: string): string => getChoiceLabel(getCheckboxes(), value);\n const emitChange = (originalEvent?: Event) => {\n const values = checkedValues.value;\n\n const labels = values.map(getLabelForValue);\n\n emit('change', { labels, originalEvent, values });\n };\n\n const toggleCheckbox = (val: string, originalEvent?: Event) => {\n choice.toggleValue(val);\n choice.triggerValidation('change');\n emitChange(originalEvent);\n };\n\n provide(CHECKBOX_GROUP_CTX, {\n color: props.color,\n disabled: computed(() => Boolean(props.disabled.value)),\n size: props.size,\n toggle: toggleCheckbox,\n values: checkedValues,\n });\n\n // Sync checked state + color/size/disabled onto slotted ore-checkbox children\n const syncChildren = () => {\n const values = checkedValues.value;\n const color = props.color.value;\n const size = props.size.value;\n const disabled = props.disabled.value;\n const checkboxes = getCheckboxes();\n\n for (const checkbox of checkboxes) {\n const val = checkbox.getAttribute('value') ?? '';\n\n checkbox.toggleAttribute('checked', values.includes(val));\n\n if (color) checkbox.setAttribute('color', color);\n else checkbox.removeAttribute('color');\n\n if (size) checkbox.setAttribute('size', size);\n else checkbox.removeAttribute('size');\n\n checkbox.toggleAttribute('disabled', Boolean(disabled));\n }\n };\n\n watch(() => {\n void slots.elements().value;\n syncChildren();\n });\n\n watch(() => {\n void slots.elements().value;\n\n const listeners = getCheckboxes().map((checkbox) => {\n const handler = (event: Event) => {\n event.stopPropagation();\n\n const val = (checkbox.getAttribute('value') ?? '').trim();\n\n if (!val) return;\n\n toggleCheckbox(val, event);\n };\n\n checkbox.addEventListener('change', handler);\n\n return () => {\n checkbox.removeEventListener('change', handler);\n };\n });\n\n return () => {\n for (const dispose of listeners) dispose();\n };\n });\n\n const legendId = createStableId('checkbox-group-legend');\n const errorId = `${legendId}-error`;\n const helperId = `${legendId}-helper`;\n const hasError = () => Boolean(props.error.value);\n const hasHelper = () => Boolean(props.helper.value) && !hasError();\n\n // Reactive, not a one-off `el.setAttribute()` inside the click handler: the host's `values`\n // attribute must stay in sync with the selection regardless of *why* it changed (a click,\n // or `reset()` on ancestor form reset — neither of which should need its own copy of this).\n bind({ attr: { size: props.size, values: choice.formValue } });\n\n return html`\n <fieldset\n role=\"group\"\n aria-required=\"${() => String(Boolean(props.required.value))}\"\n aria-invalid=\"${() => String(hasError())}\"\n aria-errormessage=\"${() => (hasError() ? errorId : null)}\"\n aria-describedby=\"${() => (hasError() ? errorId : hasHelper() ? helperId : null)}\">\n <legend id=\"${legendId}\" ?hidden=${() => !props.label.value}>\n ${props.label}${when(\n () => Boolean(props.required.value),\n () => html`\n <span aria-hidden=\"true\">*</span>\n `,\n )}\n </legend>\n <div class=\"checkbox-group-items\" part=\"items\">\n <slot></slot>\n </div>\n <div class=\"error-text\" id=\"${errorId}\" role=\"alert\" ?hidden=${() => !hasError()}>${props.error}</div>\n <div class=\"helper-text\" id=\"${helperId}\" ?hidden=${() => !hasHelper()}>${props.helper}</div>\n </fieldset>\n `;\n },\n styles: [disabledStateMixin, componentStyles],\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"checkbox-group.cjs","names":[],"sources":["../src/inputs/checkbox-group/checkbox-group.ts"],"sourcesContent":["import {\n bind,\n createContext,\n createStableId,\n define,\n getHost,\n html,\n onCleanup,\n prop,\n provide,\n useEmit,\n useField,\n useSlots,\n watchEffect,\n when,\n} from '@vielzeug/ore';\nimport { computed, type Readable, signal } from '@vielzeug/ripple';\nimport {\n type ChoiceChangeDetail,\n createChoiceField,\n getChoiceLabel,\n getLightChildrenByTag,\n lifecycleSignal,\n} from '../../core';\nimport { disablableBundle, sizableBundle, themableBundle } from '../../shared';\nimport { disabledStateMixin } from '../../styles';\nimport type { ComponentSize, ThemeColor } from '../../types';\nimport componentStyles from './checkbox-group.css?inline';\n\n// ─── Context ──────────────────────────────────────────────────────────────────\n\nexport type CheckboxGroupContext = {\n color: Readable<ThemeColor | undefined>;\n disabled: Readable<boolean>;\n size: Readable<ComponentSize | undefined>;\n toggle: (value: string, originalEvent?: Event) => void;\n values: Readable<string[]>;\n};\n\nexport const CHECKBOX_GROUP_CTX = createContext<CheckboxGroupContext>('CheckboxGroupContext');\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport type OreCheckboxGroupProps = {\n /** Theme color — propagated to all child ore-checkbox elements */\n color?: ThemeColor;\n /** Disable all checkboxes in the group */\n disabled?: boolean;\n /** Error message shown below the group */\n error?: string;\n /** Helper text shown below the group */\n helper?: string;\n /** Legend / label for the fieldset. Required for accessibility. */\n label?: string;\n /** Form field name used during submission */\n name?: string;\n /** Layout direction of the checkbox options */\n orientation?: 'vertical' | 'horizontal';\n /** Mark the group as required */\n required?: boolean;\n /** Size — propagated to all child ore-checkbox elements */\n size?: ComponentSize;\n /** Comma-separated list of currently checked values */\n values?: string;\n};\n\nexport type OreCheckboxGroupEvents = {\n change: ChoiceChangeDetail;\n};\n\n/**\n * A fieldset wrapper that groups `ore-checkbox` elements, provides shared\n * `color` and `size` via context, and manages multi-value selection state.\n *\n * @element ore-checkbox-group\n *\n * @attr {string} label - Legend text (required for a11y)\n * @attr {string} values - Comma-separated list of checked values\n * @attr {boolean} disabled - Disable all checkboxes in the group\n * @attr {string} error - Error message\n * @attr {string} helper - Helper text\n * @attr {string} name - Form field name\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} orientation - Layout: 'vertical' | 'horizontal'\n * @attr {boolean} required - Required field\n *\n * @fires change - Emitted when selection changes. detail: { value: string, values: string[], labels: string[], originalEvent?: Event }\n *\n * @slot - Place `ore-checkbox` elements here\n *\n * @cssprop --checkbox-group-direction - Flex direction of the items list ('row' | 'column')\n * @cssprop --checkbox-group-gap - Gap between checkbox items\n * @part items - Items container.\n * @example\n * ```html\n * <ore-checkbox-group name=\"fruits\" label=\"Favourite fruits\" required>\n * <ore-checkbox value=\"apple\">Apple</ore-checkbox>\n * <ore-checkbox value=\"banana\">Banana</ore-checkbox>\n * <ore-checkbox value=\"cherry\">Cherry</ore-checkbox>\n * </ore-checkbox-group>\n * <ore-checkbox-group name=\"options\" orientation=\"horizontal\" color=\"primary\">\n * <ore-checkbox value=\"a\">Option A</ore-checkbox>\n * <ore-checkbox value=\"b\">Option B</ore-checkbox>\n * </ore-checkbox-group>\n * ```\n */\nexport const CHECKBOX_GROUP_TAG = 'ore-checkbox-group' as const;\ndefine<OreCheckboxGroupProps>(CHECKBOX_GROUP_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n error: prop.string(),\n helper: prop.string(),\n label: prop.string(),\n name: prop.string(),\n orientation: prop.string('vertical'),\n required: prop.bool(false),\n // Not auto-reflected (`reflect: false`) — the derived, interaction-updated selection\n // (`choice.formValue`) is the single writer for this attribute, via `bind()` below;\n // letting `prop.string()`'s own default reflection also write the raw incoming value\n // would leave two effects racing to set the same attribute from different sources.\n values: { ...prop.string(), reflect: false },\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreCheckboxGroupEvents>();\n const slots = useSlots();\n const watch = watchEffect;\n\n const choice = createChoiceField({\n disabled: props.disabled,\n error: props.error,\n helper: props.helper,\n multiple: signal(true),\n prefix: 'checkbox-group',\n required: props.required,\n signal: lifecycleSignal(onCleanup),\n value: props.values,\n });\n\n choice.attachFormField(\n useField<string>({\n disabled: choice.disabled,\n onReset: choice.reset,\n toFormValue: (v) => v,\n validationMessage: choice.validationMessage,\n validity: choice.validity,\n value: choice.formValue,\n }),\n );\n\n const checkedValues = choice.selectedValues;\n\n const getCheckboxes = (): HTMLElement[] => getLightChildrenByTag(el, 'ore-checkbox');\n const getLabelForValue = (value: string): string => getChoiceLabel(getCheckboxes(), value);\n const emitChange = (originalEvent?: Event) => {\n const values = checkedValues.value;\n\n const labels = values.map(getLabelForValue);\n\n emit('change', { labels, originalEvent, values });\n };\n\n const toggleCheckbox = (val: string, originalEvent?: Event) => {\n choice.toggleValue(val);\n choice.triggerValidation('change');\n emitChange(originalEvent);\n };\n\n provide(CHECKBOX_GROUP_CTX, {\n color: props.color,\n disabled: computed(() => Boolean(props.disabled.value)),\n size: props.size,\n toggle: toggleCheckbox,\n values: checkedValues,\n });\n\n // Sync checked state + color/size/disabled onto slotted ore-checkbox children\n const syncChildren = () => {\n const values = checkedValues.value;\n const color = props.color.value;\n const size = props.size.value;\n const disabled = props.disabled.value;\n const checkboxes = getCheckboxes();\n\n for (const checkbox of checkboxes) {\n const val = checkbox.getAttribute('value') ?? '';\n\n checkbox.toggleAttribute('checked', values.includes(val));\n\n if (color) checkbox.setAttribute('color', color);\n else checkbox.removeAttribute('color');\n\n if (size) checkbox.setAttribute('size', size);\n else checkbox.removeAttribute('size');\n\n checkbox.toggleAttribute('disabled', Boolean(disabled));\n }\n };\n\n watch(() => {\n void slots.elements().value;\n syncChildren();\n });\n\n watch(() => {\n void slots.elements().value;\n\n const listeners = getCheckboxes().map((checkbox) => {\n const handler = (event: Event) => {\n event.stopPropagation();\n\n const val = (checkbox.getAttribute('value') ?? '').trim();\n\n if (!val) return;\n\n toggleCheckbox(val, event);\n };\n\n checkbox.addEventListener('change', handler);\n\n return () => {\n checkbox.removeEventListener('change', handler);\n };\n });\n\n return () => {\n for (const dispose of listeners) dispose();\n };\n });\n\n const legendId = createStableId('checkbox-group-legend');\n const errorId = `${legendId}-error`;\n const helperId = `${legendId}-helper`;\n const hasError = () => Boolean(props.error.value);\n const hasHelper = () => Boolean(props.helper.value) && !hasError();\n\n // Reactive, not a one-off `el.setAttribute()` inside the click handler: the host's `values`\n // attribute must stay in sync with the selection regardless of *why* it changed (a click,\n // or `reset()` on ancestor form reset — neither of which should need its own copy of this).\n bind({ attr: { size: props.size, values: choice.formValue } });\n\n return html`\n <fieldset\n role=\"group\"\n aria-required=\"${() => String(Boolean(props.required.value))}\"\n aria-invalid=\"${() => String(hasError())}\"\n aria-errormessage=\"${() => (hasError() ? errorId : null)}\"\n aria-describedby=\"${() => (hasError() ? errorId : hasHelper() ? helperId : null)}\">\n <legend id=\"${legendId}\" ?hidden=${() => !props.label.value}>\n ${props.label}${when(\n () => Boolean(props.required.value),\n () => html`\n <span aria-hidden=\"true\">*</span>\n `,\n )}\n </legend>\n <div class=\"checkbox-group-items\" part=\"items\">\n <slot></slot>\n </div>\n <div class=\"error-text\" id=\"${errorId}\" role=\"alert\" ?hidden=${() => !hasError()}>${props.error}</div>\n <div class=\"helper-text\" id=\"${helperId}\" ?hidden=${() => !hasHelper()}>${props.helper}</div>\n </fieldset>\n `;\n },\n styles: [disabledStateMixin, componentStyles],\n});\n"],"mappings":"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"}
|
package/dist/checkbox-group.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { disabledStateMixin as e } from "./styles/mixins/states.css.js";
|
|
2
2
|
import { createChoiceField as t } from "./core/choice-field.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { getChoiceLabel as n, getLightChildrenByTag as r } from "./core/light-dom.js";
|
|
4
|
+
import { lifecycleSignal as i } from "./core/ore.js";
|
|
5
5
|
import { disablableBundle as a, sizableBundle as o, themableBundle as s } from "./shared/prop-bundles.js";
|
|
6
6
|
import c from "./inputs/checkbox-group/checkbox-group.css.js";
|
|
7
7
|
import { bind as l, createContext as u, createStableId as d, define as f, getHost as p, html as m, onCleanup as h, prop as g, provide as _, useEmit as v, useField as y, useSlots as b, watchEffect as x, when as S } from "@vielzeug/ore";
|
|
@@ -25,16 +25,16 @@ f(E, {
|
|
|
25
25
|
reflect: !1
|
|
26
26
|
}
|
|
27
27
|
},
|
|
28
|
-
setup(
|
|
28
|
+
setup(e) {
|
|
29
29
|
let a = p(), o = v(), s = b(), c = x, u = t({
|
|
30
|
-
disabled:
|
|
31
|
-
error:
|
|
32
|
-
helper:
|
|
30
|
+
disabled: e.disabled,
|
|
31
|
+
error: e.error,
|
|
32
|
+
helper: e.helper,
|
|
33
33
|
multiple: w(!0),
|
|
34
34
|
prefix: "checkbox-group",
|
|
35
|
-
required:
|
|
36
|
-
signal:
|
|
37
|
-
value:
|
|
35
|
+
required: e.required,
|
|
36
|
+
signal: i(h),
|
|
37
|
+
value: e.values
|
|
38
38
|
});
|
|
39
39
|
u.attachFormField(y({
|
|
40
40
|
disabled: u.disabled,
|
|
@@ -44,7 +44,7 @@ f(E, {
|
|
|
44
44
|
validity: u.validity,
|
|
45
45
|
value: u.formValue
|
|
46
46
|
}));
|
|
47
|
-
let f = u.selectedValues, g = () =>
|
|
47
|
+
let f = u.selectedValues, g = () => r(a, "ore-checkbox"), E = (e) => n(g(), e), D = (e) => {
|
|
48
48
|
let t = f.value, n = t.map(E);
|
|
49
49
|
o("change", {
|
|
50
50
|
labels: n,
|
|
@@ -55,17 +55,17 @@ f(E, {
|
|
|
55
55
|
u.toggleValue(e), u.triggerValidation("change"), D(t);
|
|
56
56
|
};
|
|
57
57
|
_(T, {
|
|
58
|
-
color:
|
|
59
|
-
disabled: C(() => !!
|
|
60
|
-
size:
|
|
58
|
+
color: e.color,
|
|
59
|
+
disabled: C(() => !!e.disabled.value),
|
|
60
|
+
size: e.size,
|
|
61
61
|
toggle: O,
|
|
62
62
|
values: f
|
|
63
63
|
});
|
|
64
64
|
let k = () => {
|
|
65
|
-
let
|
|
66
|
-
for (let
|
|
67
|
-
let a =
|
|
68
|
-
|
|
65
|
+
let t = f.value, n = e.color.value, r = e.size.value, i = e.disabled.value, a = g();
|
|
66
|
+
for (let e of a) {
|
|
67
|
+
let a = e.getAttribute("value") ?? "";
|
|
68
|
+
e.toggleAttribute("checked", t.includes(a)), n ? e.setAttribute("color", n) : e.removeAttribute("color"), r ? e.setAttribute("size", r) : e.removeAttribute("size"), e.toggleAttribute("disabled", !!i);
|
|
69
69
|
}
|
|
70
70
|
};
|
|
71
71
|
c(() => {
|
|
@@ -86,31 +86,31 @@ f(E, {
|
|
|
86
86
|
for (let t of e) t();
|
|
87
87
|
};
|
|
88
88
|
});
|
|
89
|
-
let A = d("checkbox-group-legend"), j = `${A}-error`, M = `${A}-helper`, N = () => !!
|
|
89
|
+
let A = d("checkbox-group-legend"), j = `${A}-error`, M = `${A}-helper`, N = () => !!e.error.value, P = () => !!e.helper.value && !N();
|
|
90
90
|
return l({ attr: {
|
|
91
|
-
size:
|
|
91
|
+
size: e.size,
|
|
92
92
|
values: u.formValue
|
|
93
93
|
} }), m`
|
|
94
94
|
<fieldset
|
|
95
95
|
role="group"
|
|
96
|
-
aria-required="${() => String(!!
|
|
96
|
+
aria-required="${() => String(!!e.required.value)}"
|
|
97
97
|
aria-invalid="${() => String(N())}"
|
|
98
98
|
aria-errormessage="${() => N() ? j : null}"
|
|
99
99
|
aria-describedby="${() => N() ? j : P() ? M : null}">
|
|
100
|
-
<legend id="${A}" ?hidden=${() => !
|
|
101
|
-
${
|
|
100
|
+
<legend id="${A}" ?hidden=${() => !e.label.value}>
|
|
101
|
+
${e.label}${S(() => !!e.required.value, () => m`
|
|
102
102
|
<span aria-hidden="true">*</span>
|
|
103
103
|
`)}
|
|
104
104
|
</legend>
|
|
105
105
|
<div class="checkbox-group-items" part="items">
|
|
106
106
|
<slot></slot>
|
|
107
107
|
</div>
|
|
108
|
-
<div class="error-text" id="${j}" role="alert" ?hidden=${() => !N()}>${
|
|
109
|
-
<div class="helper-text" id="${M}" ?hidden=${() => !P()}>${
|
|
108
|
+
<div class="error-text" id="${j}" role="alert" ?hidden=${() => !N()}>${e.error}</div>
|
|
109
|
+
<div class="helper-text" id="${M}" ?hidden=${() => !P()}>${e.helper}</div>
|
|
110
110
|
</fieldset>
|
|
111
111
|
`;
|
|
112
112
|
},
|
|
113
|
-
styles: [
|
|
113
|
+
styles: [e, c]
|
|
114
114
|
});
|
|
115
115
|
//#endregion
|
|
116
116
|
export { T as CHECKBOX_GROUP_CTX, E as CHECKBOX_GROUP_TAG };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkbox-group.js","names":[],"sources":["../src/inputs/checkbox-group/checkbox-group.ts"],"sourcesContent":["import {\n createContext,\n createStableId,\n define,\n html,\n prop,\n bind,\n getHost,\n onCleanup,\n provide,\n useEmit,\n useSlots,\n watchEffect,\n when,\n} from '@vielzeug/ore';\nimport { useField } from '@vielzeug/ore';\nimport { computed, type Readable, signal } from '@vielzeug/ripple';\n\nimport type { ComponentSize, ThemeColor } from '../../types';\n\nimport {\n type ChoiceChangeDetail,\n lifecycleSignal,\n createChoiceField,\n getChoiceLabel,\n getLightChildrenByTag,\n} from '../../core';\nimport { disablableBundle, sizableBundle, themableBundle } from '../../shared';\nimport { disabledStateMixin } from '../../styles';\nimport componentStyles from './checkbox-group.css?inline';\n\n// ─── Context ──────────────────────────────────────────────────────────────────\n\nexport type CheckboxGroupContext = {\n color: Readable<ThemeColor | undefined>;\n disabled: Readable<boolean>;\n size: Readable<ComponentSize | undefined>;\n toggle: (value: string, originalEvent?: Event) => void;\n values: Readable<string[]>;\n};\n\nexport const CHECKBOX_GROUP_CTX = createContext<CheckboxGroupContext>('CheckboxGroupContext');\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport type OreCheckboxGroupProps = {\n /** Theme color — propagated to all child ore-checkbox elements */\n color?: ThemeColor;\n /** Disable all checkboxes in the group */\n disabled?: boolean;\n /** Error message shown below the group */\n error?: string;\n /** Helper text shown below the group */\n helper?: string;\n /** Legend / label for the fieldset. Required for accessibility. */\n label?: string;\n /** Form field name used during submission */\n name?: string;\n /** Layout direction of the checkbox options */\n orientation?: 'vertical' | 'horizontal';\n /** Mark the group as required */\n required?: boolean;\n /** Size — propagated to all child ore-checkbox elements */\n size?: ComponentSize;\n /** Comma-separated list of currently checked values */\n values?: string;\n};\n\nexport type OreCheckboxGroupEvents = {\n change: ChoiceChangeDetail;\n};\n\n/**\n * A fieldset wrapper that groups `ore-checkbox` elements, provides shared\n * `color` and `size` via context, and manages multi-value selection state.\n *\n * @element ore-checkbox-group\n *\n * @attr {string} label - Legend text (required for a11y)\n * @attr {string} values - Comma-separated list of checked values\n * @attr {boolean} disabled - Disable all checkboxes in the group\n * @attr {string} error - Error message\n * @attr {string} helper - Helper text\n * @attr {string} name - Form field name\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} orientation - Layout: 'vertical' | 'horizontal'\n * @attr {boolean} required - Required field\n *\n * @fires change - Emitted when selection changes. detail: { value: string, values: string[], labels: string[], originalEvent?: Event }\n *\n * @slot - Place `ore-checkbox` elements here\n *\n * @cssprop --checkbox-group-direction - Flex direction of the items list ('row' | 'column')\n * @cssprop --checkbox-group-gap - Gap between checkbox items\n * @part items - Items container.\n * @example\n * ```html\n * <ore-checkbox-group name=\"fruits\" label=\"Favourite fruits\" required>\n * <ore-checkbox value=\"apple\">Apple</ore-checkbox>\n * <ore-checkbox value=\"banana\">Banana</ore-checkbox>\n * <ore-checkbox value=\"cherry\">Cherry</ore-checkbox>\n * </ore-checkbox-group>\n * <ore-checkbox-group name=\"options\" orientation=\"horizontal\" color=\"primary\">\n * <ore-checkbox value=\"a\">Option A</ore-checkbox>\n * <ore-checkbox value=\"b\">Option B</ore-checkbox>\n * </ore-checkbox-group>\n * ```\n */\nexport const CHECKBOX_GROUP_TAG = 'ore-checkbox-group' as const;\ndefine<OreCheckboxGroupProps>(CHECKBOX_GROUP_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n error: prop.string(),\n helper: prop.string(),\n label: prop.string(),\n name: prop.string(),\n orientation: prop.string('vertical'),\n required: prop.bool(false),\n // Not auto-reflected (`reflect: false`) — the derived, interaction-updated selection\n // (`choice.formValue`) is the single writer for this attribute, via `bind()` below;\n // letting `prop.string()`'s own default reflection also write the raw incoming value\n // would leave two effects racing to set the same attribute from different sources.\n values: { ...prop.string(), reflect: false },\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreCheckboxGroupEvents>();\n const slots = useSlots();\n const watch = watchEffect;\n\n const choice = createChoiceField({\n disabled: props.disabled,\n error: props.error,\n helper: props.helper,\n multiple: signal(true),\n prefix: 'checkbox-group',\n required: props.required,\n signal: lifecycleSignal(onCleanup),\n value: props.values,\n });\n\n choice.attachFormField(\n useField<string>({\n disabled: choice.disabled,\n onReset: choice.reset,\n toFormValue: (v) => v,\n validationMessage: choice.validationMessage,\n validity: choice.validity,\n value: choice.formValue,\n }),\n );\n\n const checkedValues = choice.selectedValues;\n\n const getCheckboxes = (): HTMLElement[] => getLightChildrenByTag(el, 'ore-checkbox');\n const getLabelForValue = (value: string): string => getChoiceLabel(getCheckboxes(), value);\n const emitChange = (originalEvent?: Event) => {\n const values = checkedValues.value;\n\n const labels = values.map(getLabelForValue);\n\n emit('change', { labels, originalEvent, values });\n };\n\n const toggleCheckbox = (val: string, originalEvent?: Event) => {\n choice.toggleValue(val);\n choice.triggerValidation('change');\n emitChange(originalEvent);\n };\n\n provide(CHECKBOX_GROUP_CTX, {\n color: props.color,\n disabled: computed(() => Boolean(props.disabled.value)),\n size: props.size,\n toggle: toggleCheckbox,\n values: checkedValues,\n });\n\n // Sync checked state + color/size/disabled onto slotted ore-checkbox children\n const syncChildren = () => {\n const values = checkedValues.value;\n const color = props.color.value;\n const size = props.size.value;\n const disabled = props.disabled.value;\n const checkboxes = getCheckboxes();\n\n for (const checkbox of checkboxes) {\n const val = checkbox.getAttribute('value') ?? '';\n\n checkbox.toggleAttribute('checked', values.includes(val));\n\n if (color) checkbox.setAttribute('color', color);\n else checkbox.removeAttribute('color');\n\n if (size) checkbox.setAttribute('size', size);\n else checkbox.removeAttribute('size');\n\n checkbox.toggleAttribute('disabled', Boolean(disabled));\n }\n };\n\n watch(() => {\n void slots.elements().value;\n syncChildren();\n });\n\n watch(() => {\n void slots.elements().value;\n\n const listeners = getCheckboxes().map((checkbox) => {\n const handler = (event: Event) => {\n event.stopPropagation();\n\n const val = (checkbox.getAttribute('value') ?? '').trim();\n\n if (!val) return;\n\n toggleCheckbox(val, event);\n };\n\n checkbox.addEventListener('change', handler);\n\n return () => {\n checkbox.removeEventListener('change', handler);\n };\n });\n\n return () => {\n for (const dispose of listeners) dispose();\n };\n });\n\n const legendId = createStableId('checkbox-group-legend');\n const errorId = `${legendId}-error`;\n const helperId = `${legendId}-helper`;\n const hasError = () => Boolean(props.error.value);\n const hasHelper = () => Boolean(props.helper.value) && !hasError();\n\n // Reactive, not a one-off `el.setAttribute()` inside the click handler: the host's `values`\n // attribute must stay in sync with the selection regardless of *why* it changed (a click,\n // or `reset()` on ancestor form reset — neither of which should need its own copy of this).\n bind({ attr: { size: props.size, values: choice.formValue } });\n\n return html`\n <fieldset\n role=\"group\"\n aria-required=\"${() => String(Boolean(props.required.value))}\"\n aria-invalid=\"${() => String(hasError())}\"\n aria-errormessage=\"${() => (hasError() ? errorId : null)}\"\n aria-describedby=\"${() => (hasError() ? errorId : hasHelper() ? helperId : null)}\">\n <legend id=\"${legendId}\" ?hidden=${() => !props.label.value}>\n ${props.label}${when(\n () => Boolean(props.required.value),\n () => html`\n <span aria-hidden=\"true\">*</span>\n `,\n )}\n </legend>\n <div class=\"checkbox-group-items\" part=\"items\">\n <slot></slot>\n </div>\n <div class=\"error-text\" id=\"${errorId}\" role=\"alert\" ?hidden=${() => !hasError()}>${props.error}</div>\n <div class=\"helper-text\" id=\"${helperId}\" ?hidden=${() => !hasHelper()}>${props.helper}</div>\n </fieldset>\n `;\n },\n styles: [disabledStateMixin, componentStyles],\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"checkbox-group.js","names":[],"sources":["../src/inputs/checkbox-group/checkbox-group.ts"],"sourcesContent":["import {\n bind,\n createContext,\n createStableId,\n define,\n getHost,\n html,\n onCleanup,\n prop,\n provide,\n useEmit,\n useField,\n useSlots,\n watchEffect,\n when,\n} from '@vielzeug/ore';\nimport { computed, type Readable, signal } from '@vielzeug/ripple';\nimport {\n type ChoiceChangeDetail,\n createChoiceField,\n getChoiceLabel,\n getLightChildrenByTag,\n lifecycleSignal,\n} from '../../core';\nimport { disablableBundle, sizableBundle, themableBundle } from '../../shared';\nimport { disabledStateMixin } from '../../styles';\nimport type { ComponentSize, ThemeColor } from '../../types';\nimport componentStyles from './checkbox-group.css?inline';\n\n// ─── Context ──────────────────────────────────────────────────────────────────\n\nexport type CheckboxGroupContext = {\n color: Readable<ThemeColor | undefined>;\n disabled: Readable<boolean>;\n size: Readable<ComponentSize | undefined>;\n toggle: (value: string, originalEvent?: Event) => void;\n values: Readable<string[]>;\n};\n\nexport const CHECKBOX_GROUP_CTX = createContext<CheckboxGroupContext>('CheckboxGroupContext');\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport type OreCheckboxGroupProps = {\n /** Theme color — propagated to all child ore-checkbox elements */\n color?: ThemeColor;\n /** Disable all checkboxes in the group */\n disabled?: boolean;\n /** Error message shown below the group */\n error?: string;\n /** Helper text shown below the group */\n helper?: string;\n /** Legend / label for the fieldset. Required for accessibility. */\n label?: string;\n /** Form field name used during submission */\n name?: string;\n /** Layout direction of the checkbox options */\n orientation?: 'vertical' | 'horizontal';\n /** Mark the group as required */\n required?: boolean;\n /** Size — propagated to all child ore-checkbox elements */\n size?: ComponentSize;\n /** Comma-separated list of currently checked values */\n values?: string;\n};\n\nexport type OreCheckboxGroupEvents = {\n change: ChoiceChangeDetail;\n};\n\n/**\n * A fieldset wrapper that groups `ore-checkbox` elements, provides shared\n * `color` and `size` via context, and manages multi-value selection state.\n *\n * @element ore-checkbox-group\n *\n * @attr {string} label - Legend text (required for a11y)\n * @attr {string} values - Comma-separated list of checked values\n * @attr {boolean} disabled - Disable all checkboxes in the group\n * @attr {string} error - Error message\n * @attr {string} helper - Helper text\n * @attr {string} name - Form field name\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} orientation - Layout: 'vertical' | 'horizontal'\n * @attr {boolean} required - Required field\n *\n * @fires change - Emitted when selection changes. detail: { value: string, values: string[], labels: string[], originalEvent?: Event }\n *\n * @slot - Place `ore-checkbox` elements here\n *\n * @cssprop --checkbox-group-direction - Flex direction of the items list ('row' | 'column')\n * @cssprop --checkbox-group-gap - Gap between checkbox items\n * @part items - Items container.\n * @example\n * ```html\n * <ore-checkbox-group name=\"fruits\" label=\"Favourite fruits\" required>\n * <ore-checkbox value=\"apple\">Apple</ore-checkbox>\n * <ore-checkbox value=\"banana\">Banana</ore-checkbox>\n * <ore-checkbox value=\"cherry\">Cherry</ore-checkbox>\n * </ore-checkbox-group>\n * <ore-checkbox-group name=\"options\" orientation=\"horizontal\" color=\"primary\">\n * <ore-checkbox value=\"a\">Option A</ore-checkbox>\n * <ore-checkbox value=\"b\">Option B</ore-checkbox>\n * </ore-checkbox-group>\n * ```\n */\nexport const CHECKBOX_GROUP_TAG = 'ore-checkbox-group' as const;\ndefine<OreCheckboxGroupProps>(CHECKBOX_GROUP_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n error: prop.string(),\n helper: prop.string(),\n label: prop.string(),\n name: prop.string(),\n orientation: prop.string('vertical'),\n required: prop.bool(false),\n // Not auto-reflected (`reflect: false`) — the derived, interaction-updated selection\n // (`choice.formValue`) is the single writer for this attribute, via `bind()` below;\n // letting `prop.string()`'s own default reflection also write the raw incoming value\n // would leave two effects racing to set the same attribute from different sources.\n values: { ...prop.string(), reflect: false },\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreCheckboxGroupEvents>();\n const slots = useSlots();\n const watch = watchEffect;\n\n const choice = createChoiceField({\n disabled: props.disabled,\n error: props.error,\n helper: props.helper,\n multiple: signal(true),\n prefix: 'checkbox-group',\n required: props.required,\n signal: lifecycleSignal(onCleanup),\n value: props.values,\n });\n\n choice.attachFormField(\n useField<string>({\n disabled: choice.disabled,\n onReset: choice.reset,\n toFormValue: (v) => v,\n validationMessage: choice.validationMessage,\n validity: choice.validity,\n value: choice.formValue,\n }),\n );\n\n const checkedValues = choice.selectedValues;\n\n const getCheckboxes = (): HTMLElement[] => getLightChildrenByTag(el, 'ore-checkbox');\n const getLabelForValue = (value: string): string => getChoiceLabel(getCheckboxes(), value);\n const emitChange = (originalEvent?: Event) => {\n const values = checkedValues.value;\n\n const labels = values.map(getLabelForValue);\n\n emit('change', { labels, originalEvent, values });\n };\n\n const toggleCheckbox = (val: string, originalEvent?: Event) => {\n choice.toggleValue(val);\n choice.triggerValidation('change');\n emitChange(originalEvent);\n };\n\n provide(CHECKBOX_GROUP_CTX, {\n color: props.color,\n disabled: computed(() => Boolean(props.disabled.value)),\n size: props.size,\n toggle: toggleCheckbox,\n values: checkedValues,\n });\n\n // Sync checked state + color/size/disabled onto slotted ore-checkbox children\n const syncChildren = () => {\n const values = checkedValues.value;\n const color = props.color.value;\n const size = props.size.value;\n const disabled = props.disabled.value;\n const checkboxes = getCheckboxes();\n\n for (const checkbox of checkboxes) {\n const val = checkbox.getAttribute('value') ?? '';\n\n checkbox.toggleAttribute('checked', values.includes(val));\n\n if (color) checkbox.setAttribute('color', color);\n else checkbox.removeAttribute('color');\n\n if (size) checkbox.setAttribute('size', size);\n else checkbox.removeAttribute('size');\n\n checkbox.toggleAttribute('disabled', Boolean(disabled));\n }\n };\n\n watch(() => {\n void slots.elements().value;\n syncChildren();\n });\n\n watch(() => {\n void slots.elements().value;\n\n const listeners = getCheckboxes().map((checkbox) => {\n const handler = (event: Event) => {\n event.stopPropagation();\n\n const val = (checkbox.getAttribute('value') ?? '').trim();\n\n if (!val) return;\n\n toggleCheckbox(val, event);\n };\n\n checkbox.addEventListener('change', handler);\n\n return () => {\n checkbox.removeEventListener('change', handler);\n };\n });\n\n return () => {\n for (const dispose of listeners) dispose();\n };\n });\n\n const legendId = createStableId('checkbox-group-legend');\n const errorId = `${legendId}-error`;\n const helperId = `${legendId}-helper`;\n const hasError = () => Boolean(props.error.value);\n const hasHelper = () => Boolean(props.helper.value) && !hasError();\n\n // Reactive, not a one-off `el.setAttribute()` inside the click handler: the host's `values`\n // attribute must stay in sync with the selection regardless of *why* it changed (a click,\n // or `reset()` on ancestor form reset — neither of which should need its own copy of this).\n bind({ attr: { size: props.size, values: choice.formValue } });\n\n return html`\n <fieldset\n role=\"group\"\n aria-required=\"${() => String(Boolean(props.required.value))}\"\n aria-invalid=\"${() => String(hasError())}\"\n aria-errormessage=\"${() => (hasError() ? errorId : null)}\"\n aria-describedby=\"${() => (hasError() ? errorId : hasHelper() ? helperId : null)}\">\n <legend id=\"${legendId}\" ?hidden=${() => !props.label.value}>\n ${props.label}${when(\n () => Boolean(props.required.value),\n () => html`\n <span aria-hidden=\"true\">*</span>\n `,\n )}\n </legend>\n <div class=\"checkbox-group-items\" part=\"items\">\n <slot></slot>\n </div>\n <div class=\"error-text\" id=\"${errorId}\" role=\"alert\" ?hidden=${() => !hasError()}>${props.error}</div>\n <div class=\"helper-text\" id=\"${helperId}\" ?hidden=${() => !hasHelper()}>${props.helper}</div>\n </fieldset>\n `;\n },\n styles: [disabledStateMixin, componentStyles],\n});\n"],"mappings":"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"}
|
package/dist/checkbox.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./styles/mixins/accessibility.css.cjs"),t=require("./styles/mixins/shape.css.cjs"),n=require("./styles/mixins/states.css.cjs"),r=require("./styles/mixins/theme.css.cjs"),i=require("./core/checkable.cjs"),a=require("./core/ore.cjs"),o=require("./shared/prop-bundles.cjs"),s=require("./shared/size-presets.cjs"),c=require("./inputs/shared/field-binding.cjs"),l=require("./inputs/shared/templates.cjs"),u=require("./checkbox-group.cjs"),d=require("./inputs/shared/native-field-event.cjs"),f=require("./inputs/checkbox/checkbox.css.cjs");let p=require("@vielzeug/ore"),m=require("@vielzeug/ripple");var h=`ore-checkbox`;(0,p.define)(h,{formAssociated:!0,props:{...o.themableBundle,...o.sizableBundle,...o.disablableBundle,checked:p.prop.bool(!1),error:p.prop.string(),helper:p.prop.string(),indeterminate:p.prop.bool(!1),name:p.prop.string(),required:p.prop.bool(!1),value:p.prop.string(`on`)},setup(e){let t=(0,p.getHost)(),n=(0,p.inject)(u.CHECKBOX_GROUP_CTX),r=i.createCheckable({checked:e.checked,clearIndeterminateFirst:!0,disabled:(0,m.computed)(()=>e.disabled.value||!!n?.disabled.value),error:e.error,group:n,helper:e.helper,indeterminate:e.indeterminate,onToggle:e=>{r.triggerValidation(`change`),d.setFieldChecked(t,e.checked),!n&&(d.dispatchNativeFieldEvent(t,`input`),d.dispatchNativeFieldEvent(t,`change`))},prefix:`checkbox`,required:e.required,signal:a.lifecycleSignal(p.onCleanup),value:e.value});r.attachFormField((0,p.useField)({disabled:r.disabled,onReset:r.reset,toFormValue:e=>e,validationMessage:r.validationMessage,validity:r.validity,value:r.checkableFormValue}));let{assistiveId:o,checked:s,disabled:f,errorText:h,handleClick:g,handleKeydown:_,helperText:v,indeterminate:y,labelId:b}=r;return d.defineFieldChecked(t,()=>s.value,e=>{s.value=e}),c.applyCheckableBinding(e.size,{assistiveId:o,checked:s,disabled:f,errorText:h,handleClick:g,handleKeydown:_,helperText:v,indeterminate:y,labelId:b,required:e.required},`checkbox`),p.html`
|
|
2
2
|
<div class="checkbox-wrapper" part="checkbox">
|
|
3
3
|
<div class="box" part="box">
|
|
4
4
|
<ore-icon class="checkmark" name="check" size="14" stroke-width="2" aria-hidden="true"></ore-icon>
|
|
@@ -7,5 +7,5 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
|
|
|
7
7
|
</div>
|
|
8
8
|
<span class="label" part="label" id="${b}"><slot></slot></span>
|
|
9
9
|
${l.renderHelperRegion(o,h,v)}
|
|
10
|
-
`},styles:[
|
|
10
|
+
`},styles:[r.colorThemeMixin,r.forcedColorsFormControlMixin,n.disabledStateMixin,e.coarsePointerMixin,t.sizeVariantMixin(s.CONTROL_SIZE_PRESET),f.default]}),exports.CHECKBOX_TAG=h;
|
|
11
11
|
//# sourceMappingURL=checkbox.cjs.map
|
package/dist/checkbox.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkbox.cjs","names":[],"sources":["../src/inputs/checkbox/checkbox.ts"],"sourcesContent":["import { define, html, inject,
|
|
1
|
+
{"version":3,"file":"checkbox.cjs","names":[],"sources":["../src/inputs/checkbox/checkbox.ts"],"sourcesContent":["import { define, getHost, html, inject, onCleanup, prop, useField } from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\nimport { createCheckable, lifecycleSignal } from '../../core';\nimport type { CheckableProps, ComponentSize, ThemeColor } from '../../types';\nimport '../../content/icon/icon';\nimport { CONTROL_SIZE_PRESET, disablableBundle, sizableBundle, themableBundle } from '../../shared';\nimport {\n coarsePointerMixin,\n colorThemeMixin,\n disabledStateMixin,\n forcedColorsFormControlMixin,\n sizeVariantMixin,\n} from '../../styles';\nimport { CHECKBOX_GROUP_CTX } from '../checkbox-group/checkbox-group';\nimport { applyCheckableBinding } from '../shared/field-binding';\nimport { defineFieldChecked, dispatchNativeFieldEvent, setFieldChecked } from '../shared/native-field-event';\nimport { renderHelperRegion } from '../shared/templates';\nimport componentStyles from './checkbox.css?inline';\n\nexport type OreCheckboxEvents = {\n change: Event;\n input: Event;\n};\n\nexport type OreCheckboxProps = CheckableProps & {\n /** Theme color */\n color?: ThemeColor;\n /** Disable interaction */\n disabled?: boolean;\n /** Error message (marks field as invalid) */\n error?: string;\n /** Helper text displayed below the checkbox */\n helper?: string;\n /** Indeterminate state (partially checked) */\n indeterminate?: boolean;\n /** Require this checkbox to be checked for native form validation (e.g. a consent checkbox) */\n required?: boolean;\n /** Component size */\n size?: ComponentSize;\n};\n\n/**\n * A customizable checkbox component with theme colors, sizes, and indeterminate state support.\n *\n * @element ore-checkbox\n *\n * @attr {boolean} checked - Checked state\n * @attr {boolean} disabled - Disable checkbox interaction\n * @attr {boolean} indeterminate - Indeterminate (partially checked) state\n * @attr {boolean} required - Require this checkbox to be checked for native form validation\n * @attr {string} value - Field value submitted with forms\n * @attr {string} name - Form field name\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - Checkbox size: 'sm' | 'md' | 'lg'\n * @attr {string} error - Error message (marks field as invalid)\n * @attr {string} helper - Helper text displayed below the checkbox\n *\n * @fires input - Emitted when checkbox is toggled.\n * @fires change - Emitted when checkbox is toggled.\n *\n * @slot - Checkbox label text\n *\n * @cssprop --checkbox-size - Control size (width and height)\n * @cssprop --checkbox-radius - Control border radius\n * @cssprop --checkbox-bg - Unchecked background color\n * @cssprop --checkbox-border-color - Unchecked border color\n * @cssprop --checkbox-checked-bg - Checked/indeterminate background color\n * @cssprop --checkbox-color - Checkmark icon color\n * @cssprop --checkbox-font-size - Label font size\n * @part checkbox - The checkbox wrapper element\n * @part box - The visual checkbox box\n * @part label - The label element\n * @part helper-text - The helper/error text element\n *\n * @example\n * ```html\n * <ore-checkbox name=\"agree\" required>I agree to the terms</ore-checkbox>\n * <ore-checkbox checked color=\"primary\" size=\"lg\">Enabled by default</ore-checkbox>\n * <ore-checkbox error=\"This field is required\" helper=\"Check to continue\">Accept</ore-checkbox>\n * ```\n */\nexport const CHECKBOX_TAG = 'ore-checkbox' as const;\ndefine<OreCheckboxProps>(CHECKBOX_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n checked: prop.bool(false),\n error: prop.string(),\n helper: prop.string(),\n indeterminate: prop.bool(false),\n name: prop.string(),\n required: prop.bool(false),\n value: prop.string('on'),\n },\n setup(props) {\n const el = getHost();\n\n const groupCtx = inject(CHECKBOX_GROUP_CTX);\n\n const checkable = createCheckable({\n checked: props.checked,\n clearIndeterminateFirst: true,\n disabled: computed(() => props.disabled.value || Boolean(groupCtx?.disabled.value)),\n error: props.error,\n group: groupCtx,\n helper: props.helper,\n indeterminate: props.indeterminate,\n onToggle: (payload) => {\n checkable.triggerValidation('change');\n setFieldChecked(el, payload.checked);\n\n // In a checkbox-group, the group owns change emission/state updates.\n // Emitting here would bubble to the group and toggle a second time.\n if (groupCtx) return;\n\n dispatchNativeFieldEvent(el, 'input');\n dispatchNativeFieldEvent(el, 'change');\n },\n prefix: 'checkbox',\n required: props.required,\n signal: lifecycleSignal(onCleanup),\n value: props.value,\n });\n\n checkable.attachFormField(\n useField<string | null>({\n disabled: checkable.disabled,\n onReset: checkable.reset,\n toFormValue: (v) => v,\n validationMessage: checkable.validationMessage,\n validity: checkable.validity,\n value: checkable.checkableFormValue,\n }),\n );\n\n const {\n assistiveId,\n checked,\n disabled,\n errorText,\n handleClick,\n handleKeydown,\n helperText,\n indeterminate,\n labelId,\n } = checkable;\n\n defineFieldChecked(\n el,\n () => checked.value,\n (value) => {\n checked.value = value;\n },\n );\n\n applyCheckableBinding(\n props.size,\n {\n assistiveId,\n checked,\n disabled,\n errorText,\n handleClick,\n handleKeydown,\n helperText,\n indeterminate,\n labelId,\n required: props.required,\n },\n 'checkbox',\n );\n\n return html`\n <div class=\"checkbox-wrapper\" part=\"checkbox\">\n <div class=\"box\" part=\"box\">\n <ore-icon class=\"checkmark\" name=\"check\" size=\"14\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n <ore-icon class=\"dash\" name=\"minus\" size=\"14\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </div>\n </div>\n <span class=\"label\" part=\"label\" id=\"${labelId}\"><slot></slot></span>\n ${renderHelperRegion(assistiveId, errorText, helperText)}\n `;\n },\n styles: [\n colorThemeMixin,\n forcedColorsFormControlMixin,\n disabledStateMixin,\n coarsePointerMixin,\n sizeVariantMixin(CONTROL_SIZE_PRESET),\n componentStyles,\n ],\n});\n"],"mappings":"uqBAiFA,IAAa,EAAe,gBAC5B,EAAA,EAAA,OAAA,CAAyB,EAAc,CACrC,eAAgB,GAChB,MAAO,CACL,GAAG,EAAA,eACH,GAAG,EAAA,cACH,GAAG,EAAA,iBACH,QAAS,EAAA,KAAK,KAAK,EAAK,EACxB,MAAO,EAAA,KAAK,OAAO,EACnB,OAAQ,EAAA,KAAK,OAAO,EACpB,cAAe,EAAA,KAAK,KAAK,EAAK,EAC9B,KAAM,EAAA,KAAK,OAAO,EAClB,SAAU,EAAA,KAAK,KAAK,EAAK,EACzB,MAAO,EAAA,KAAK,OAAO,IAAI,CACzB,EACA,MAAM,EAAO,CACX,IAAM,GAAA,EAAK,EAAA,QAAA,CAAQ,EAEb,GAAA,EAAW,EAAA,OAAA,CAAO,EAAA,kBAAkB,EAEpC,EAAY,EAAA,gBAAgB,CAChC,QAAS,EAAM,QACf,wBAAyB,GACzB,UAAA,EAAU,EAAA,SAAA,KAAe,EAAM,SAAS,OAAS,EAAQ,GAAU,SAAS,KAAM,EAClF,MAAO,EAAM,MACb,MAAO,EACP,OAAQ,EAAM,OACd,cAAe,EAAM,cACrB,SAAW,GAAY,CACrB,EAAU,kBAAkB,QAAQ,EACpC,EAAA,gBAAgB,EAAI,EAAQ,OAAO,EAI/B,KAEJ,EAAA,yBAAyB,EAAI,OAAO,EACpC,EAAA,yBAAyB,EAAI,QAAQ,EACvC,EACA,OAAQ,WACR,SAAU,EAAM,SAChB,OAAQ,EAAA,gBAAgB,EAAA,SAAS,EACjC,MAAO,EAAM,KACf,CAAC,EAED,EAAU,iBAAA,EACR,EAAA,SAAA,CAAwB,CACtB,SAAU,EAAU,SACpB,QAAS,EAAU,MACnB,YAAc,GAAM,EACpB,kBAAmB,EAAU,kBAC7B,SAAU,EAAU,SACpB,MAAO,EAAU,kBACnB,CAAC,CACH,EAEA,GAAM,CACJ,cACA,UACA,WACA,YACA,cACA,gBACA,aACA,gBACA,WACE,EA2BJ,OAzBA,EAAA,mBACE,MACM,EAAQ,MACb,GAAU,CACT,EAAQ,MAAQ,CAClB,CACF,EAEA,EAAA,sBACE,EAAM,KACN,CACE,cACA,UACA,WACA,YACA,cACA,gBACA,aACA,gBACA,UACA,SAAU,EAAM,QAClB,EACA,UACF,EAEO,EAAA,IAAI;;;;;;;6CAO8B,EAAQ;QAC7C,EAAA,mBAAmB,EAAa,EAAW,CAAU,EAAE;KAE7D,EACA,OAAQ,CACN,EAAA,gBACA,EAAA,6BACA,EAAA,mBACA,EAAA,mBACA,EAAA,iBAAiB,EAAA,mBAAmB,EACpC,EAAA,OACF,CACF,CAAC"}
|