@exsto/ds 0.0.1-rc.2 → 0.0.1-rc.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +171 -28
- package/dist/date-picker.js +2 -0
- package/dist/ds/src/date-picker.d.ts +9 -0
- package/dist/ds/src/file-input.d.ts +9 -0
- package/dist/ds/src/index.d.ts +2 -3
- package/dist/ds/src/rich-text-editor.d.ts +8 -0
- package/dist/ds/src/time-field.d.ts +9 -0
- package/dist/file-input.js +2 -0
- package/dist/index.js +79 -2
- package/dist/rich-text-editor.js +4 -0
- package/dist/source-hash.txt +1 -0
- package/dist/styles.css +1201 -404
- package/dist/theme.css +125 -7
- package/dist/time-field.js +2 -0
- package/dist/ui/src/components/edyn/animated-number/animated-number.d.ts +30 -0
- package/dist/ui/src/components/edyn/animated-number/animated-number.js +108 -0
- package/dist/ui/src/components/edyn/animated-number/animated-number.js.map +1 -0
- package/dist/ui/src/components/edyn/animated-number/animated-number.test.d.ts +9 -0
- package/dist/ui/src/components/edyn/animated-number/index.d.ts +1 -0
- package/dist/ui/src/components/edyn/audio-player/audio-player.d.ts +3 -2
- package/dist/ui/src/components/edyn/audio-player/audio-player.js +86 -0
- package/dist/ui/src/components/edyn/audio-player/audio-player.js.map +1 -0
- package/dist/ui/src/components/edyn/date-picker/date-picker.d.ts +86 -0
- package/dist/ui/src/components/edyn/date-picker/date-picker.js +302 -0
- package/dist/ui/src/components/edyn/date-picker/date-picker.js.map +1 -0
- package/dist/ui/src/components/edyn/date-picker/date-picker.state.test.d.ts +9 -0
- package/dist/ui/src/components/edyn/date-picker/date-text.d.ts +40 -0
- package/dist/ui/src/components/edyn/date-picker/date-text.js +105 -0
- package/dist/ui/src/components/edyn/date-picker/date-text.js.map +1 -0
- package/dist/ui/src/components/edyn/date-picker/index.d.ts +2 -0
- package/dist/ui/src/components/edyn/date-range-picker/date-range-picker.d.ts +28 -0
- package/dist/ui/src/components/edyn/date-range-picker/date-range-picker.js +70 -0
- package/dist/ui/src/components/edyn/date-range-picker/date-range-picker.js.map +1 -0
- package/dist/ui/src/components/edyn/date-range-picker/date-range-picker.test.d.ts +9 -0
- package/dist/ui/src/components/edyn/date-range-picker/index.d.ts +1 -0
- package/dist/ui/src/components/edyn/file-input/file-input.d.ts +90 -0
- package/dist/ui/src/components/edyn/file-input/file-input.js +261 -0
- package/dist/ui/src/components/edyn/file-input/file-input.js.map +1 -0
- package/dist/ui/src/components/edyn/file-input/file-input.test.d.ts +8 -0
- package/dist/ui/src/components/edyn/file-input/index.d.ts +1 -0
- package/dist/ui/src/components/edyn/initials-avatar/index.d.ts +1 -0
- package/dist/ui/src/components/edyn/initials-avatar/initials-avatar.d.ts +54 -0
- package/dist/ui/src/components/edyn/initials-avatar/initials-avatar.js +86 -0
- package/dist/ui/src/components/edyn/initials-avatar/initials-avatar.js.map +1 -0
- package/dist/ui/src/components/edyn/initials-avatar/initials-avatar.test.d.ts +10 -0
- package/dist/ui/src/components/edyn/multi-select/index.d.ts +1 -0
- package/dist/ui/src/components/edyn/multi-select/multi-select.d.ts +117 -0
- package/dist/ui/src/components/edyn/multi-select/multi-select.js +342 -0
- package/dist/ui/src/components/edyn/multi-select/multi-select.js.map +1 -0
- package/dist/ui/src/components/edyn/multi-select/multi-select.test.d.ts +9 -0
- package/dist/ui/src/components/edyn/presence/index.d.ts +1 -0
- package/dist/ui/src/components/edyn/presence/presence.d.ts +15 -0
- package/dist/ui/src/components/edyn/presence/presence.js +58 -0
- package/dist/ui/src/components/edyn/presence/presence.js.map +1 -0
- package/dist/ui/src/components/edyn/presence/presence.test.d.ts +8 -0
- package/dist/ui/src/components/edyn/progress-line/index.d.ts +1 -0
- package/dist/ui/src/components/edyn/progress-line/progress-line.d.ts +23 -0
- package/dist/ui/src/components/edyn/progress-line/progress-line.js +100 -0
- package/dist/ui/src/components/edyn/progress-line/progress-line.js.map +1 -0
- package/dist/ui/src/components/edyn/progress-line/progress-line.test.d.ts +9 -0
- package/dist/ui/src/components/edyn/rich-text-content/allow-list.d.ts +11 -0
- package/dist/ui/src/components/edyn/rich-text-content/allow-list.js +37 -0
- package/dist/ui/src/components/edyn/rich-text-content/allow-list.js.map +1 -0
- package/dist/ui/src/components/edyn/rich-text-content/index.d.ts +2 -0
- package/dist/ui/src/components/edyn/rich-text-content/rich-text-content.d.ts +22 -0
- package/dist/ui/src/components/edyn/rich-text-content/rich-text-content.js +124 -0
- package/dist/ui/src/components/edyn/rich-text-content/rich-text-content.js.map +1 -0
- package/dist/ui/src/components/edyn/rich-text-content/rich-text-content.test.d.ts +8 -0
- package/dist/ui/src/components/edyn/rich-text-editor/extensions.d.ts +18 -0
- package/dist/ui/src/components/edyn/rich-text-editor/extensions.js +124 -0
- package/dist/ui/src/components/edyn/rich-text-editor/extensions.js.map +1 -0
- package/dist/ui/src/components/edyn/rich-text-editor/index.d.ts +3 -0
- package/dist/ui/src/components/edyn/rich-text-editor/mention-list.d.ts +17 -0
- package/dist/ui/src/components/edyn/rich-text-editor/mention-list.js +232 -0
- package/dist/ui/src/components/edyn/rich-text-editor/mention-list.js.map +1 -0
- package/dist/ui/src/components/edyn/rich-text-editor/rich-text-editor.d.ts +53 -0
- package/dist/ui/src/components/edyn/rich-text-editor/rich-text-editor.js +244 -0
- package/dist/ui/src/components/edyn/rich-text-editor/rich-text-editor.js.map +1 -0
- package/dist/ui/src/components/edyn/rich-text-editor/rich-text-editor.test.d.ts +6 -0
- package/dist/ui/src/components/edyn/rich-text-editor/serialize.d.ts +13 -0
- package/dist/ui/src/components/edyn/rich-text-editor/serialize.js +55 -0
- package/dist/ui/src/components/edyn/rich-text-editor/serialize.js.map +1 -0
- package/dist/ui/src/components/edyn/rich-text-editor/sync.d.ts +19 -0
- package/dist/ui/src/components/edyn/rich-text-editor/sync.js +34 -0
- package/dist/ui/src/components/edyn/rich-text-editor/sync.js.map +1 -0
- package/dist/ui/src/components/edyn/rich-text-editor/sync.test.d.ts +11 -0
- package/dist/ui/src/components/edyn/rich-text-editor/toolbar.d.ts +20 -0
- package/dist/ui/src/components/edyn/rich-text-editor/toolbar.js +235 -0
- package/dist/ui/src/components/edyn/rich-text-editor/toolbar.js.map +1 -0
- package/dist/ui/src/components/edyn/rich-text-editor/types.d.ts +68 -0
- package/dist/ui/src/components/edyn/rich-text-editor/types.js +26 -0
- package/dist/ui/src/components/edyn/rich-text-editor/types.js.map +1 -0
- package/dist/ui/src/components/edyn/time-field/index.d.ts +1 -0
- package/dist/ui/src/components/edyn/time-field/time-field.d.ts +85 -0
- package/dist/ui/src/components/edyn/time-field/time-field.js +337 -0
- package/dist/ui/src/components/edyn/time-field/time-field.js.map +1 -0
- package/dist/ui/src/components/edyn/time-field/time-field.test.d.ts +8 -0
- package/dist/ui/src/components/edyn/video-player/video-player.d.ts +2 -2
- package/dist/ui/src/components/edyn/video-player/video-player.js +132 -0
- package/dist/ui/src/components/edyn/video-player/video-player.js.map +1 -0
- package/dist/ui/src/components/forwarded-props.test.d.ts +8 -0
- package/dist/ui/src/components/ui/accordion/accordion.d.ts +9 -8
- package/dist/ui/src/components/ui/accordion/accordion.js +83 -0
- package/dist/ui/src/components/ui/accordion/accordion.js.map +1 -0
- package/dist/ui/src/components/ui/alert/alert.js +47 -0
- package/dist/ui/src/components/ui/alert/alert.js.map +1 -0
- package/dist/ui/src/components/ui/alert-dialog/alert-dialog.js +97 -0
- package/dist/ui/src/components/ui/alert-dialog/alert-dialog.js.map +1 -0
- package/dist/ui/src/components/ui/aspect-ratio/aspect-ratio.js +15 -0
- package/dist/ui/src/components/ui/aspect-ratio/aspect-ratio.js.map +1 -0
- package/dist/ui/src/components/ui/attachment/attachment.d.ts +1 -1
- package/dist/ui/src/components/ui/attachment/attachment.js +105 -0
- package/dist/ui/src/components/ui/attachment/attachment.js.map +1 -0
- package/dist/ui/src/components/ui/avatar/avatar.js +51 -0
- package/dist/ui/src/components/ui/avatar/avatar.js.map +1 -0
- package/dist/ui/src/components/ui/badge/badge.d.ts +1 -1
- package/dist/ui/src/components/ui/badge/badge.js +47 -0
- package/dist/ui/src/components/ui/badge/badge.js.map +1 -0
- package/dist/ui/src/components/ui/breadcrumb/breadcrumb.js +73 -0
- package/dist/ui/src/components/ui/breadcrumb/breadcrumb.js.map +1 -0
- package/dist/ui/src/components/ui/bubble/bubble.js +74 -0
- package/dist/ui/src/components/ui/bubble/bubble.js.map +1 -0
- package/dist/ui/src/components/ui/button/button.behavior.test.d.ts +8 -0
- package/dist/ui/src/components/ui/button/button.d.ts +1 -1
- package/dist/ui/src/components/ui/button/button.js +68 -0
- package/dist/ui/src/components/ui/button/button.js.map +1 -0
- package/dist/ui/src/components/ui/button-group/button-group.js +37 -0
- package/dist/ui/src/components/ui/button-group/button-group.js.map +1 -0
- package/dist/ui/src/components/ui/calendar/calendar.behavior.test.d.ts +9 -0
- package/dist/ui/src/components/ui/calendar/calendar.d.ts +1 -1
- package/dist/ui/src/components/ui/calendar/calendar.js +141 -0
- package/dist/ui/src/components/ui/calendar/calendar.js.map +1 -0
- package/dist/ui/src/components/ui/card/card.js +57 -0
- package/dist/ui/src/components/ui/card/card.js.map +1 -0
- package/dist/ui/src/components/ui/carousel/carousel.js +136 -0
- package/dist/ui/src/components/ui/carousel/carousel.js.map +1 -0
- package/dist/ui/src/components/ui/chart/chart.js +168 -0
- package/dist/ui/src/components/ui/chart/chart.js.map +1 -0
- package/dist/ui/src/components/ui/checkbox/checkbox.js +21 -0
- package/dist/ui/src/components/ui/checkbox/checkbox.js.map +1 -0
- package/dist/ui/src/components/ui/collapsible/collapsible.js +26 -0
- package/dist/ui/src/components/ui/collapsible/collapsible.js.map +1 -0
- package/dist/ui/src/components/ui/combobox/combobox.d.ts +15 -1
- package/dist/ui/src/components/ui/combobox/combobox.js +111 -0
- package/dist/ui/src/components/ui/combobox/combobox.js.map +1 -0
- package/dist/ui/src/components/ui/command/command.d.ts +17 -1
- package/dist/ui/src/components/ui/command/command.js +118 -0
- package/dist/ui/src/components/ui/command/command.js.map +1 -0
- package/dist/ui/src/components/ui/context-menu/context-menu.d.ts +1 -1
- package/dist/ui/src/components/ui/context-menu/context-menu.js +145 -0
- package/dist/ui/src/components/ui/context-menu/context-menu.js.map +1 -0
- package/dist/ui/src/components/ui/dialog/dialog.js +94 -0
- package/dist/ui/src/components/ui/dialog/dialog.js.map +1 -0
- package/dist/ui/src/components/ui/direction/direction.js +2 -0
- package/dist/ui/src/components/ui/drawer/drawer.js +88 -0
- package/dist/ui/src/components/ui/drawer/drawer.js.map +1 -0
- package/dist/ui/src/components/ui/dropdown-menu/dropdown-menu.d.ts +12 -1
- package/dist/ui/src/components/ui/dropdown-menu/dropdown-menu.js +159 -0
- package/dist/ui/src/components/ui/dropdown-menu/dropdown-menu.js.map +1 -0
- package/dist/ui/src/components/ui/empty/empty.d.ts +5 -1
- package/dist/ui/src/components/ui/empty/empty.js +72 -0
- package/dist/ui/src/components/ui/empty/empty.js.map +1 -0
- package/dist/ui/src/components/ui/field/field.js +36 -0
- package/dist/ui/src/components/ui/field/field.js.map +1 -0
- package/dist/ui/src/components/ui/hover-card/hover-card.js +39 -0
- package/dist/ui/src/components/ui/hover-card/hover-card.js.map +1 -0
- package/dist/ui/src/components/ui/indicator/indicator.js +79 -0
- package/dist/ui/src/components/ui/indicator/indicator.js.map +1 -0
- package/dist/ui/src/components/ui/input/input.js +16 -0
- package/dist/ui/src/components/ui/input/input.js.map +1 -0
- package/dist/ui/src/components/ui/input-group/input-group.d.ts +1 -1
- package/dist/ui/src/components/ui/input-group/input-group.js +77 -0
- package/dist/ui/src/components/ui/input-group/input-group.js.map +1 -0
- package/dist/ui/src/components/ui/input-otp/input-otp.js +48 -0
- package/dist/ui/src/components/ui/input-otp/input-otp.js.map +1 -0
- package/dist/ui/src/components/ui/item/item.d.ts +1 -1
- package/dist/ui/src/components/ui/item/item.js +122 -0
- package/dist/ui/src/components/ui/item/item.js.map +1 -0
- package/dist/ui/src/components/ui/kbd/kbd.js +21 -0
- package/dist/ui/src/components/ui/kbd/kbd.js.map +1 -0
- package/dist/ui/src/components/ui/label/label.js +14 -0
- package/dist/ui/src/components/ui/label/label.js.map +1 -0
- package/dist/ui/src/components/ui/marker/marker.js +44 -0
- package/dist/ui/src/components/ui/marker/marker.js.map +1 -0
- package/dist/ui/src/components/ui/menubar/menubar.js +140 -0
- package/dist/ui/src/components/ui/menubar/menubar.js.map +1 -0
- package/dist/ui/src/components/ui/message/message.js +50 -0
- package/dist/ui/src/components/ui/message/message.js.map +1 -0
- package/dist/ui/src/components/ui/message-scroller/message-scroller.js +61 -0
- package/dist/ui/src/components/ui/message-scroller/message-scroller.js.map +1 -0
- package/dist/ui/src/components/ui/native-select/native-select.js +39 -0
- package/dist/ui/src/components/ui/native-select/native-select.js.map +1 -0
- package/dist/ui/src/components/ui/navigation-menu/navigation-menu.js +87 -0
- package/dist/ui/src/components/ui/navigation-menu/navigation-menu.js.map +1 -0
- package/dist/ui/src/components/ui/pagination/pagination.d.ts +3 -2
- package/dist/ui/src/components/ui/pagination/pagination.js +104 -0
- package/dist/ui/src/components/ui/pagination/pagination.js.map +1 -0
- package/dist/ui/src/components/ui/popover/popover.d.ts +1 -1
- package/dist/ui/src/components/ui/popover/popover.js +59 -0
- package/dist/ui/src/components/ui/popover/popover.js.map +1 -0
- package/dist/ui/src/components/ui/progress/progress.behavior.test.d.ts +8 -0
- package/dist/ui/src/components/ui/progress/progress.d.ts +43 -1
- package/dist/ui/src/components/ui/progress/progress.js +70 -0
- package/dist/ui/src/components/ui/progress/progress.js.map +1 -0
- package/dist/ui/src/components/ui/questionnaire/questionnaire.js +171 -0
- package/dist/ui/src/components/ui/questionnaire/questionnaire.js.map +1 -0
- package/dist/ui/src/components/ui/radio-group/radio-group.js +29 -0
- package/dist/ui/src/components/ui/radio-group/radio-group.js.map +1 -0
- package/dist/ui/src/components/ui/resizable/resizable.js +29 -0
- package/dist/ui/src/components/ui/resizable/resizable.js.map +1 -0
- package/dist/ui/src/components/ui/scroll-area/index.d.ts +1 -0
- package/dist/ui/src/components/ui/scroll-area/popup-list-scroll.d.ts +13 -0
- package/dist/ui/src/components/ui/scroll-area/popup-list-scroll.js +69 -0
- package/dist/ui/src/components/ui/scroll-area/popup-list-scroll.js.map +1 -0
- package/dist/ui/src/components/ui/scroll-area/scroll-area.behavior.test.d.ts +12 -0
- package/dist/ui/src/components/ui/scroll-area/scroll-area.d.ts +57 -6
- package/dist/ui/src/components/ui/scroll-area/scroll-area.js +125 -0
- package/dist/ui/src/components/ui/scroll-area/scroll-area.js.map +1 -0
- package/dist/ui/src/components/ui/select/select.js +97 -0
- package/dist/ui/src/components/ui/select/select.js.map +1 -0
- package/dist/ui/src/components/ui/separator/separator.behavior.test.d.ts +14 -0
- package/dist/ui/src/components/ui/separator/separator.d.ts +14 -0
- package/dist/ui/src/components/ui/separator/separator.js +30 -0
- package/dist/ui/src/components/ui/separator/separator.js.map +1 -0
- package/dist/ui/src/components/ui/sheet/sheet.d.ts +8 -0
- package/dist/ui/src/components/ui/sheet/sheet.js +99 -0
- package/dist/ui/src/components/ui/sheet/sheet.js.map +1 -0
- package/dist/ui/src/components/ui/sidebar/sidebar.js +383 -0
- package/dist/ui/src/components/ui/sidebar/sidebar.js.map +1 -0
- package/dist/ui/src/components/ui/skeleton/skeleton.js +14 -0
- package/dist/ui/src/components/ui/skeleton/skeleton.js.map +1 -0
- package/dist/ui/src/components/ui/slider/slider.js +49 -0
- package/dist/ui/src/components/ui/slider/slider.js.map +1 -0
- package/dist/ui/src/components/ui/spinner/spinner.js +28 -0
- package/dist/ui/src/components/ui/spinner/spinner.js.map +1 -0
- package/dist/ui/src/components/ui/switch/switch.js +20 -0
- package/dist/ui/src/components/ui/switch/switch.js.map +1 -0
- package/dist/ui/src/components/ui/table/table.behavior.test.d.ts +4 -5
- package/dist/ui/src/components/ui/table/table.d.ts +15 -1
- package/dist/ui/src/components/ui/table/table.js +81 -0
- package/dist/ui/src/components/ui/table/table.js.map +1 -0
- package/dist/ui/src/components/ui/tabs/tabs.d.ts +14 -8
- package/dist/ui/src/components/ui/tabs/tabs.js +115 -0
- package/dist/ui/src/components/ui/tabs/tabs.js.map +1 -0
- package/dist/ui/src/components/ui/textarea/textarea.js +14 -0
- package/dist/ui/src/components/ui/textarea/textarea.js.map +1 -0
- package/dist/ui/src/components/ui/toast/toast.js +124 -0
- package/dist/ui/src/components/ui/toast/toast.js.map +1 -0
- package/dist/ui/src/components/ui/toggle/toggle.js +37 -0
- package/dist/ui/src/components/ui/toggle/toggle.js.map +1 -0
- package/dist/ui/src/components/ui/toggle-group/toggle-group.js +56 -0
- package/dist/ui/src/components/ui/toggle-group/toggle-group.js.map +1 -0
- package/dist/ui/src/components/ui/tooltip/tooltip.js +43 -0
- package/dist/ui/src/components/ui/tooltip/tooltip.js.map +1 -0
- package/dist/ui/src/hooks/use-holds-focusable.d.ts +3 -0
- package/dist/ui/src/hooks/use-holds-focusable.js +33 -0
- package/dist/ui/src/hooks/use-holds-focusable.js.map +1 -0
- package/dist/ui/src/hooks/use-media-player.js +140 -0
- package/dist/ui/src/hooks/use-media-player.js.map +1 -0
- package/dist/ui/src/hooks/use-merged-refs.js +18 -0
- package/dist/ui/src/hooks/use-merged-refs.js.map +1 -0
- package/dist/ui/src/hooks/use-mobile.js +20 -0
- package/dist/ui/src/hooks/use-mobile.js.map +1 -0
- package/dist/ui/src/index.d.ts +8 -0
- package/dist/ui/src/lib/first-weekday.d.ts +6 -0
- package/dist/ui/src/lib/first-weekday.js +34 -0
- package/dist/ui/src/lib/first-weekday.js.map +1 -0
- package/dist/ui/src/lib/focus-guards.d.ts +2 -0
- package/dist/ui/src/lib/focus-guards.js +44 -0
- package/dist/ui/src/lib/focus-guards.js.map +1 -0
- package/dist/ui/src/lib/focus-ring.test.d.ts +8 -0
- package/dist/ui/src/lib/popup-list.d.ts +75 -0
- package/dist/ui/src/lib/popup-list.js +48 -0
- package/dist/ui/src/lib/popup-list.js.map +1 -0
- package/dist/ui/src/lib/popup-list.test.d.ts +10 -0
- package/dist/ui/src/lib/utils.js +21 -0
- package/dist/ui/src/lib/utils.js.map +1 -0
- package/package.json +36 -8
- package/dist/chunks/toggle-group-ByNq8g7H.js +0 -4263
- package/dist/chunks/toggle-group-ByNq8g7H.js.map +0 -1
- package/dist/dom/src/context.d.ts +0 -34
- package/dist/dom/src/define-element.d.ts +0 -11
- package/dist/dom/src/field-control.d.ts +0 -5
- package/dist/dom/src/index.d.ts +0 -6
- package/dist/dom/src/mode.d.ts +0 -8
- package/dist/dom/src/styles.d.ts +0 -6
- package/dist/dom/src/theme-state.d.ts +0 -1
- package/dist/dom/src/types.d.ts +0 -65
- package/dist/ds/src/elements.d.ts +0 -12
- package/dist/elements/src/edx-accordion.d.ts +0 -14
- package/dist/elements/src/edx-accordion.test.d.ts +0 -1
- package/dist/elements/src/edx-alert.d.ts +0 -14
- package/dist/elements/src/edx-audio-player.d.ts +0 -11
- package/dist/elements/src/edx-avatar.d.ts +0 -10
- package/dist/elements/src/edx-badge.d.ts +0 -12
- package/dist/elements/src/edx-breadcrumb.d.ts +0 -11
- package/dist/elements/src/edx-button-group.d.ts +0 -7
- package/dist/elements/src/edx-button.d.ts +0 -20
- package/dist/elements/src/edx-calendar.d.ts +0 -21
- package/dist/elements/src/edx-card.d.ts +0 -8
- package/dist/elements/src/edx-checkbox.d.ts +0 -18
- package/dist/elements/src/edx-combobox.d.ts +0 -28
- package/dist/elements/src/edx-content-components.d.ts +0 -2
- package/dist/elements/src/edx-dialog.d.ts +0 -20
- package/dist/elements/src/edx-drawer.d.ts +0 -21
- package/dist/elements/src/edx-dropdown-menu.d.ts +0 -29
- package/dist/elements/src/edx-field.d.ts +0 -9
- package/dist/elements/src/edx-field.test.d.ts +0 -1
- package/dist/elements/src/edx-indicator.d.ts +0 -14
- package/dist/elements/src/edx-input-group.d.ts +0 -32
- package/dist/elements/src/edx-input-otp.d.ts +0 -19
- package/dist/elements/src/edx-input.d.ts +0 -31
- package/dist/elements/src/edx-interactive-components.d.ts +0 -2
- package/dist/elements/src/edx-label.d.ts +0 -6
- package/dist/elements/src/edx-pagination.d.ts +0 -8
- package/dist/elements/src/edx-popover.d.ts +0 -24
- package/dist/elements/src/edx-progress.d.ts +0 -10
- package/dist/elements/src/edx-radio-group.d.ts +0 -22
- package/dist/elements/src/edx-radio-group.test.d.ts +0 -1
- package/dist/elements/src/edx-scroll-area.d.ts +0 -15
- package/dist/elements/src/edx-scroll-area.test.d.ts +0 -1
- package/dist/elements/src/edx-select.d.ts +0 -34
- package/dist/elements/src/edx-separator.d.ts +0 -10
- package/dist/elements/src/edx-skeleton.d.ts +0 -8
- package/dist/elements/src/edx-slider.d.ts +0 -17
- package/dist/elements/src/edx-slider.test.d.ts +0 -1
- package/dist/elements/src/edx-switch.d.ts +0 -18
- package/dist/elements/src/edx-table.d.ts +0 -13
- package/dist/elements/src/edx-table.test.d.ts +0 -1
- package/dist/elements/src/edx-tabs.d.ts +0 -15
- package/dist/elements/src/edx-tabs.test.d.ts +0 -1
- package/dist/elements/src/edx-textarea.d.ts +0 -25
- package/dist/elements/src/edx-toggle-group.d.ts +0 -27
- package/dist/elements/src/edx-toggle-group.test.d.ts +0 -1
- package/dist/elements/src/edx-toggle.d.ts +0 -18
- package/dist/elements/src/edx-tooltip.d.ts +0 -28
- package/dist/elements/src/edx-video-player.d.ts +0 -16
- package/dist/elements/src/field-control-bridge.d.ts +0 -7
- package/dist/elements/src/index.d.ts +0 -14
- package/dist/elements/src/projected-content.test.d.ts +0 -1
- package/dist/elements/src/registry.d.ts +0 -39
- package/dist/elements/src/registry.test.d.ts +0 -1
- package/dist/elements.js +0 -4020
- package/dist/elements.js.map +0 -1
- /package/dist/{dom/src/define-element.test.d.ts → ui/src/components/edyn/date-picker/date-text.test.d.ts} +0 -0
- /package/dist/{dom/src/native-slot.test.d.ts → ui/src/lib/first-weekday.test.d.ts} +0 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { DOMSerializer } from "@tiptap/pm/model";
|
|
2
|
+
//#region ../ui/src/components/edyn/rich-text-editor/serialize.ts
|
|
3
|
+
var MENTION_MARK = "data-rich-text-mention";
|
|
4
|
+
var defaultMentionToText = (item) => `@${item.id}`;
|
|
5
|
+
/**
|
|
6
|
+
* The document as HTML. Not `editor.getHTML()`: that would write a mention as its chip element, and
|
|
7
|
+
* the HTML must carry the plain text the app chose (`@person@example.test`) and nothing else.
|
|
8
|
+
*/
|
|
9
|
+
var serializeDocument = (doc, toText) => {
|
|
10
|
+
const schema = doc.type.schema;
|
|
11
|
+
const nodes = {
|
|
12
|
+
...DOMSerializer.nodesFromSchema(schema),
|
|
13
|
+
mention: (node) => [
|
|
14
|
+
"span",
|
|
15
|
+
{ [MENTION_MARK]: "" },
|
|
16
|
+
toText({
|
|
17
|
+
id: String(node.attrs.id ?? ""),
|
|
18
|
+
label: String(node.attrs.label ?? "")
|
|
19
|
+
})
|
|
20
|
+
]
|
|
21
|
+
};
|
|
22
|
+
const serializer = new DOMSerializer(nodes, DOMSerializer.marksFromSchema(schema));
|
|
23
|
+
const container = document.createElement("div");
|
|
24
|
+
container.appendChild(serializer.serializeFragment(doc.content));
|
|
25
|
+
for (const element of Array.from(container.querySelectorAll(`[${MENTION_MARK}]`))) element.replaceWith(document.createTextNode(element.textContent ?? ""));
|
|
26
|
+
return container.innerHTML;
|
|
27
|
+
};
|
|
28
|
+
/** No text and no mention. A document of blank paragraphs, spaces and line breaks is empty too. */
|
|
29
|
+
var isDocumentEmpty = (doc) => {
|
|
30
|
+
if (doc.textContent.trim() !== "") return false;
|
|
31
|
+
let hasMention = false;
|
|
32
|
+
doc.descendants((node) => {
|
|
33
|
+
if (node.type.name === "mention") hasMention = true;
|
|
34
|
+
return !hasMention;
|
|
35
|
+
});
|
|
36
|
+
return !hasMention;
|
|
37
|
+
};
|
|
38
|
+
/** Characters the HTML text will have: a mention counts as the text it is written as. */
|
|
39
|
+
var countCharacters = (doc, toText) => {
|
|
40
|
+
let total = 0;
|
|
41
|
+
doc.descendants((node) => {
|
|
42
|
+
if (node.isText) total += node.text?.length ?? 0;
|
|
43
|
+
else if (node.type.name === "mention") total += toText({
|
|
44
|
+
id: String(node.attrs.id ?? ""),
|
|
45
|
+
label: String(node.attrs.label ?? "")
|
|
46
|
+
}).length;
|
|
47
|
+
else if (node.type.name === "hardBreak") total += 1;
|
|
48
|
+
return true;
|
|
49
|
+
});
|
|
50
|
+
return total;
|
|
51
|
+
};
|
|
52
|
+
//#endregion
|
|
53
|
+
export { countCharacters, defaultMentionToText, isDocumentEmpty, serializeDocument };
|
|
54
|
+
|
|
55
|
+
//# sourceMappingURL=serialize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialize.js","names":[],"sources":["../../../../../../../ui/src/components/edyn/rich-text-editor/serialize.ts"],"sourcesContent":["import { type DOMOutputSpec, DOMSerializer, type Node as TProseNode } from '@tiptap/pm/model';\nimport type { IRichTextMention } from './types';\n\nexport type TMentionToText = NonNullable<IRichTextMention['toText']>;\n\n// A serializer can only return elements, so a mention leaves as one and is unwrapped to its text below.\nconst MENTION_MARK = 'data-rich-text-mention';\n\nexport const defaultMentionToText: TMentionToText = (item) => `@${item.id}`;\n\n/**\n * The document as HTML. Not `editor.getHTML()`: that would write a mention as its chip element, and\n * the HTML must carry the plain text the app chose (`@person@example.test`) and nothing else.\n */\nexport const serializeDocument = (doc: TProseNode, toText: TMentionToText): string => {\n const schema = doc.type.schema;\n const nodes = {\n ...DOMSerializer.nodesFromSchema(schema),\n mention: (node: TProseNode): DOMOutputSpec => [\n 'span',\n { [MENTION_MARK]: '' },\n toText({ id: String(node.attrs.id ?? ''), label: String(node.attrs.label ?? '') }),\n ],\n };\n const serializer = new DOMSerializer(nodes, DOMSerializer.marksFromSchema(schema));\n const container = document.createElement('div');\n container.appendChild(serializer.serializeFragment(doc.content));\n for (const element of Array.from(container.querySelectorAll(`[${MENTION_MARK}]`))) {\n element.replaceWith(document.createTextNode(element.textContent ?? ''));\n }\n return container.innerHTML;\n};\n\n/** No text and no mention. A document of blank paragraphs, spaces and line breaks is empty too. */\nexport const isDocumentEmpty = (doc: TProseNode): boolean => {\n if (doc.textContent.trim() !== '') {\n return false;\n }\n let hasMention = false;\n doc.descendants((node) => {\n if (node.type.name === 'mention') {\n hasMention = true;\n }\n return !hasMention;\n });\n return !hasMention;\n};\n\n/** Characters the HTML text will have: a mention counts as the text it is written as. */\nexport const countCharacters = (doc: TProseNode, toText: TMentionToText): number => {\n let total = 0;\n doc.descendants((node) => {\n if (node.isText) {\n total += node.text?.length ?? 0;\n } else if (node.type.name === 'mention') {\n total += toText({ id: String(node.attrs.id ?? ''), label: String(node.attrs.label ?? '') }).length;\n } else if (node.type.name === 'hardBreak') {\n total += 1;\n }\n return true;\n });\n return total;\n};\n"],"mappings":";;AAMA,IAAM,eAAe;AAErB,IAAa,wBAAwC,SAAS,IAAI,KAAK;;;;;AAMvE,IAAa,qBAAqB,KAAiB,WAAmC;CACpF,MAAM,SAAS,IAAI,KAAK;CACxB,MAAM,QAAQ;EACZ,GAAG,cAAc,gBAAgB,MAAM;EACvC,UAAU,SAAoC;GAC5C;GACA,GAAG,eAAe,GAAG;GACrB,OAAO;IAAE,IAAI,OAAO,KAAK,MAAM,MAAM,EAAE;IAAG,OAAO,OAAO,KAAK,MAAM,SAAS,EAAE;GAAE,CAAC;EACnF;CACF;CACA,MAAM,aAAa,IAAI,cAAc,OAAO,cAAc,gBAAgB,MAAM,CAAC;CACjF,MAAM,YAAY,SAAS,cAAc,KAAK;CAC9C,UAAU,YAAY,WAAW,kBAAkB,IAAI,OAAO,CAAC;CAC/D,KAAK,MAAM,WAAW,MAAM,KAAK,UAAU,iBAAiB,IAAI,aAAa,EAAE,CAAC,GAC9E,QAAQ,YAAY,SAAS,eAAe,QAAQ,eAAe,EAAE,CAAC;CAExE,OAAO,UAAU;AACnB;;AAGA,IAAa,mBAAmB,QAA6B;CAC3D,IAAI,IAAI,YAAY,KAAK,MAAM,IAC7B,OAAO;CAET,IAAI,aAAa;CACjB,IAAI,aAAa,SAAS;EACxB,IAAI,KAAK,KAAK,SAAS,WACrB,aAAa;EAEf,OAAO,CAAC;CACV,CAAC;CACD,OAAO,CAAC;AACV;;AAGA,IAAa,mBAAmB,KAAiB,WAAmC;CAClF,IAAI,QAAQ;CACZ,IAAI,aAAa,SAAS;EACxB,IAAI,KAAK,QACP,SAAS,KAAK,MAAM,UAAU;OACzB,IAAI,KAAK,KAAK,SAAS,WAC5B,SAAS,OAAO;GAAE,IAAI,OAAO,KAAK,MAAM,MAAM,EAAE;GAAG,OAAO,OAAO,KAAK,MAAM,SAAS,EAAE;EAAE,CAAC,CAAC,CAAC;OACvF,IAAI,KAAK,KAAK,SAAS,aAC5B,SAAS;EAEX,OAAO;CACT,CAAC;CACD,OAAO;AACT"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Editor } from '@tiptap/core';
|
|
2
|
+
/**
|
|
3
|
+
* Whether commands may be called on the editor. TipTap builds an editor during the render, mounts its view later, and
|
|
4
|
+
* destroys one that has not been mounted within a moment (useEditor then makes a new one), so an effect can be handed an
|
|
5
|
+
* editor that is not there yet or no longer is. `isDestroyed` is true for both: it reads true until the view exists. A
|
|
6
|
+
* destroyed editor has no command manager, so `editor.commands` throws on it.
|
|
7
|
+
*/
|
|
8
|
+
export declare const isLive: (editor: Editor) => boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Brings the editor to a value the parent passed in, if it is one the editor did not just report itself.
|
|
11
|
+
* `known` is the last HTML the editor and the parent agree on (the starting value, then whatever the editor emitted or was
|
|
12
|
+
* given). The caret stays where it was, kept inside the new content, so a value changed from outside while the writer is
|
|
13
|
+
* typing does not throw the caret to the start.
|
|
14
|
+
*/
|
|
15
|
+
export declare const syncValue: (editor: Editor, value: string | undefined, known: {
|
|
16
|
+
current: string | undefined;
|
|
17
|
+
}) => void;
|
|
18
|
+
/** Sets whether the editor can be edited without telling the app something changed (TipTap emits an update by default). */
|
|
19
|
+
export declare const syncEditable: (editor: Editor, editable: boolean) => void;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { TextSelection } from "@tiptap/pm/state";
|
|
2
|
+
//#region ../ui/src/components/edyn/rich-text-editor/sync.ts
|
|
3
|
+
/**
|
|
4
|
+
* Whether commands may be called on the editor. TipTap builds an editor during the render, mounts its view later, and
|
|
5
|
+
* destroys one that has not been mounted within a moment (useEditor then makes a new one), so an effect can be handed an
|
|
6
|
+
* editor that is not there yet or no longer is. `isDestroyed` is true for both: it reads true until the view exists. A
|
|
7
|
+
* destroyed editor has no command manager, so `editor.commands` throws on it.
|
|
8
|
+
*/
|
|
9
|
+
var isLive = (editor) => editor.isInitialized && !editor.isDestroyed;
|
|
10
|
+
/**
|
|
11
|
+
* Brings the editor to a value the parent passed in, if it is one the editor did not just report itself.
|
|
12
|
+
* `known` is the last HTML the editor and the parent agree on (the starting value, then whatever the editor emitted or was
|
|
13
|
+
* given). The caret stays where it was, kept inside the new content, so a value changed from outside while the writer is
|
|
14
|
+
* typing does not throw the caret to the start.
|
|
15
|
+
*/
|
|
16
|
+
var syncValue = (editor, value, known) => {
|
|
17
|
+
if (!isLive(editor) || value === void 0 || value === known.current) return;
|
|
18
|
+
known.current = value;
|
|
19
|
+
const { from, to } = editor.state.selection;
|
|
20
|
+
editor.commands.setContent(value, { emitUpdate: false });
|
|
21
|
+
editor.commands.command(({ tr }) => {
|
|
22
|
+
const size = tr.doc.content.size;
|
|
23
|
+
tr.setSelection(TextSelection.between(tr.doc.resolve(Math.min(from, size)), tr.doc.resolve(Math.min(to, size))));
|
|
24
|
+
return true;
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
/** Sets whether the editor can be edited without telling the app something changed (TipTap emits an update by default). */
|
|
28
|
+
var syncEditable = (editor, editable) => {
|
|
29
|
+
if (isLive(editor) && editor.isEditable !== editable) editor.setEditable(editable, false);
|
|
30
|
+
};
|
|
31
|
+
//#endregion
|
|
32
|
+
export { isLive, syncEditable, syncValue };
|
|
33
|
+
|
|
34
|
+
//# sourceMappingURL=sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync.js","names":[],"sources":["../../../../../../../ui/src/components/edyn/rich-text-editor/sync.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core';\nimport { TextSelection } from '@tiptap/pm/state';\n\n/**\n * Whether commands may be called on the editor. TipTap builds an editor during the render, mounts its view later, and\n * destroys one that has not been mounted within a moment (useEditor then makes a new one), so an effect can be handed an\n * editor that is not there yet or no longer is. `isDestroyed` is true for both: it reads true until the view exists. A\n * destroyed editor has no command manager, so `editor.commands` throws on it.\n */\nexport const isLive = (editor: Editor): boolean => editor.isInitialized && !editor.isDestroyed;\n\n/**\n * Brings the editor to a value the parent passed in, if it is one the editor did not just report itself.\n * `known` is the last HTML the editor and the parent agree on (the starting value, then whatever the editor emitted or was\n * given). The caret stays where it was, kept inside the new content, so a value changed from outside while the writer is\n * typing does not throw the caret to the start.\n */\nexport const syncValue = (editor: Editor, value: string | undefined, known: { current: string | undefined }): void => {\n if (!isLive(editor) || value === undefined || value === known.current) {\n return;\n }\n known.current = value;\n const { from, to } = editor.state.selection;\n editor.commands.setContent(value, { emitUpdate: false });\n editor.commands.command(({ tr }) => {\n const size = tr.doc.content.size;\n tr.setSelection(TextSelection.between(tr.doc.resolve(Math.min(from, size)), tr.doc.resolve(Math.min(to, size))));\n return true;\n });\n};\n\n/** Sets whether the editor can be edited without telling the app something changed (TipTap emits an update by default). */\nexport const syncEditable = (editor: Editor, editable: boolean): void => {\n if (isLive(editor) && editor.isEditable !== editable) {\n editor.setEditable(editable, false);\n }\n};\n"],"mappings":";;;;;;;;AASA,IAAa,UAAU,WAA4B,OAAO,iBAAiB,CAAC,OAAO;;;;;;;AAQnF,IAAa,aAAa,QAAgB,OAA2B,UAAiD;CACpH,IAAI,CAAC,OAAO,MAAM,KAAK,UAAU,KAAA,KAAa,UAAU,MAAM,SAC5D;CAEF,MAAM,UAAU;CAChB,MAAM,EAAE,MAAM,OAAO,OAAO,MAAM;CAClC,OAAO,SAAS,WAAW,OAAO,EAAE,YAAY,MAAM,CAAC;CACvD,OAAO,SAAS,SAAS,EAAE,SAAS;EAClC,MAAM,OAAO,GAAG,IAAI,QAAQ;EAC5B,GAAG,aAAa,cAAc,QAAQ,GAAG,IAAI,QAAQ,KAAK,IAAI,MAAM,IAAI,CAAC,GAAG,GAAG,IAAI,QAAQ,KAAK,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC;EAC/G,OAAO;CACT,CAAC;AACH;;AAGA,IAAa,gBAAgB,QAAgB,aAA4B;CACvE,IAAI,OAAO,MAAM,KAAK,OAAO,eAAe,UAC1C,OAAO,YAAY,UAAU,KAAK;AAEtC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keeping the editor in step with the parent's value without ever touching an editor that is not there. A controlled
|
|
3
|
+
* RichTextEditor crashed on mount in rc.7 ("Cannot read properties of null (reading 'commands')"): TipTap makes the editor
|
|
4
|
+
* during the render, mounts its view later and destroys one that is not mounted in time, and the value effect ran at the
|
|
5
|
+
* first commit for every controlled value and called a command on whatever editor it was handed.
|
|
6
|
+
*
|
|
7
|
+
* PATH TAKEN: the destroyed editor is reproduced as the state TipTap leaves it in (no command manager, so `commands`
|
|
8
|
+
* throws), because the timing that produces it in an app cannot be driven from a test. The real behaviour in a browser,
|
|
9
|
+
* mount order included, is e2e/rich-text-editor-lifecycle.spec.ts.
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Editor } from '@tiptap/core';
|
|
2
|
+
import { RefObject } from 'react';
|
|
3
|
+
import { IRichTextField, IRichTextLabels } from './types';
|
|
4
|
+
/** A typed address becomes a link: "name@example.test" a mailto, "example.test" an https address. */
|
|
5
|
+
export declare const normalizeHref: (raw: string) => string;
|
|
6
|
+
/** Where the writer's selection was when the link box opened: moving focus into the box must not lose it. */
|
|
7
|
+
export interface ILinkRange {
|
|
8
|
+
from: number;
|
|
9
|
+
to: number;
|
|
10
|
+
}
|
|
11
|
+
export interface IRichTextToolbarProps {
|
|
12
|
+
linkRange: RefObject<ILinkRange | null>;
|
|
13
|
+
editor: Editor;
|
|
14
|
+
labels: IRichTextLabels;
|
|
15
|
+
fields: IRichTextField[] | undefined;
|
|
16
|
+
disabled: boolean;
|
|
17
|
+
linkOpen: boolean;
|
|
18
|
+
onLinkOpenChange: (open: boolean) => void;
|
|
19
|
+
}
|
|
20
|
+
export declare const RichTextToolbar: ({ linkRange, editor, labels, fields, disabled, linkOpen, onLinkOpenChange }: IRichTextToolbarProps) => import('react').JSX.Element;
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { cn } from "../../../lib/utils.js";
|
|
2
|
+
import { Button } from "../../ui/button/button.js";
|
|
3
|
+
import { Popover, PopoverContent, PopoverTrigger } from "../../ui/popover/popover.js";
|
|
4
|
+
import { isAllowedRichTextHref } from "../rich-text-content/allow-list.js";
|
|
5
|
+
import { Input } from "../../ui/input/input.js";
|
|
6
|
+
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "../../ui/dropdown-menu/dropdown-menu.js";
|
|
7
|
+
import { toggleVariants } from "../../ui/toggle/toggle.js";
|
|
8
|
+
import { useEffect, useState } from "react";
|
|
9
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
import { IconBold, IconItalic, IconLink, IconList, IconListNumbers, IconSeparatorHorizontal, IconUnderline, IconVariable } from "@tabler/icons-react";
|
|
11
|
+
import { useEditorState } from "@tiptap/react";
|
|
12
|
+
import { Toolbar } from "@base-ui/react/toolbar";
|
|
13
|
+
//#region ../ui/src/components/edyn/rich-text-editor/toolbar.tsx
|
|
14
|
+
var BUTTON_CLASS = cn(toggleVariants({
|
|
15
|
+
variant: "default",
|
|
16
|
+
size: "sm"
|
|
17
|
+
}), "size-7 px-0");
|
|
18
|
+
/** A typed address becomes a link: "name@example.test" a mailto, "example.test" an https address. */
|
|
19
|
+
var normalizeHref = (raw) => {
|
|
20
|
+
const value = raw.trim();
|
|
21
|
+
if (value === "" || /^[a-z][a-z0-9+.-]*:/i.test(value)) return value;
|
|
22
|
+
return /^[^\s@/]+@[^\s@/]+\.[^\s@/]+$/.test(value) ? `mailto:${value}` : `https://${value}`;
|
|
23
|
+
};
|
|
24
|
+
var ToolbarButton = ({ label, pressed, disabled, onClick, children }) => /* @__PURE__ */ jsx(Toolbar.Button, {
|
|
25
|
+
type: "button",
|
|
26
|
+
"aria-label": label,
|
|
27
|
+
title: label,
|
|
28
|
+
"aria-pressed": pressed,
|
|
29
|
+
"data-pressed": pressed ? "" : void 0,
|
|
30
|
+
disabled,
|
|
31
|
+
className: BUTTON_CLASS,
|
|
32
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
33
|
+
onClick,
|
|
34
|
+
children
|
|
35
|
+
});
|
|
36
|
+
var hrefAt = (editor, range) => {
|
|
37
|
+
const { doc } = editor.state;
|
|
38
|
+
const marks = range.from < range.to ? doc.nodeAt(range.from)?.marks ?? [] : doc.resolve(range.from).marks();
|
|
39
|
+
return String(marks.find((mark) => mark.type.name === "link")?.attrs.href ?? "");
|
|
40
|
+
};
|
|
41
|
+
var LinkControl = ({ range, editor, labels, active, disabled, open, onOpenChange }) => {
|
|
42
|
+
const [address, setAddress] = useState("");
|
|
43
|
+
const [invalid, setInvalid] = useState(false);
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (open) {
|
|
46
|
+
setAddress(range.current ? hrefAt(editor, range.current) : "");
|
|
47
|
+
setInvalid(false);
|
|
48
|
+
}
|
|
49
|
+
}, [
|
|
50
|
+
editor,
|
|
51
|
+
open,
|
|
52
|
+
range
|
|
53
|
+
]);
|
|
54
|
+
const apply = (event) => {
|
|
55
|
+
event.preventDefault();
|
|
56
|
+
event.stopPropagation();
|
|
57
|
+
const href = normalizeHref(address);
|
|
58
|
+
if (!isAllowedRichTextHref(href)) {
|
|
59
|
+
setInvalid(true);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const saved = range.current ?? {
|
|
63
|
+
from: editor.state.selection.from,
|
|
64
|
+
to: editor.state.selection.to
|
|
65
|
+
};
|
|
66
|
+
const chain = editor.chain().focus().setTextSelection(saved);
|
|
67
|
+
if (saved.from === saved.to && !hrefAt(editor, saved)) chain.insertContent({
|
|
68
|
+
type: "text",
|
|
69
|
+
text: href,
|
|
70
|
+
marks: [{
|
|
71
|
+
type: "link",
|
|
72
|
+
attrs: { href }
|
|
73
|
+
}]
|
|
74
|
+
}).run();
|
|
75
|
+
else chain.extendMarkRange("link").setLink({ href }).run();
|
|
76
|
+
onOpenChange(false);
|
|
77
|
+
};
|
|
78
|
+
const remove = () => {
|
|
79
|
+
const saved = range.current ?? {
|
|
80
|
+
from: editor.state.selection.from,
|
|
81
|
+
to: editor.state.selection.to
|
|
82
|
+
};
|
|
83
|
+
editor.chain().focus().setTextSelection(saved).extendMarkRange("link").unsetLink().run();
|
|
84
|
+
onOpenChange(false);
|
|
85
|
+
};
|
|
86
|
+
return /* @__PURE__ */ jsxs(Popover, {
|
|
87
|
+
open,
|
|
88
|
+
onOpenChange,
|
|
89
|
+
children: [/* @__PURE__ */ jsx(PopoverTrigger, {
|
|
90
|
+
render: /* @__PURE__ */ jsx(Toolbar.Button, {
|
|
91
|
+
type: "button",
|
|
92
|
+
"aria-label": labels.link,
|
|
93
|
+
title: labels.link,
|
|
94
|
+
"aria-pressed": active,
|
|
95
|
+
"data-pressed": active ? "" : void 0,
|
|
96
|
+
disabled,
|
|
97
|
+
className: BUTTON_CLASS
|
|
98
|
+
}),
|
|
99
|
+
children: /* @__PURE__ */ jsx(IconLink, { "aria-hidden": true })
|
|
100
|
+
}), /* @__PURE__ */ jsx(PopoverContent, {
|
|
101
|
+
align: "start",
|
|
102
|
+
className: "w-80",
|
|
103
|
+
children: /* @__PURE__ */ jsxs("form", {
|
|
104
|
+
className: "flex flex-col gap-2",
|
|
105
|
+
onSubmit: apply,
|
|
106
|
+
children: [
|
|
107
|
+
/* @__PURE__ */ jsx(Input, {
|
|
108
|
+
type: "text",
|
|
109
|
+
inputMode: "url",
|
|
110
|
+
"aria-label": labels.linkAddress,
|
|
111
|
+
"aria-invalid": invalid || void 0,
|
|
112
|
+
value: address,
|
|
113
|
+
onChange: (event) => {
|
|
114
|
+
setAddress(event.target.value);
|
|
115
|
+
setInvalid(false);
|
|
116
|
+
}
|
|
117
|
+
}),
|
|
118
|
+
invalid ? /* @__PURE__ */ jsx("p", {
|
|
119
|
+
className: "text-xs text-destructive",
|
|
120
|
+
children: labels.linkInvalid
|
|
121
|
+
}) : null,
|
|
122
|
+
/* @__PURE__ */ jsxs("div", {
|
|
123
|
+
className: "flex justify-end gap-2",
|
|
124
|
+
children: [active ? /* @__PURE__ */ jsx(Button, {
|
|
125
|
+
type: "button",
|
|
126
|
+
variant: "outline",
|
|
127
|
+
size: "sm",
|
|
128
|
+
onClick: remove,
|
|
129
|
+
children: labels.linkRemove
|
|
130
|
+
}) : null, /* @__PURE__ */ jsx(Button, {
|
|
131
|
+
type: "submit",
|
|
132
|
+
size: "sm",
|
|
133
|
+
children: labels.linkApply
|
|
134
|
+
})]
|
|
135
|
+
})
|
|
136
|
+
]
|
|
137
|
+
})
|
|
138
|
+
})]
|
|
139
|
+
});
|
|
140
|
+
};
|
|
141
|
+
var RichTextToolbar = ({ linkRange, editor, labels, fields, disabled, linkOpen, onLinkOpenChange }) => {
|
|
142
|
+
const state = useEditorState({
|
|
143
|
+
editor,
|
|
144
|
+
selector: ({ editor: current }) => ({
|
|
145
|
+
bold: current.isActive("bold"),
|
|
146
|
+
italic: current.isActive("italic"),
|
|
147
|
+
underline: current.isActive("underline"),
|
|
148
|
+
bullets: current.isActive("bulletList"),
|
|
149
|
+
numbers: current.isActive("orderedList"),
|
|
150
|
+
link: current.isActive("link")
|
|
151
|
+
})
|
|
152
|
+
});
|
|
153
|
+
return /* @__PURE__ */ jsxs(Toolbar.Root, {
|
|
154
|
+
"data-slot": "rich-text-toolbar",
|
|
155
|
+
"aria-label": labels.toolbar,
|
|
156
|
+
className: "flex flex-wrap items-center gap-0.5 border-b border-control p-1",
|
|
157
|
+
children: [
|
|
158
|
+
/* @__PURE__ */ jsx(ToolbarButton, {
|
|
159
|
+
label: labels.bold,
|
|
160
|
+
pressed: state.bold,
|
|
161
|
+
disabled,
|
|
162
|
+
onClick: () => editor.chain().focus().toggleBold().run(),
|
|
163
|
+
children: /* @__PURE__ */ jsx(IconBold, { "aria-hidden": true })
|
|
164
|
+
}),
|
|
165
|
+
/* @__PURE__ */ jsx(ToolbarButton, {
|
|
166
|
+
label: labels.italic,
|
|
167
|
+
pressed: state.italic,
|
|
168
|
+
disabled,
|
|
169
|
+
onClick: () => editor.chain().focus().toggleItalic().run(),
|
|
170
|
+
children: /* @__PURE__ */ jsx(IconItalic, { "aria-hidden": true })
|
|
171
|
+
}),
|
|
172
|
+
/* @__PURE__ */ jsx(ToolbarButton, {
|
|
173
|
+
label: labels.underline,
|
|
174
|
+
pressed: state.underline,
|
|
175
|
+
disabled,
|
|
176
|
+
onClick: () => editor.chain().focus().toggleUnderline().run(),
|
|
177
|
+
children: /* @__PURE__ */ jsx(IconUnderline, { "aria-hidden": true })
|
|
178
|
+
}),
|
|
179
|
+
/* @__PURE__ */ jsx(Toolbar.Separator, { className: "mx-1 h-4 w-px bg-border" }),
|
|
180
|
+
/* @__PURE__ */ jsx(ToolbarButton, {
|
|
181
|
+
label: labels.bulletList,
|
|
182
|
+
pressed: state.bullets,
|
|
183
|
+
disabled,
|
|
184
|
+
onClick: () => editor.chain().focus().toggleBulletList().run(),
|
|
185
|
+
children: /* @__PURE__ */ jsx(IconList, { "aria-hidden": true })
|
|
186
|
+
}),
|
|
187
|
+
/* @__PURE__ */ jsx(ToolbarButton, {
|
|
188
|
+
label: labels.numberedList,
|
|
189
|
+
pressed: state.numbers,
|
|
190
|
+
disabled,
|
|
191
|
+
onClick: () => editor.chain().focus().toggleOrderedList().run(),
|
|
192
|
+
children: /* @__PURE__ */ jsx(IconListNumbers, { "aria-hidden": true })
|
|
193
|
+
}),
|
|
194
|
+
/* @__PURE__ */ jsx(LinkControl, {
|
|
195
|
+
range: linkRange,
|
|
196
|
+
editor,
|
|
197
|
+
labels,
|
|
198
|
+
active: state.link,
|
|
199
|
+
disabled,
|
|
200
|
+
open: linkOpen,
|
|
201
|
+
onOpenChange: onLinkOpenChange
|
|
202
|
+
}),
|
|
203
|
+
/* @__PURE__ */ jsx(ToolbarButton, {
|
|
204
|
+
label: labels.horizontalRule,
|
|
205
|
+
disabled,
|
|
206
|
+
onClick: () => editor.chain().focus().setHorizontalRule().run(),
|
|
207
|
+
children: /* @__PURE__ */ jsx(IconSeparatorHorizontal, { "aria-hidden": true })
|
|
208
|
+
}),
|
|
209
|
+
fields && fields.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Toolbar.Separator, { className: "mx-1 h-4 w-px bg-border" }), /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
|
|
210
|
+
render: /* @__PURE__ */ jsx(Toolbar.Button, {
|
|
211
|
+
type: "button",
|
|
212
|
+
"aria-label": labels.insertField,
|
|
213
|
+
title: labels.insertField,
|
|
214
|
+
disabled,
|
|
215
|
+
className: BUTTON_CLASS
|
|
216
|
+
}),
|
|
217
|
+
children: /* @__PURE__ */ jsx(IconVariable, { "aria-hidden": true })
|
|
218
|
+
}), /* @__PURE__ */ jsx(DropdownMenuContent, {
|
|
219
|
+
align: "start",
|
|
220
|
+
className: "w-56",
|
|
221
|
+
children: fields.map((field) => /* @__PURE__ */ jsx(DropdownMenuItem, {
|
|
222
|
+
onClick: () => editor.chain().focus().insertContent({
|
|
223
|
+
type: "text",
|
|
224
|
+
text: `{{${field.id}}}`
|
|
225
|
+
}).run(),
|
|
226
|
+
children: field.label
|
|
227
|
+
}, field.id))
|
|
228
|
+
})] })] }) : null
|
|
229
|
+
]
|
|
230
|
+
});
|
|
231
|
+
};
|
|
232
|
+
//#endregion
|
|
233
|
+
export { RichTextToolbar, normalizeHref };
|
|
234
|
+
|
|
235
|
+
//# sourceMappingURL=toolbar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolbar.js","names":[],"sources":["../../../../../../../ui/src/components/edyn/rich-text-editor/toolbar.tsx"],"sourcesContent":["import { Toolbar as ToolbarPrimitive } from '@base-ui/react/toolbar';\nimport { isAllowedRichTextHref } from '@edyn/ui/components/edyn/rich-text-content/allow-list';\nimport { Button } from '@edyn/ui/components/ui/button';\nimport { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@edyn/ui/components/ui/dropdown-menu';\nimport { Input } from '@edyn/ui/components/ui/input';\nimport { Popover, PopoverContent, PopoverTrigger } from '@edyn/ui/components/ui/popover';\nimport { toggleVariants } from '@edyn/ui/components/ui/toggle';\nimport { cn } from '@edyn/ui/lib/utils';\nimport { IconBold, IconItalic, IconLink, IconList, IconListNumbers, IconSeparatorHorizontal, IconUnderline, IconVariable } from '@tabler/icons-react';\nimport type { Editor } from '@tiptap/core';\nimport { useEditorState } from '@tiptap/react';\nimport { type FormEvent, type ReactNode, type RefObject, useEffect, useState } from 'react';\nimport type { IRichTextField, IRichTextLabels } from './types';\n\nconst BUTTON_CLASS = cn(toggleVariants({ variant: 'default', size: 'sm' }), 'size-7 px-0');\n\n/** A typed address becomes a link: \"name@example.test\" a mailto, \"example.test\" an https address. */\nexport const normalizeHref = (raw: string): string => {\n const value = raw.trim();\n if (value === '' || /^[a-z][a-z0-9+.-]*:/i.test(value)) {\n return value;\n }\n return /^[^\\s@/]+@[^\\s@/]+\\.[^\\s@/]+$/.test(value) ? `mailto:${value}` : `https://${value}`;\n};\n\ninterface IToolbarButtonProps {\n label: string;\n pressed?: boolean;\n disabled?: boolean;\n onClick?: () => void;\n children: ReactNode;\n}\n\nconst ToolbarButton = ({ label, pressed, disabled, onClick, children }: IToolbarButtonProps) => (\n <ToolbarPrimitive.Button\n type=\"button\"\n aria-label={label}\n title={label}\n aria-pressed={pressed}\n data-pressed={pressed ? '' : undefined}\n disabled={disabled}\n className={BUTTON_CLASS}\n onMouseDown={(event) => event.preventDefault()}\n onClick={onClick}\n >\n {children}\n </ToolbarPrimitive.Button>\n);\n\n/** Where the writer's selection was when the link box opened: moving focus into the box must not lose it. */\nexport interface ILinkRange {\n from: number;\n to: number;\n}\n\nconst hrefAt = (editor: Editor, range: ILinkRange): string => {\n const { doc } = editor.state;\n const marks = range.from < range.to ? (doc.nodeAt(range.from)?.marks ?? []) : doc.resolve(range.from).marks();\n return String(marks.find((mark) => mark.type.name === 'link')?.attrs.href ?? '');\n};\n\ninterface ILinkControlProps {\n range: RefObject<ILinkRange | null>;\n editor: Editor;\n labels: IRichTextLabels;\n active: boolean;\n disabled: boolean;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}\n\nconst LinkControl = ({ range, editor, labels, active, disabled, open, onOpenChange }: ILinkControlProps) => {\n const [address, setAddress] = useState('');\n const [invalid, setInvalid] = useState(false);\n\n useEffect(() => {\n if (open) {\n setAddress(range.current ? hrefAt(editor, range.current) : '');\n setInvalid(false);\n }\n }, [editor, open, range]);\n\n const apply = (event: FormEvent) => {\n event.preventDefault();\n event.stopPropagation();\n const href = normalizeHref(address);\n if (!isAllowedRichTextHref(href)) {\n setInvalid(true);\n return;\n }\n const saved = range.current ?? { from: editor.state.selection.from, to: editor.state.selection.to };\n const chain = editor.chain().focus().setTextSelection(saved);\n if (saved.from === saved.to && !hrefAt(editor, saved)) {\n chain.insertContent({ type: 'text', text: href, marks: [{ type: 'link', attrs: { href } }] }).run();\n } else {\n chain.extendMarkRange('link').setLink({ href }).run();\n }\n onOpenChange(false);\n };\n\n const remove = () => {\n const saved = range.current ?? { from: editor.state.selection.from, to: editor.state.selection.to };\n editor.chain().focus().setTextSelection(saved).extendMarkRange('link').unsetLink().run();\n onOpenChange(false);\n };\n\n return (\n <Popover open={open} onOpenChange={onOpenChange}>\n <PopoverTrigger\n render={\n <ToolbarPrimitive.Button\n type=\"button\"\n aria-label={labels.link}\n title={labels.link}\n aria-pressed={active}\n data-pressed={active ? '' : undefined}\n disabled={disabled}\n className={BUTTON_CLASS}\n />\n }\n >\n <IconLink aria-hidden />\n </PopoverTrigger>\n <PopoverContent align=\"start\" className=\"w-80\">\n <form className=\"flex flex-col gap-2\" onSubmit={apply}>\n <Input\n type=\"text\"\n inputMode=\"url\"\n aria-label={labels.linkAddress}\n aria-invalid={invalid || undefined}\n value={address}\n onChange={(event) => {\n setAddress(event.target.value);\n setInvalid(false);\n }}\n />\n {invalid ? <p className=\"text-xs text-destructive\">{labels.linkInvalid}</p> : null}\n <div className=\"flex justify-end gap-2\">\n {active ? (\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={remove}>\n {labels.linkRemove}\n </Button>\n ) : null}\n <Button type=\"submit\" size=\"sm\">\n {labels.linkApply}\n </Button>\n </div>\n </form>\n </PopoverContent>\n </Popover>\n );\n};\n\nexport interface IRichTextToolbarProps {\n linkRange: RefObject<ILinkRange | null>;\n editor: Editor;\n labels: IRichTextLabels;\n fields: IRichTextField[] | undefined;\n disabled: boolean;\n linkOpen: boolean;\n onLinkOpenChange: (open: boolean) => void;\n}\n\nexport const RichTextToolbar = ({ linkRange, editor, labels, fields, disabled, linkOpen, onLinkOpenChange }: IRichTextToolbarProps) => {\n const state = useEditorState({\n editor,\n selector: ({ editor: current }) => ({\n bold: current.isActive('bold'),\n italic: current.isActive('italic'),\n underline: current.isActive('underline'),\n bullets: current.isActive('bulletList'),\n numbers: current.isActive('orderedList'),\n link: current.isActive('link'),\n }),\n });\n\n return (\n <ToolbarPrimitive.Root\n data-slot=\"rich-text-toolbar\"\n aria-label={labels.toolbar}\n className=\"flex flex-wrap items-center gap-0.5 border-b border-control p-1\"\n >\n <ToolbarButton label={labels.bold} pressed={state.bold} disabled={disabled} onClick={() => editor.chain().focus().toggleBold().run()}>\n <IconBold aria-hidden />\n </ToolbarButton>\n <ToolbarButton label={labels.italic} pressed={state.italic} disabled={disabled} onClick={() => editor.chain().focus().toggleItalic().run()}>\n <IconItalic aria-hidden />\n </ToolbarButton>\n <ToolbarButton\n label={labels.underline}\n pressed={state.underline}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleUnderline().run()}\n >\n <IconUnderline aria-hidden />\n </ToolbarButton>\n <ToolbarPrimitive.Separator className=\"mx-1 h-4 w-px bg-border\" />\n <ToolbarButton\n label={labels.bulletList}\n pressed={state.bullets}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleBulletList().run()}\n >\n <IconList aria-hidden />\n </ToolbarButton>\n <ToolbarButton\n label={labels.numberedList}\n pressed={state.numbers}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleOrderedList().run()}\n >\n <IconListNumbers aria-hidden />\n </ToolbarButton>\n <LinkControl\n range={linkRange}\n editor={editor}\n labels={labels}\n active={state.link}\n disabled={disabled}\n open={linkOpen}\n onOpenChange={onLinkOpenChange}\n />\n <ToolbarButton label={labels.horizontalRule} disabled={disabled} onClick={() => editor.chain().focus().setHorizontalRule().run()}>\n <IconSeparatorHorizontal aria-hidden />\n </ToolbarButton>\n {fields && fields.length > 0 ? (\n <>\n <ToolbarPrimitive.Separator className=\"mx-1 h-4 w-px bg-border\" />\n <DropdownMenu>\n <DropdownMenuTrigger\n render={\n <ToolbarPrimitive.Button\n type=\"button\"\n aria-label={labels.insertField}\n title={labels.insertField}\n disabled={disabled}\n className={BUTTON_CLASS}\n />\n }\n >\n <IconVariable aria-hidden />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" className=\"w-56\">\n {fields.map((field) => (\n <DropdownMenuItem\n key={field.id}\n onClick={() =>\n editor\n .chain()\n .focus()\n .insertContent({ type: 'text', text: `{{${field.id}}}` })\n .run()\n }\n >\n {field.label}\n </DropdownMenuItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n </>\n ) : null}\n </ToolbarPrimitive.Root>\n );\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/** One person (or anything else) the app offers when the writer types @. */
|
|
2
|
+
export interface IRichTextMentionItem {
|
|
3
|
+
/** What the HTML carries. By default the value is written as `@${id}`, so an email address works as an id. */
|
|
4
|
+
id: string;
|
|
5
|
+
/** What the chip shows while the text is being edited. */
|
|
6
|
+
label: string;
|
|
7
|
+
/** A second, muted line in the list (a role, an email address). */
|
|
8
|
+
secondary?: string;
|
|
9
|
+
}
|
|
10
|
+
/** A page of results. Return a plain array instead when there is only ever one page. */
|
|
11
|
+
export interface IRichTextMentionPage {
|
|
12
|
+
items: IRichTextMentionItem[];
|
|
13
|
+
/** True when asking for `page + 1` would return more. The list loads it when it is scrolled to the end. */
|
|
14
|
+
hasMore?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface IRichTextMentionSearchOptions {
|
|
17
|
+
/** 1-based. */
|
|
18
|
+
page: number;
|
|
19
|
+
/** Aborted when the writer types on or closes the list: pass it to `fetch` so a stale search stops. */
|
|
20
|
+
signal: AbortSignal;
|
|
21
|
+
}
|
|
22
|
+
export type TRichTextMentionSearch = (query: string, options: IRichTextMentionSearchOptions) => Promise<IRichTextMentionItem[] | IRichTextMentionPage>;
|
|
23
|
+
export interface IRichTextMention {
|
|
24
|
+
/** Asked for the first page when the writer types @ and again for every change of the text after it, debounced. */
|
|
25
|
+
search: TRichTextMentionSearch;
|
|
26
|
+
/**
|
|
27
|
+
* How a mention is written into the HTML. The chip exists only while editing; the HTML carries this text
|
|
28
|
+
* and no element. Default: `@${item.id}`.
|
|
29
|
+
*/
|
|
30
|
+
toText?: (item: Pick<IRichTextMentionItem, 'id' | 'label'>) => string;
|
|
31
|
+
/** Milliseconds to wait after the last keystroke before searching. Default 250. */
|
|
32
|
+
debounce?: number;
|
|
33
|
+
}
|
|
34
|
+
/** A field of a template (a mail merge token). Inserted as the plain text `{{id}}`. */
|
|
35
|
+
export interface IRichTextField {
|
|
36
|
+
id: string;
|
|
37
|
+
label: string;
|
|
38
|
+
}
|
|
39
|
+
/** What a ref to the editor can do, for a button outside it (a merge tag, say). */
|
|
40
|
+
export interface IRichTextEditorHandle {
|
|
41
|
+
/** Writes plain text at the caret (over the selection), and puts focus back in the editor. */
|
|
42
|
+
insertText: (text: string) => void;
|
|
43
|
+
focus: () => void;
|
|
44
|
+
}
|
|
45
|
+
/** Every string the editor shows, so an app can translate them. */
|
|
46
|
+
export interface IRichTextLabels {
|
|
47
|
+
toolbar: string;
|
|
48
|
+
bold: string;
|
|
49
|
+
italic: string;
|
|
50
|
+
underline: string;
|
|
51
|
+
bulletList: string;
|
|
52
|
+
numberedList: string;
|
|
53
|
+
link: string;
|
|
54
|
+
horizontalRule: string;
|
|
55
|
+
insertField: string;
|
|
56
|
+
linkAddress: string;
|
|
57
|
+
linkApply: string;
|
|
58
|
+
linkRemove: string;
|
|
59
|
+
linkInvalid: string;
|
|
60
|
+
mentionList: string;
|
|
61
|
+
mentionSearching: string;
|
|
62
|
+
mentionEmpty: string;
|
|
63
|
+
mentionError: string;
|
|
64
|
+
mentionLoadingMore: string;
|
|
65
|
+
/** Announced as the list changes. `{count}` is replaced. */
|
|
66
|
+
mentionResults: string;
|
|
67
|
+
}
|
|
68
|
+
export declare const DEFAULT_RICH_TEXT_LABELS: IRichTextLabels;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//#region ../ui/src/components/edyn/rich-text-editor/types.ts
|
|
2
|
+
var DEFAULT_RICH_TEXT_LABELS = {
|
|
3
|
+
toolbar: "Formatting",
|
|
4
|
+
bold: "Bold",
|
|
5
|
+
italic: "Italic",
|
|
6
|
+
underline: "Underline",
|
|
7
|
+
bulletList: "Bulleted list",
|
|
8
|
+
numberedList: "Numbered list",
|
|
9
|
+
link: "Link",
|
|
10
|
+
horizontalRule: "Horizontal line",
|
|
11
|
+
insertField: "Insert a field",
|
|
12
|
+
linkAddress: "Link address",
|
|
13
|
+
linkApply: "Apply",
|
|
14
|
+
linkRemove: "Remove link",
|
|
15
|
+
linkInvalid: "Enter an http, https or mailto address.",
|
|
16
|
+
mentionList: "Mentions",
|
|
17
|
+
mentionSearching: "Searching...",
|
|
18
|
+
mentionEmpty: "No matches",
|
|
19
|
+
mentionError: "The search failed",
|
|
20
|
+
mentionLoadingMore: "Loading more...",
|
|
21
|
+
mentionResults: "{count} results"
|
|
22
|
+
};
|
|
23
|
+
//#endregion
|
|
24
|
+
export { DEFAULT_RICH_TEXT_LABELS };
|
|
25
|
+
|
|
26
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","names":[],"sources":["../../../../../../../ui/src/components/edyn/rich-text-editor/types.ts"],"sourcesContent":["/** One person (or anything else) the app offers when the writer types @. */\nexport interface IRichTextMentionItem {\n /** What the HTML carries. By default the value is written as `@${id}`, so an email address works as an id. */\n id: string;\n /** What the chip shows while the text is being edited. */\n label: string;\n /** A second, muted line in the list (a role, an email address). */\n secondary?: string;\n}\n\n/** A page of results. Return a plain array instead when there is only ever one page. */\nexport interface IRichTextMentionPage {\n items: IRichTextMentionItem[];\n /** True when asking for `page + 1` would return more. The list loads it when it is scrolled to the end. */\n hasMore?: boolean;\n}\n\nexport interface IRichTextMentionSearchOptions {\n /** 1-based. */\n page: number;\n /** Aborted when the writer types on or closes the list: pass it to `fetch` so a stale search stops. */\n signal: AbortSignal;\n}\n\nexport type TRichTextMentionSearch = (\n query: string,\n options: IRichTextMentionSearchOptions,\n) => Promise<IRichTextMentionItem[] | IRichTextMentionPage>;\n\nexport interface IRichTextMention {\n /** Asked for the first page when the writer types @ and again for every change of the text after it, debounced. */\n search: TRichTextMentionSearch;\n /**\n * How a mention is written into the HTML. The chip exists only while editing; the HTML carries this text\n * and no element. Default: `@${item.id}`.\n */\n toText?: (item: Pick<IRichTextMentionItem, 'id' | 'label'>) => string;\n /** Milliseconds to wait after the last keystroke before searching. Default 250. */\n debounce?: number;\n}\n\n/** A field of a template (a mail merge token). Inserted as the plain text `{{id}}`. */\nexport interface IRichTextField {\n id: string;\n label: string;\n}\n\n/** What a ref to the editor can do, for a button outside it (a merge tag, say). */\nexport interface IRichTextEditorHandle {\n /** Writes plain text at the caret (over the selection), and puts focus back in the editor. */\n insertText: (text: string) => void;\n focus: () => void;\n}\n\n/** Every string the editor shows, so an app can translate them. */\nexport interface IRichTextLabels {\n toolbar: string;\n bold: string;\n italic: string;\n underline: string;\n bulletList: string;\n numberedList: string;\n link: string;\n horizontalRule: string;\n insertField: string;\n linkAddress: string;\n linkApply: string;\n linkRemove: string;\n linkInvalid: string;\n mentionList: string;\n mentionSearching: string;\n mentionEmpty: string;\n mentionError: string;\n mentionLoadingMore: string;\n /** Announced as the list changes. `{count}` is replaced. */\n mentionResults: string;\n}\n\nexport const DEFAULT_RICH_TEXT_LABELS: IRichTextLabels = {\n toolbar: 'Formatting',\n bold: 'Bold',\n italic: 'Italic',\n underline: 'Underline',\n bulletList: 'Bulleted list',\n numberedList: 'Numbered list',\n link: 'Link',\n horizontalRule: 'Horizontal line',\n insertField: 'Insert a field',\n linkAddress: 'Link address',\n linkApply: 'Apply',\n linkRemove: 'Remove link',\n linkInvalid: 'Enter an http, https or mailto address.',\n mentionList: 'Mentions',\n mentionSearching: 'Searching...',\n mentionEmpty: 'No matches',\n mentionError: 'The search failed',\n mentionLoadingMore: 'Loading more...',\n mentionResults: '{count} results',\n};\n"],"mappings":";AA8EA,IAAa,2BAA4C;CACvD,SAAS;CACT,MAAM;CACN,QAAQ;CACR,WAAW;CACX,YAAY;CACZ,cAAc;CACd,MAAM;CACN,gBAAgB;CAChB,aAAa;CACb,aAAa;CACb,WAAW;CACX,YAAY;CACZ,aAAa;CACb,aAAa;CACb,kBAAkB;CAClB,cAAc;CACd,cAAc;CACd,oBAAoB;CACpB,gBAAgB;AAClB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './time-field';
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { ComponentPropsWithoutRef } from 'react';
|
|
2
|
+
export type TTimeFieldGranularity = 'minute' | 'second';
|
|
3
|
+
export type TTimeFieldHourCycle = 12 | 24;
|
|
4
|
+
export type TTimeFieldSegment = 'hour' | 'minute' | 'second' | 'period';
|
|
5
|
+
export type TTimeFieldPeriod = 'AM' | 'PM';
|
|
6
|
+
/** The segments as they are shown: the hour in the field's own cycle (0 to 23, or 1 to 12 beside a period), each empty until entered. */
|
|
7
|
+
export interface ITimeParts {
|
|
8
|
+
hour: number | null;
|
|
9
|
+
minute: number | null;
|
|
10
|
+
second: number | null;
|
|
11
|
+
period: TTimeFieldPeriod | null;
|
|
12
|
+
}
|
|
13
|
+
export declare const EMPTY_TIME: ITimeParts;
|
|
14
|
+
export interface ITimeFieldLabels {
|
|
15
|
+
hour: string;
|
|
16
|
+
minute: string;
|
|
17
|
+
second: string;
|
|
18
|
+
/** The AM/PM segment. */
|
|
19
|
+
period: string;
|
|
20
|
+
/** Read for a segment with nothing in it. */
|
|
21
|
+
empty: string;
|
|
22
|
+
}
|
|
23
|
+
export declare const DEFAULT_TIME_FIELD_LABELS: ITimeFieldLabels;
|
|
24
|
+
/** 12 where the reader's locale writes AM and PM, 24 where it does not. */
|
|
25
|
+
export declare const localeHourCycle: () => TTimeFieldHourCycle;
|
|
26
|
+
/** `HH:mm` or `HH:mm:ss` (24-hour, as `<input type="time">` writes it) to the segments; anything else is no time. */
|
|
27
|
+
export declare const parseTime: (value: string, hourCycle: TTimeFieldHourCycle) => ITimeParts;
|
|
28
|
+
/** The segments to `HH:mm` or `HH:mm:ss`, or '' until every segment the field shows is in. */
|
|
29
|
+
export declare const formatTime: (parts: ITimeParts, hourCycle: TTimeFieldHourCycle, granularity: TTimeFieldGranularity) => string;
|
|
30
|
+
export interface IRange {
|
|
31
|
+
min: number;
|
|
32
|
+
max: number;
|
|
33
|
+
}
|
|
34
|
+
export declare const rangeOf: (segment: Exclude<TTimeFieldSegment, "period">, hourCycle: TTimeFieldHourCycle) => IRange;
|
|
35
|
+
/** One step up or down inside a range, wrapping at the ends. A segment with nothing in it starts at the end the step is heading away from. */
|
|
36
|
+
export declare const stepValue: (current: number | null, delta: number, { min, max }: IRange) => number;
|
|
37
|
+
/**
|
|
38
|
+
* Types a digit into a segment. The second digit joins the first when it makes a number the segment can hold; otherwise it starts
|
|
39
|
+
* over. The segment is done, and focus moves on, at two digits or as soon as no second digit could fit (a 3 in the hours, a 6 in the
|
|
40
|
+
* minutes).
|
|
41
|
+
*/
|
|
42
|
+
export declare const typeDigit: (buffer: string, digit: string, { min, max }: IRange) => {
|
|
43
|
+
value: number;
|
|
44
|
+
buffer: string;
|
|
45
|
+
done: boolean;
|
|
46
|
+
};
|
|
47
|
+
export interface IEdit {
|
|
48
|
+
parts: ITimeParts;
|
|
49
|
+
/** The digits typed so far into this segment and not yet complete. */
|
|
50
|
+
buffer: string;
|
|
51
|
+
/** Move to the next segment: this one is finished. */
|
|
52
|
+
advance: boolean;
|
|
53
|
+
}
|
|
54
|
+
/** What a key does to a segment, or null when the key is not one the segment handles (Tab, a letter in the hours...). */
|
|
55
|
+
export declare const editSegment: (parts: ITimeParts, segment: TTimeFieldSegment, key: string, hourCycle: TTimeFieldHourCycle, buffer: string) => IEdit | null;
|
|
56
|
+
export interface ITimeFieldProps extends Omit<ComponentPropsWithoutRef<'div'>, 'defaultValue' | 'onChange' | 'children' | 'role'> {
|
|
57
|
+
/** The time as `HH:mm` or `HH:mm:ss`, 24-hour whatever the field shows, as `<input type="time">` writes it. '' is no time. */
|
|
58
|
+
value?: string;
|
|
59
|
+
defaultValue?: string;
|
|
60
|
+
/** Called with the time as soon as every segment is in, and with '' when one of a full time is cleared. */
|
|
61
|
+
onValueChange?: (value: string) => void;
|
|
62
|
+
/** `second` adds a seconds segment and a `HH:mm:ss` value. */
|
|
63
|
+
granularity?: TTimeFieldGranularity;
|
|
64
|
+
/** 12 shows an AM/PM segment, 24 does not. The default is what the reader's locale writes. */
|
|
65
|
+
hourCycle?: TTimeFieldHourCycle;
|
|
66
|
+
/** The earliest and the latest time, `HH:mm`. A time outside them is marked invalid; it is not refused. */
|
|
67
|
+
min?: string;
|
|
68
|
+
max?: string;
|
|
69
|
+
disabled?: boolean;
|
|
70
|
+
/** Shown, focusable and readable, not changeable. */
|
|
71
|
+
readOnly?: boolean;
|
|
72
|
+
invalid?: boolean;
|
|
73
|
+
/** Submits the time with a form, under this name, as `HH:mm` or `HH:mm:ss`. */
|
|
74
|
+
name?: string;
|
|
75
|
+
labels?: Partial<ITimeFieldLabels>;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* A time of day typed in segments, in the kit's field: hours, minutes, optional seconds, and AM/PM where the reader's locale uses it.
|
|
79
|
+
* It exists so an app does not fall back to `<input type="time">`, whose look differs between browsers and from the rest of the kit.
|
|
80
|
+
*
|
|
81
|
+
* Each segment is a spinbutton: type digits (the focus moves on by itself), ArrowUp and ArrowDown step with wrap-around, PageUp and
|
|
82
|
+
* PageDown step by more, Home and End jump to the ends, Backspace empties, ArrowLeft and ArrowRight move between segments, and A or P
|
|
83
|
+
* set the period. The group is named by `aria-label` or `aria-labelledby`; a screen reader reads each segment by its own name and value.
|
|
84
|
+
*/
|
|
85
|
+
export declare const TimeField: ({ value, defaultValue, onValueChange, granularity, hourCycle: hourCycleProp, min, max, disabled, readOnly, invalid, name, labels: labelOverrides, className, ...rest }: ITimeFieldProps) => import('react').JSX.Element;
|