@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,23 @@
|
|
|
1
|
+
import { ComponentPropsWithoutRef, CSSProperties } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* The line's colour: an app sets --progress-line (on :root, or on any element above the
|
|
4
|
+
* line) to match its accent. The fallback is read where the line is, so it follows the
|
|
5
|
+
* theme, which a default declared once on :root would not.
|
|
6
|
+
*/
|
|
7
|
+
export declare const PROGRESS_LINE_COLOR = "var(--progress-line, var(--primary))";
|
|
8
|
+
export interface IProgressLineProps extends Omit<ComponentPropsWithoutRef<'div'>, 'children' | 'className' | 'style' | 'role'> {
|
|
9
|
+
/** Work is under way. */
|
|
10
|
+
active: boolean;
|
|
11
|
+
label?: string;
|
|
12
|
+
className?: string;
|
|
13
|
+
style?: CSSProperties;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* A thin line in the accent (--progress-line, by default --primary) that runs along the top of what is loading (a table's rows
|
|
17
|
+
* under its header, a page under the top bar). It waits a moment before it shows, so
|
|
18
|
+
* quick work never flashes it; it eases towards the end without reaching it while the
|
|
19
|
+
* work runs; when the work is done it runs to the end and only then fades. More work
|
|
20
|
+
* before it has gone carries on from where it is. With reduced motion it is a
|
|
21
|
+
* full-width line that fades.
|
|
22
|
+
*/
|
|
23
|
+
export declare const ProgressLine: ({ active, label, className, style, ...props }: IProgressLineProps) => import('react').JSX.Element;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { cn } from "../../../lib/utils.js";
|
|
2
|
+
import { useEffect, useRef, useState } from "react";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
//#region ../ui/src/components/edyn/progress-line/progress-line.tsx
|
|
5
|
+
/** Work quicker than this shows no line at all. */
|
|
6
|
+
var START_DELAY = 150;
|
|
7
|
+
var FINISH = 150;
|
|
8
|
+
var FADE = 200;
|
|
9
|
+
/** How far an ordinary run eases towards the end without reaching it. */
|
|
10
|
+
var RUN_TARGET = .85;
|
|
11
|
+
/**
|
|
12
|
+
* The line's colour: an app sets --progress-line (on :root, or on any element above the
|
|
13
|
+
* line) to match its accent. The fallback is read where the line is, so it follows the
|
|
14
|
+
* theme, which a default declared once on :root would not.
|
|
15
|
+
*/
|
|
16
|
+
var PROGRESS_LINE_COLOR = "var(--progress-line, var(--primary))";
|
|
17
|
+
var reducedMotion = () => window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
18
|
+
var scaleOf = (line) => {
|
|
19
|
+
const transform = line === null ? "none" : getComputedStyle(line).transform;
|
|
20
|
+
return transform === "none" ? 0 : new DOMMatrixReadOnly(transform).a;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* A thin line in the accent (--progress-line, by default --primary) that runs along the top of what is loading (a table's rows
|
|
24
|
+
* under its header, a page under the top bar). It waits a moment before it shows, so
|
|
25
|
+
* quick work never flashes it; it eases towards the end without reaching it while the
|
|
26
|
+
* work runs; when the work is done it runs to the end and only then fades. More work
|
|
27
|
+
* before it has gone carries on from where it is. With reduced motion it is a
|
|
28
|
+
* full-width line that fades.
|
|
29
|
+
*/
|
|
30
|
+
var ProgressLine = ({ active, label = "Loading", className, style, ...props }) => {
|
|
31
|
+
const [phase, setPhase] = useState("idle");
|
|
32
|
+
const [target, setTarget] = useState(RUN_TARGET);
|
|
33
|
+
const refPhase = useRef("idle");
|
|
34
|
+
const refLine = useRef(null);
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
let timer;
|
|
37
|
+
const go = (next) => {
|
|
38
|
+
refPhase.current = next;
|
|
39
|
+
setPhase(next);
|
|
40
|
+
};
|
|
41
|
+
const later = (milliseconds, run) => {
|
|
42
|
+
timer = window.setTimeout(run, milliseconds);
|
|
43
|
+
};
|
|
44
|
+
const fade = () => {
|
|
45
|
+
go("fading");
|
|
46
|
+
later(FADE, () => go("idle"));
|
|
47
|
+
};
|
|
48
|
+
const phaseNow = refPhase.current;
|
|
49
|
+
if (active) {
|
|
50
|
+
if (phaseNow === "idle" || phaseNow === "waiting") {
|
|
51
|
+
go("waiting");
|
|
52
|
+
later(START_DELAY, () => {
|
|
53
|
+
setTarget(RUN_TARGET);
|
|
54
|
+
go("running");
|
|
55
|
+
});
|
|
56
|
+
} else if (phaseNow === "finishing" || phaseNow === "fading") {
|
|
57
|
+
const reached = scaleOf(refLine.current);
|
|
58
|
+
setTarget(reached > .8 ? Math.min(.97, reached + .04) : RUN_TARGET);
|
|
59
|
+
go("running");
|
|
60
|
+
}
|
|
61
|
+
} else if (phaseNow === "waiting") go("idle");
|
|
62
|
+
else if (phaseNow === "running" || phaseNow === "finishing") {
|
|
63
|
+
if (reducedMotion()) fade();
|
|
64
|
+
else {
|
|
65
|
+
go("finishing");
|
|
66
|
+
later(FINISH, fade);
|
|
67
|
+
}
|
|
68
|
+
} else if (phaseNow === "fading") later(FADE, () => go("idle"));
|
|
69
|
+
return () => window.clearTimeout(timer);
|
|
70
|
+
}, [active]);
|
|
71
|
+
const reduced = phase !== "idle" && reducedMotion();
|
|
72
|
+
const scale = phase === "idle" || phase === "waiting" ? 0 : phase === "running" && !reduced ? target : 1;
|
|
73
|
+
const transition = phase === "running" && !reduced ? "transform 8s cubic-bezier(0.1, 0.7, 0.15, 1), opacity 120ms ease-out" : phase === "finishing" ? `transform ${FINISH}ms ease-out` : phase === "fading" ? `opacity ${FADE}ms ease-out` : "none";
|
|
74
|
+
const shown = phase === "running" || phase === "finishing" || phase === "fading";
|
|
75
|
+
return /* @__PURE__ */ jsx("div", {
|
|
76
|
+
"data-slot": "progress-line",
|
|
77
|
+
role: "progressbar",
|
|
78
|
+
"aria-label": label,
|
|
79
|
+
...props,
|
|
80
|
+
"aria-hidden": shown && phase !== "fading" ? void 0 : true,
|
|
81
|
+
"data-phase": phase,
|
|
82
|
+
className: cn("pointer-events-none h-0.5 overflow-hidden", className),
|
|
83
|
+
style,
|
|
84
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
85
|
+
ref: refLine,
|
|
86
|
+
"data-slot": "progress-line-bar",
|
|
87
|
+
className: "h-full origin-left",
|
|
88
|
+
style: {
|
|
89
|
+
backgroundColor: PROGRESS_LINE_COLOR,
|
|
90
|
+
transform: `scaleX(${scale})`,
|
|
91
|
+
opacity: phase === "fading" || !shown ? 0 : 1,
|
|
92
|
+
transition
|
|
93
|
+
}
|
|
94
|
+
})
|
|
95
|
+
});
|
|
96
|
+
};
|
|
97
|
+
//#endregion
|
|
98
|
+
export { PROGRESS_LINE_COLOR, ProgressLine };
|
|
99
|
+
|
|
100
|
+
//# sourceMappingURL=progress-line.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress-line.js","names":[],"sources":["../../../../../../../ui/src/components/edyn/progress-line/progress-line.tsx"],"sourcesContent":["import { cn } from '@edyn/ui/lib/utils';\nimport { type ComponentPropsWithoutRef, type CSSProperties, useEffect, useRef, useState } from 'react';\n\ntype TPhase = 'idle' | 'waiting' | 'running' | 'finishing' | 'fading';\n\n/** Work quicker than this shows no line at all. */\nconst START_DELAY = 150;\nconst FINISH = 150;\nconst FADE = 200;\n/** How far an ordinary run eases towards the end without reaching it. */\nconst RUN_TARGET = 0.85;\n\n/**\n * The line's colour: an app sets --progress-line (on :root, or on any element above the\n * line) to match its accent. The fallback is read where the line is, so it follows the\n * theme, which a default declared once on :root would not.\n */\nexport const PROGRESS_LINE_COLOR = 'var(--progress-line, var(--primary))';\n\nconst reducedMotion = (): boolean => window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n\n// How far the line has got: its scale along x, read from the transform it is drawn with right now.\nconst scaleOf = (line: HTMLElement | null): number => {\n const transform = line === null ? 'none' : getComputedStyle(line).transform;\n return transform === 'none' ? 0 : new DOMMatrixReadOnly(transform).a;\n};\n\nexport interface IProgressLineProps extends Omit<ComponentPropsWithoutRef<'div'>, 'children' | 'className' | 'style' | 'role'> {\n /** Work is under way. */\n active: boolean;\n label?: string;\n className?: string;\n style?: CSSProperties;\n}\n\n/**\n * A thin line in the accent (--progress-line, by default --primary) that runs along the top of what is loading (a table's rows\n * under its header, a page under the top bar). It waits a moment before it shows, so\n * quick work never flashes it; it eases towards the end without reaching it while the\n * work runs; when the work is done it runs to the end and only then fades. More work\n * before it has gone carries on from where it is. With reduced motion it is a\n * full-width line that fades.\n */\nexport const ProgressLine = ({ active, label = 'Loading', className, style, ...props }: IProgressLineProps) => {\n const [phase, setPhase] = useState<TPhase>('idle');\n const [target, setTarget] = useState(RUN_TARGET);\n const refPhase = useRef<TPhase>('idle');\n const refLine = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n let timer: number | undefined;\n const go = (next: TPhase): void => {\n refPhase.current = next;\n setPhase(next);\n };\n const later = (milliseconds: number, run: () => void): void => {\n timer = window.setTimeout(run, milliseconds);\n };\n const fade = (): void => {\n go('fading');\n later(FADE, () => go('idle'));\n };\n const phaseNow = refPhase.current;\n if (active) {\n if (phaseNow === 'idle' || phaseNow === 'waiting') {\n go('waiting');\n later(START_DELAY, () => {\n setTarget(RUN_TARGET);\n go('running');\n });\n } else if (phaseNow === 'finishing' || phaseNow === 'fading') {\n // More work before the line has gone: on from where it is, never back to the start.\n const reached = scaleOf(refLine.current);\n setTarget(reached > 0.8 ? Math.min(0.97, reached + 0.04) : RUN_TARGET);\n go('running');\n }\n } else if (phaseNow === 'waiting') {\n go('idle');\n } else if (phaseNow === 'running' || phaseNow === 'finishing') {\n if (reducedMotion()) {\n fade();\n } else {\n go('finishing');\n later(FINISH, fade);\n }\n } else if (phaseNow === 'fading') {\n later(FADE, () => go('idle'));\n }\n return () => window.clearTimeout(timer);\n }, [active]);\n\n const reduced = phase !== 'idle' && reducedMotion();\n const scale = phase === 'idle' || phase === 'waiting' ? 0 : phase === 'running' && !reduced ? target : 1;\n const transition =\n phase === 'running' && !reduced\n ? 'transform 8s cubic-bezier(0.1, 0.7, 0.15, 1), opacity 120ms ease-out'\n : phase === 'finishing'\n ? `transform ${FINISH}ms ease-out`\n : phase === 'fading'\n ? `opacity ${FADE}ms ease-out`\n : 'none';\n const shown = phase === 'running' || phase === 'finishing' || phase === 'fading';\n return (\n <div\n data-slot=\"progress-line\"\n role=\"progressbar\"\n aria-label={label}\n {...props}\n aria-hidden={shown && phase !== 'fading' ? undefined : true}\n data-phase={phase}\n className={cn('pointer-events-none h-0.5 overflow-hidden', className)}\n style={style}\n >\n <div\n ref={refLine}\n data-slot=\"progress-line-bar\"\n className=\"h-full origin-left\"\n style={{\n backgroundColor: PROGRESS_LINE_COLOR,\n transform: `scaleX(${scale})`,\n opacity: phase === 'fading' || !shown ? 0 : 1,\n transition,\n }}\n />\n </div>\n );\n};\n"],"mappings":";;;;;AAMA,IAAM,cAAc;AACpB,IAAM,SAAS;AACf,IAAM,OAAO;;AAEb,IAAM,aAAa;;;;;;AAOnB,IAAa,sBAAsB;AAEnC,IAAM,sBAA+B,OAAO,WAAW,kCAAkC,CAAC,CAAC;AAG3F,IAAM,WAAW,SAAqC;CACpD,MAAM,YAAY,SAAS,OAAO,SAAS,iBAAiB,IAAI,CAAC,CAAC;CAClE,OAAO,cAAc,SAAS,IAAI,IAAI,kBAAkB,SAAS,CAAC,CAAC;AACrE;;;;;;;;;AAkBA,IAAa,gBAAgB,EAAE,QAAQ,QAAQ,WAAW,WAAW,OAAO,GAAG,YAAgC;CAC7G,MAAM,CAAC,OAAO,YAAY,SAAiB,MAAM;CACjD,MAAM,CAAC,QAAQ,aAAa,SAAS,UAAU;CAC/C,MAAM,WAAW,OAAe,MAAM;CACtC,MAAM,UAAU,OAAuB,IAAI;CAE3C,gBAAgB;EACd,IAAI;EACJ,MAAM,MAAM,SAAuB;GACjC,SAAS,UAAU;GACnB,SAAS,IAAI;EACf;EACA,MAAM,SAAS,cAAsB,QAA0B;GAC7D,QAAQ,OAAO,WAAW,KAAK,YAAY;EAC7C;EACA,MAAM,aAAmB;GACvB,GAAG,QAAQ;GACX,MAAM,YAAY,GAAG,MAAM,CAAC;EAC9B;EACA,MAAM,WAAW,SAAS;EAC1B,IAAI,QAAQ;GACV,IAAI,aAAa,UAAU,aAAa,WAAW;IACjD,GAAG,SAAS;IACZ,MAAM,mBAAmB;KACvB,UAAU,UAAU;KACpB,GAAG,SAAS;IACd,CAAC;GACH,OAAO,IAAI,aAAa,eAAe,aAAa,UAAU;IAE5D,MAAM,UAAU,QAAQ,QAAQ,OAAO;IACvC,UAAU,UAAU,KAAM,KAAK,IAAI,KAAM,UAAU,GAAI,IAAI,UAAU;IACrE,GAAG,SAAS;GACd;EACF,OAAO,IAAI,aAAa,WACtB,GAAG,MAAM;OACJ,IAAI,aAAa,aAAa,aAAa,aAAa;GAC7D,IAAI,cAAc,GAChB,KAAK;QACA;IACL,GAAG,WAAW;IACd,MAAM,QAAQ,IAAI;GACpB;EACF,OAAO,IAAI,aAAa,UACtB,MAAM,YAAY,GAAG,MAAM,CAAC;EAE9B,aAAa,OAAO,aAAa,KAAK;CACxC,GAAG,CAAC,MAAM,CAAC;CAEX,MAAM,UAAU,UAAU,UAAU,cAAc;CAClD,MAAM,QAAQ,UAAU,UAAU,UAAU,YAAY,IAAI,UAAU,aAAa,CAAC,UAAU,SAAS;CACvG,MAAM,aACJ,UAAU,aAAa,CAAC,UACpB,yEACA,UAAU,cACR,aAAa,OAAO,eACpB,UAAU,WACR,WAAW,KAAK,eAChB;CACV,MAAM,QAAQ,UAAU,aAAa,UAAU,eAAe,UAAU;CACxE,OACE,oBAAC,OAAD;EACE,aAAU;EACV,MAAK;EACL,cAAY;EACZ,GAAI;EACJ,eAAa,SAAS,UAAU,WAAW,KAAA,IAAY;EACvD,cAAY;EACZ,WAAW,GAAG,6CAA6C,SAAS;EAC7D;EAEP,UAAA,oBAAC,OAAD;GACE,KAAK;GACL,aAAU;GACV,WAAU;GACV,OAAO;IACL,iBAAiB;IACjB,WAAW,UAAU,MAAM;IAC3B,SAAS,UAAU,YAAY,CAAC,QAAQ,IAAI;IAC5C;GACF;EACD,CAAA;CACE,CAAA;AAET"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ProgressLine: waits before it shows, eases while the work runs, finishes before it fades.
|
|
3
|
+
*
|
|
4
|
+
* PATH TAKEN: the phase machine is timers and state, so happy-dom with the real
|
|
5
|
+
* clock covers it (the delays are 150, 150 and 200ms, waited out with margin
|
|
6
|
+
* rather than faked). Carrying on from where the line is after more work arrives
|
|
7
|
+
* mid-fade needs a real computed transform, so e2e/progress-line.spec.ts covers it.
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The HTML the rich-text editor emits, and the only HTML RichTextContent renders. An app that
|
|
3
|
+
* sanitises on a server takes its allow-list from here: nothing outside these elements and this
|
|
4
|
+
* attribute ever comes out of the editor, whatever was pasted into it.
|
|
5
|
+
*/
|
|
6
|
+
export declare const RICH_TEXT_ELEMENTS: readonly ["p", "br", "hr", "strong", "em", "u", "ul", "ol", "li", "a"];
|
|
7
|
+
/** The attributes each element may carry. Every other element carries none (no class, no style). */
|
|
8
|
+
export declare const RICH_TEXT_ATTRIBUTES: Readonly<Record<string, readonly string[]>>;
|
|
9
|
+
/** A link must be absolute and use one of these. `javascript:`, `data:` and relative links are refused. */
|
|
10
|
+
export declare const RICH_TEXT_LINK_PROTOCOLS: readonly ["http", "https", "mailto"];
|
|
11
|
+
export declare const isAllowedRichTextHref: (href: string) => boolean;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
//#region ../ui/src/components/edyn/rich-text-content/allow-list.ts
|
|
2
|
+
/**
|
|
3
|
+
* The HTML the rich-text editor emits, and the only HTML RichTextContent renders. An app that
|
|
4
|
+
* sanitises on a server takes its allow-list from here: nothing outside these elements and this
|
|
5
|
+
* attribute ever comes out of the editor, whatever was pasted into it.
|
|
6
|
+
*/
|
|
7
|
+
var RICH_TEXT_ELEMENTS = [
|
|
8
|
+
"p",
|
|
9
|
+
"br",
|
|
10
|
+
"hr",
|
|
11
|
+
"strong",
|
|
12
|
+
"em",
|
|
13
|
+
"u",
|
|
14
|
+
"ul",
|
|
15
|
+
"ol",
|
|
16
|
+
"li",
|
|
17
|
+
"a"
|
|
18
|
+
];
|
|
19
|
+
/** The attributes each element may carry. Every other element carries none (no class, no style). */
|
|
20
|
+
var RICH_TEXT_ATTRIBUTES = { a: ["href"] };
|
|
21
|
+
/** A link must be absolute and use one of these. `javascript:`, `data:` and relative links are refused. */
|
|
22
|
+
var RICH_TEXT_LINK_PROTOCOLS = [
|
|
23
|
+
"http",
|
|
24
|
+
"https",
|
|
25
|
+
"mailto"
|
|
26
|
+
];
|
|
27
|
+
var isAllowedRichTextHref = (href) => {
|
|
28
|
+
const cleaned = Array.from(href).filter((char) => char.charCodeAt(0) > 32).join("");
|
|
29
|
+
const colon = cleaned.indexOf(":");
|
|
30
|
+
if (colon < 1) return false;
|
|
31
|
+
const protocol = cleaned.slice(0, colon).toLowerCase();
|
|
32
|
+
return RICH_TEXT_LINK_PROTOCOLS.includes(protocol);
|
|
33
|
+
};
|
|
34
|
+
//#endregion
|
|
35
|
+
export { RICH_TEXT_ATTRIBUTES, RICH_TEXT_ELEMENTS, RICH_TEXT_LINK_PROTOCOLS, isAllowedRichTextHref };
|
|
36
|
+
|
|
37
|
+
//# sourceMappingURL=allow-list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"allow-list.js","names":[],"sources":["../../../../../../../ui/src/components/edyn/rich-text-content/allow-list.ts"],"sourcesContent":["/**\n * The HTML the rich-text editor emits, and the only HTML RichTextContent renders. An app that\n * sanitises on a server takes its allow-list from here: nothing outside these elements and this\n * attribute ever comes out of the editor, whatever was pasted into it.\n */\nexport const RICH_TEXT_ELEMENTS = ['p', 'br', 'hr', 'strong', 'em', 'u', 'ul', 'ol', 'li', 'a'] as const;\n\n/** The attributes each element may carry. Every other element carries none (no class, no style). */\nexport const RICH_TEXT_ATTRIBUTES: Readonly<Record<string, readonly string[]>> = { a: ['href'] };\n\n/** A link must be absolute and use one of these. `javascript:`, `data:` and relative links are refused. */\nexport const RICH_TEXT_LINK_PROTOCOLS = ['http', 'https', 'mailto'] as const;\n\nexport const isAllowedRichTextHref = (href: string): boolean => {\n const cleaned = Array.from(href)\n .filter((char) => char.charCodeAt(0) > 32)\n .join('');\n const colon = cleaned.indexOf(':');\n if (colon < 1) {\n return false;\n }\n const protocol = cleaned.slice(0, colon).toLowerCase();\n return (RICH_TEXT_LINK_PROTOCOLS as readonly string[]).includes(protocol);\n};\n"],"mappings":";;;;;;AAKA,IAAa,qBAAqB;CAAC;CAAK;CAAM;CAAM;CAAU;CAAM;CAAK;CAAM;CAAM;CAAM;AAAG;;AAG9F,IAAa,uBAAoE,EAAE,GAAG,CAAC,MAAM,EAAE;;AAG/F,IAAa,2BAA2B;CAAC;CAAQ;CAAS;AAAQ;AAElE,IAAa,yBAAyB,SAA0B;CAC9D,MAAM,UAAU,MAAM,KAAK,IAAI,CAAC,CAC7B,QAAQ,SAAS,KAAK,WAAW,CAAC,IAAI,EAAE,CAAC,CACzC,KAAK,EAAE;CACV,MAAM,QAAQ,QAAQ,QAAQ,GAAG;CACjC,IAAI,QAAQ,GACV,OAAO;CAET,MAAM,WAAW,QAAQ,MAAM,GAAG,KAAK,CAAC,CAAC,YAAY;CACrD,OAAQ,yBAA+C,SAAS,QAAQ;AAC1E"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* How rich text looks, shared by the editor and by RichTextContent so a comment reads the same while it is typed and
|
|
4
|
+
* after it is saved. Descendant selectors rather than classes on the elements, because the HTML that is stored carries
|
|
5
|
+
* no classes.
|
|
6
|
+
*/
|
|
7
|
+
export declare const RICH_TEXT_BODY_CLASS = "text-sm leading-6 wrap-break-word [&_a]:text-primary [&_a]:underline [&_a]:underline-offset-2 [&_hr]:my-3 [&_hr]:border-0 [&_hr]:border-t [&_hr]:border-border [&_ol]:list-decimal [&_ol]:ps-5 [&_p+p]:mt-2 [&_ul]:list-disc [&_ul]:ps-5 [&_ul+p]:mt-2 [&_ol+p]:mt-2 [&_p+ul]:mt-2 [&_p+ol]:mt-2";
|
|
8
|
+
export declare const RICH_TEXT_MENTION_CLASS = "rounded-sm bg-primary/10 px-1 py-0.5 font-medium text-primary";
|
|
9
|
+
/** The HTML as React elements, keeping only what the editor can produce. Browser only (it needs a DOM parser). */
|
|
10
|
+
export declare const richTextToNodes: (html: string) => ReactNode[];
|
|
11
|
+
export interface IRichTextContentProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'dangerouslySetInnerHTML'> {
|
|
12
|
+
/** The HTML to show. Only the editor's elements are rendered, whatever else it holds. */
|
|
13
|
+
html: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Shows rich text the editor produced (or any HTML), as the same elements the editor emits and nothing else:
|
|
17
|
+
* `p`, `br`, `hr`, `strong`, `em`, `u`, `ul`, `ol`, `li` and `a` with an `href` (http, https or mailto; it opens in a new tab
|
|
18
|
+
* with `rel="noopener noreferrer"`). Everything else is dropped and its text kept. Built as React elements, not injected
|
|
19
|
+
* as markup, so it is safe on HTML that has not been cleaned. A run like `@name@example.test` or `@assignees` is shown
|
|
20
|
+
* as a chip.
|
|
21
|
+
*/
|
|
22
|
+
export declare const RichTextContent: ({ html, className, ...props }: IRichTextContentProps) => import('react').JSX.Element;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { cn } from "../../../lib/utils.js";
|
|
2
|
+
import { isAllowedRichTextHref } from "./allow-list.js";
|
|
3
|
+
import { createElement, useMemo } from "react";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
//#region ../ui/src/components/edyn/rich-text-content/rich-text-content.tsx
|
|
6
|
+
/**
|
|
7
|
+
* How rich text looks, shared by the editor and by RichTextContent so a comment reads the same while it is typed and
|
|
8
|
+
* after it is saved. Descendant selectors rather than classes on the elements, because the HTML that is stored carries
|
|
9
|
+
* no classes.
|
|
10
|
+
*/
|
|
11
|
+
var RICH_TEXT_BODY_CLASS = "text-sm leading-6 wrap-break-word [&_a]:text-primary [&_a]:underline [&_a]:underline-offset-2 [&_hr]:my-3 [&_hr]:border-0 [&_hr]:border-t [&_hr]:border-border [&_ol]:list-decimal [&_ol]:ps-5 [&_p+p]:mt-2 [&_ul]:list-disc [&_ul]:ps-5 [&_ul+p]:mt-2 [&_ol+p]:mt-2 [&_p+ul]:mt-2 [&_p+ol]:mt-2";
|
|
12
|
+
var MENTION_PATTERN = /(?<![\w.+-])@(?:assignees\b|[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)+)/g;
|
|
13
|
+
var RICH_TEXT_MENTION_CLASS = "rounded-sm bg-primary/10 px-1 py-0.5 font-medium text-primary";
|
|
14
|
+
var TAG_FOR = {
|
|
15
|
+
b: "strong",
|
|
16
|
+
i: "em"
|
|
17
|
+
};
|
|
18
|
+
var KEPT = /* @__PURE__ */ new Set([
|
|
19
|
+
"p",
|
|
20
|
+
"strong",
|
|
21
|
+
"em",
|
|
22
|
+
"u",
|
|
23
|
+
"ul",
|
|
24
|
+
"ol",
|
|
25
|
+
"li",
|
|
26
|
+
"a",
|
|
27
|
+
"br",
|
|
28
|
+
"hr"
|
|
29
|
+
]);
|
|
30
|
+
var DROPPED_WITH_CONTENT = /* @__PURE__ */ new Set([
|
|
31
|
+
"script",
|
|
32
|
+
"style",
|
|
33
|
+
"template",
|
|
34
|
+
"iframe",
|
|
35
|
+
"object",
|
|
36
|
+
"embed",
|
|
37
|
+
"noscript",
|
|
38
|
+
"svg",
|
|
39
|
+
"math",
|
|
40
|
+
"head",
|
|
41
|
+
"title"
|
|
42
|
+
]);
|
|
43
|
+
var withMentions = (text, key) => {
|
|
44
|
+
const parts = [];
|
|
45
|
+
let last = 0;
|
|
46
|
+
for (const match of text.matchAll(MENTION_PATTERN)) {
|
|
47
|
+
const start = match.index ?? 0;
|
|
48
|
+
if (start > last) parts.push(text.slice(last, start));
|
|
49
|
+
parts.push(/* @__PURE__ */ jsx("span", {
|
|
50
|
+
"data-slot": "rich-text-mention",
|
|
51
|
+
className: RICH_TEXT_MENTION_CLASS,
|
|
52
|
+
children: match[0]
|
|
53
|
+
}, `${key}-${start}`));
|
|
54
|
+
last = start + match[0].length;
|
|
55
|
+
}
|
|
56
|
+
if (last < text.length) parts.push(text.slice(last));
|
|
57
|
+
return parts;
|
|
58
|
+
};
|
|
59
|
+
var toNodes = (parent, key, insideLink) => {
|
|
60
|
+
const out = [];
|
|
61
|
+
parent.childNodes.forEach((child, index) => {
|
|
62
|
+
const childKey = `${key}.${index}`;
|
|
63
|
+
if (child.nodeType === 3) {
|
|
64
|
+
const text = child.textContent ?? "";
|
|
65
|
+
out.push(...insideLink ? [text] : withMentions(text, childKey));
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (child.nodeType !== 1) return;
|
|
69
|
+
const element = child;
|
|
70
|
+
const name = element.tagName.toLowerCase();
|
|
71
|
+
if (DROPPED_WITH_CONTENT.has(name)) return;
|
|
72
|
+
const tag = TAG_FOR[name] ?? name;
|
|
73
|
+
if (!KEPT.has(tag)) {
|
|
74
|
+
out.push(...toNodes(element, childKey, insideLink));
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (tag === "br") {
|
|
78
|
+
out.push(/* @__PURE__ */ jsx("br", {}, childKey));
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (tag === "hr") {
|
|
82
|
+
out.push(/* @__PURE__ */ jsx("hr", {}, childKey));
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (tag === "a") {
|
|
86
|
+
const href = element.getAttribute("href") ?? "";
|
|
87
|
+
const inner = toNodes(element, childKey, true);
|
|
88
|
+
out.push(...isAllowedRichTextHref(href) ? [/* @__PURE__ */ jsx("a", {
|
|
89
|
+
href: href.trim(),
|
|
90
|
+
rel: "noopener noreferrer",
|
|
91
|
+
target: "_blank",
|
|
92
|
+
children: inner
|
|
93
|
+
}, childKey)] : inner);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
out.push(createElement(tag, { key: childKey }, ...toNodes(element, childKey, insideLink)));
|
|
97
|
+
});
|
|
98
|
+
return out;
|
|
99
|
+
};
|
|
100
|
+
/** The HTML as React elements, keeping only what the editor can produce. Browser only (it needs a DOM parser). */
|
|
101
|
+
var richTextToNodes = (html) => {
|
|
102
|
+
if (typeof DOMParser === "undefined" || html === "") return [];
|
|
103
|
+
return toNodes(new DOMParser().parseFromString(`<body>${html}`, "text/html").body, "r", false);
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* Shows rich text the editor produced (or any HTML), as the same elements the editor emits and nothing else:
|
|
107
|
+
* `p`, `br`, `hr`, `strong`, `em`, `u`, `ul`, `ol`, `li` and `a` with an `href` (http, https or mailto; it opens in a new tab
|
|
108
|
+
* with `rel="noopener noreferrer"`). Everything else is dropped and its text kept. Built as React elements, not injected
|
|
109
|
+
* as markup, so it is safe on HTML that has not been cleaned. A run like `@name@example.test` or `@assignees` is shown
|
|
110
|
+
* as a chip.
|
|
111
|
+
*/
|
|
112
|
+
var RichTextContent = ({ html, className, ...props }) => {
|
|
113
|
+
const nodes = useMemo(() => richTextToNodes(html), [html]);
|
|
114
|
+
return /* @__PURE__ */ jsx("div", {
|
|
115
|
+
"data-slot": "rich-text-content",
|
|
116
|
+
className: cn(RICH_TEXT_BODY_CLASS, className),
|
|
117
|
+
...props,
|
|
118
|
+
children: nodes
|
|
119
|
+
});
|
|
120
|
+
};
|
|
121
|
+
//#endregion
|
|
122
|
+
export { RICH_TEXT_BODY_CLASS, RICH_TEXT_MENTION_CLASS, RichTextContent, richTextToNodes };
|
|
123
|
+
|
|
124
|
+
//# sourceMappingURL=rich-text-content.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rich-text-content.js","names":[],"sources":["../../../../../../../ui/src/components/edyn/rich-text-content/rich-text-content.tsx"],"sourcesContent":["import { cn } from '@edyn/ui/lib/utils';\nimport { createElement, type HTMLAttributes, type ReactNode, useMemo } from 'react';\nimport { isAllowedRichTextHref } from './allow-list';\n\n/**\n * How rich text looks, shared by the editor and by RichTextContent so a comment reads the same while it is typed and\n * after it is saved. Descendant selectors rather than classes on the elements, because the HTML that is stored carries\n * no classes.\n */\nexport const RICH_TEXT_BODY_CLASS =\n 'text-sm leading-6 wrap-break-word [&_a]:text-primary [&_a]:underline [&_a]:underline-offset-2 [&_hr]:my-3 [&_hr]:border-0 [&_hr]:border-t [&_hr]:border-border [&_ol]:list-decimal [&_ol]:ps-5 [&_p+p]:mt-2 [&_ul]:list-disc [&_ul]:ps-5 [&_ul+p]:mt-2 [&_ol+p]:mt-2 [&_p+ul]:mt-2 [&_p+ol]:mt-2';\n\nconst MENTION_PATTERN = /(?<![\\w.+-])@(?:assignees\\b|[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(?:\\.[A-Za-z0-9-]+)+)/g;\n\nexport const RICH_TEXT_MENTION_CLASS = 'rounded-sm bg-primary/10 px-1 py-0.5 font-medium text-primary';\n\nconst TAG_FOR: Readonly<Record<string, string>> = { b: 'strong', i: 'em' };\nconst KEPT = new Set(['p', 'strong', 'em', 'u', 'ul', 'ol', 'li', 'a', 'br', 'hr']);\nconst DROPPED_WITH_CONTENT = new Set(['script', 'style', 'template', 'iframe', 'object', 'embed', 'noscript', 'svg', 'math', 'head', 'title']);\n\nconst withMentions = (text: string, key: string): ReactNode[] => {\n const parts: ReactNode[] = [];\n let last = 0;\n for (const match of text.matchAll(MENTION_PATTERN)) {\n const start = match.index ?? 0;\n if (start > last) {\n parts.push(text.slice(last, start));\n }\n parts.push(\n <span key={`${key}-${start}`} data-slot=\"rich-text-mention\" className={RICH_TEXT_MENTION_CLASS}>\n {match[0]}\n </span>,\n );\n last = start + match[0].length;\n }\n if (last < text.length) {\n parts.push(text.slice(last));\n }\n return parts;\n};\n\nconst toNodes = (parent: Node, key: string, insideLink: boolean): ReactNode[] => {\n const out: ReactNode[] = [];\n parent.childNodes.forEach((child, index) => {\n const childKey = `${key}.${index}`;\n if (child.nodeType === 3) {\n const text = child.textContent ?? '';\n out.push(...(insideLink ? [text] : withMentions(text, childKey)));\n return;\n }\n if (child.nodeType !== 1) {\n return;\n }\n const element = child as Element;\n const name = element.tagName.toLowerCase();\n if (DROPPED_WITH_CONTENT.has(name)) {\n return;\n }\n const tag = TAG_FOR[name] ?? name;\n if (!KEPT.has(tag)) {\n out.push(...toNodes(element, childKey, insideLink));\n return;\n }\n if (tag === 'br') {\n out.push(<br key={childKey} />);\n return;\n }\n if (tag === 'hr') {\n out.push(<hr key={childKey} />);\n return;\n }\n if (tag === 'a') {\n const href = element.getAttribute('href') ?? '';\n const inner = toNodes(element, childKey, true);\n out.push(\n ...(isAllowedRichTextHref(href)\n ? [\n <a key={childKey} href={href.trim()} rel=\"noopener noreferrer\" target=\"_blank\">\n {inner}\n </a>,\n ]\n : inner),\n );\n return;\n }\n out.push(createElement(tag, { key: childKey }, ...toNodes(element, childKey, insideLink)));\n });\n return out;\n};\n\n/** The HTML as React elements, keeping only what the editor can produce. Browser only (it needs a DOM parser). */\nexport const richTextToNodes = (html: string): ReactNode[] => {\n if (typeof DOMParser === 'undefined' || html === '') {\n return [];\n }\n const parsed = new DOMParser().parseFromString(`<body>${html}`, 'text/html');\n return toNodes(parsed.body, 'r', false);\n};\n\nexport interface IRichTextContentProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'dangerouslySetInnerHTML'> {\n /** The HTML to show. Only the editor's elements are rendered, whatever else it holds. */\n html: string;\n}\n\n/**\n * Shows rich text the editor produced (or any HTML), as the same elements the editor emits and nothing else:\n * `p`, `br`, `hr`, `strong`, `em`, `u`, `ul`, `ol`, `li` and `a` with an `href` (http, https or mailto; it opens in a new tab\n * with `rel=\"noopener noreferrer\"`). Everything else is dropped and its text kept. Built as React elements, not injected\n * as markup, so it is safe on HTML that has not been cleaned. A run like `@name@example.test` or `@assignees` is shown\n * as a chip.\n */\nexport const RichTextContent = ({ html, className, ...props }: IRichTextContentProps) => {\n const nodes = useMemo(() => richTextToNodes(html), [html]);\n return (\n <div data-slot=\"rich-text-content\" className={cn(RICH_TEXT_BODY_CLASS, className)} {...props}>\n {nodes}\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;AASA,IAAa,uBACX;AAEF,IAAM,kBAAkB;AAExB,IAAa,0BAA0B;AAEvC,IAAM,UAA4C;CAAE,GAAG;CAAU,GAAG;AAAK;AACzE,IAAM,uBAAO,IAAI,IAAI;CAAC;CAAK;CAAU;CAAM;CAAK;CAAM;CAAM;CAAM;CAAK;CAAM;AAAI,CAAC;AAClF,IAAM,uCAAuB,IAAI,IAAI;CAAC;CAAU;CAAS;CAAY;CAAU;CAAU;CAAS;CAAY;CAAO;CAAQ;CAAQ;AAAO,CAAC;AAE7I,IAAM,gBAAgB,MAAc,QAA6B;CAC/D,MAAM,QAAqB,CAAC;CAC5B,IAAI,OAAO;CACX,KAAK,MAAM,SAAS,KAAK,SAAS,eAAe,GAAG;EAClD,MAAM,QAAQ,MAAM,SAAS;EAC7B,IAAI,QAAQ,MACV,MAAM,KAAK,KAAK,MAAM,MAAM,KAAK,CAAC;EAEpC,MAAM,KACJ,oBAAC,QAAD;GAA8B,aAAU;GAAoB,WAAW;GACpE,UAAA,MAAM;EACH,GAFK,GAAG,IAAI,GAAG,OAEf,CACR;EACA,OAAO,QAAQ,MAAM,EAAE,CAAC;CAC1B;CACA,IAAI,OAAO,KAAK,QACd,MAAM,KAAK,KAAK,MAAM,IAAI,CAAC;CAE7B,OAAO;AACT;AAEA,IAAM,WAAW,QAAc,KAAa,eAAqC;CAC/E,MAAM,MAAmB,CAAC;CAC1B,OAAO,WAAW,SAAS,OAAO,UAAU;EAC1C,MAAM,WAAW,GAAG,IAAI,GAAG;EAC3B,IAAI,MAAM,aAAa,GAAG;GACxB,MAAM,OAAO,MAAM,eAAe;GAClC,IAAI,KAAK,GAAI,aAAa,CAAC,IAAI,IAAI,aAAa,MAAM,QAAQ,CAAE;GAChE;EACF;EACA,IAAI,MAAM,aAAa,GACrB;EAEF,MAAM,UAAU;EAChB,MAAM,OAAO,QAAQ,QAAQ,YAAY;EACzC,IAAI,qBAAqB,IAAI,IAAI,GAC/B;EAEF,MAAM,MAAM,QAAQ,SAAS;EAC7B,IAAI,CAAC,KAAK,IAAI,GAAG,GAAG;GAClB,IAAI,KAAK,GAAG,QAAQ,SAAS,UAAU,UAAU,CAAC;GAClD;EACF;EACA,IAAI,QAAQ,MAAM;GAChB,IAAI,KAAK,oBAAC,MAAD,CAAoB,GAAX,QAAW,CAAC;GAC9B;EACF;EACA,IAAI,QAAQ,MAAM;GAChB,IAAI,KAAK,oBAAC,MAAD,CAAoB,GAAX,QAAW,CAAC;GAC9B;EACF;EACA,IAAI,QAAQ,KAAK;GACf,MAAM,OAAO,QAAQ,aAAa,MAAM,KAAK;GAC7C,MAAM,QAAQ,QAAQ,SAAS,UAAU,IAAI;GAC7C,IAAI,KACF,GAAI,sBAAsB,IAAI,IAC1B,CACE,oBAAC,KAAD;IAAkB,MAAM,KAAK,KAAK;IAAG,KAAI;IAAsB,QAAO;IACnE,UAAA;GACA,GAFK,QAEL,CACL,IACA,KACN;GACA;EACF;EACA,IAAI,KAAK,cAAc,KAAK,EAAE,KAAK,SAAS,GAAG,GAAG,QAAQ,SAAS,UAAU,UAAU,CAAC,CAAC;CAC3F,CAAC;CACD,OAAO;AACT;;AAGA,IAAa,mBAAmB,SAA8B;CAC5D,IAAI,OAAO,cAAc,eAAe,SAAS,IAC/C,OAAO,CAAC;CAGV,OAAO,QADQ,IAAI,UAAU,CAAC,CAAC,gBAAgB,SAAS,QAAQ,WACjD,CAAA,CAAO,MAAM,KAAK,KAAK;AACxC;;;;;;;;AAcA,IAAa,mBAAmB,EAAE,MAAM,WAAW,GAAG,YAAmC;CACvF,MAAM,QAAQ,cAAc,gBAAgB,IAAI,GAAG,CAAC,IAAI,CAAC;CACzD,OACE,oBAAC,OAAD;EAAK,aAAU;EAAoB,WAAW,GAAG,sBAAsB,SAAS;EAAG,GAAI;EACpF,UAAA;CACE,CAAA;AAET"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RichTextContent shows saved HTML as the editor's own elements and nothing else. It is built as React elements,
|
|
3
|
+
* so these assertions read the markup it renders: a script or a javascript: link that survived would show here.
|
|
4
|
+
*
|
|
5
|
+
* PATH TAKEN: happy-dom parses the input (DOMParser) and renderToStaticMarkup prints the result, which is enough
|
|
6
|
+
* for what this component decides (what stays, what goes, what is added). How it looks is the browser spec's.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Extension } from '@tiptap/core';
|
|
2
|
+
import { SuggestionKeyDownProps, SuggestionProps } from '@tiptap/suggestion';
|
|
3
|
+
import { TMentionToText } from './serialize';
|
|
4
|
+
import { IRichTextMentionItem } from './types';
|
|
5
|
+
/** What the editor needs from the component while it runs. Held in a ref, so the extensions are built once. */
|
|
6
|
+
export interface IEditorHost {
|
|
7
|
+
mentionEnabled: () => boolean;
|
|
8
|
+
maxLength: () => number | undefined;
|
|
9
|
+
toText: () => TMentionToText;
|
|
10
|
+
onSuggestion: (props: SuggestionProps<IRichTextMentionItem, IRichTextMentionItem> | null) => void;
|
|
11
|
+
onSuggestionKey: (props: SuggestionKeyDownProps) => boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The editor's whole schema: paragraph, line break, bold, italic, underline, bullet and numbered lists, link, and the
|
|
15
|
+
* mention chip. Whatever else arrives (a paste, `value`) is not in the schema, so ProseMirror drops the markup and keeps
|
|
16
|
+
* the text.
|
|
17
|
+
*/
|
|
18
|
+
export declare const buildExtensions: (host: IEditorHost) => (Extension<any, any> | import('@tiptap/core').Node<any, any> | import('@tiptap/core').Node<import('@tiptap/extension-paragraph').ParagraphOptions, any> | import('@tiptap/core').Node<import('@tiptap/extension-hard-break').HardBreakOptions, any> | import('@tiptap/core').Mark<import('@tiptap/extension-bold').BoldOptions, any> | import('@tiptap/core').Node<import('@tiptap/extension-list').BulletListOptions, any> | import('@tiptap/core').Node<import('@tiptap/extension-list').ListItemOptions, any> | import('@tiptap/core').Node<import('@tiptap/extension-horizontal-rule').HorizontalRuleOptions, any> | import('@tiptap/core').Mark<import('@tiptap/extension-link').LinkOptions, any> | Extension<import('@tiptap/extensions').UndoRedoOptions, any> | import('@tiptap/core').Node<import('@tiptap/extension-mention').MentionOptions<any, import('@tiptap/extension-mention').MentionNodeAttrs>, any>)[];
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { isAllowedRichTextHref } from "../rich-text-content/allow-list.js";
|
|
2
|
+
import { countCharacters } from "./serialize.js";
|
|
3
|
+
import { Extension, mergeAttributes } from "@tiptap/core";
|
|
4
|
+
import { Bold } from "@tiptap/extension-bold";
|
|
5
|
+
import { Document } from "@tiptap/extension-document";
|
|
6
|
+
import { HardBreak } from "@tiptap/extension-hard-break";
|
|
7
|
+
import { HorizontalRule } from "@tiptap/extension-horizontal-rule";
|
|
8
|
+
import { Italic } from "@tiptap/extension-italic";
|
|
9
|
+
import { Link } from "@tiptap/extension-link";
|
|
10
|
+
import { BulletList, ListItem, OrderedList } from "@tiptap/extension-list";
|
|
11
|
+
import { Mention } from "@tiptap/extension-mention";
|
|
12
|
+
import { Paragraph } from "@tiptap/extension-paragraph";
|
|
13
|
+
import { Text } from "@tiptap/extension-text";
|
|
14
|
+
import { Underline } from "@tiptap/extension-underline";
|
|
15
|
+
import { UndoRedo } from "@tiptap/extensions";
|
|
16
|
+
import { Plugin, PluginKey } from "@tiptap/pm/state";
|
|
17
|
+
//#region ../ui/src/components/edyn/rich-text-editor/extensions.ts
|
|
18
|
+
var MENTION_CHIP_CLASS = "rounded-sm bg-primary/10 px-1 py-0.5 font-medium text-primary";
|
|
19
|
+
var limitKey = new PluginKey("richTextMaxLength");
|
|
20
|
+
/** Refuses an edit that would take the text over the limit (a paste included) and lets one that shortens it through. */
|
|
21
|
+
var maxLengthExtension = (host) => Extension.create({
|
|
22
|
+
name: "maxLength",
|
|
23
|
+
addProseMirrorPlugins() {
|
|
24
|
+
return [new Plugin({
|
|
25
|
+
key: limitKey,
|
|
26
|
+
filterTransaction: (tr, state) => {
|
|
27
|
+
const limit = host.maxLength();
|
|
28
|
+
if (!tr.docChanged || limit === void 0) return true;
|
|
29
|
+
const next = countCharacters(tr.doc, host.toText());
|
|
30
|
+
return next <= limit || next <= countCharacters(state.doc, host.toText());
|
|
31
|
+
}
|
|
32
|
+
})];
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
/**
|
|
36
|
+
* The editor's whole schema: paragraph, line break, bold, italic, underline, bullet and numbered lists, link, and the
|
|
37
|
+
* mention chip. Whatever else arrives (a paste, `value`) is not in the schema, so ProseMirror drops the markup and keeps
|
|
38
|
+
* the text.
|
|
39
|
+
*/
|
|
40
|
+
var buildExtensions = (host) => [
|
|
41
|
+
Document,
|
|
42
|
+
Paragraph,
|
|
43
|
+
Text,
|
|
44
|
+
HardBreak,
|
|
45
|
+
Bold,
|
|
46
|
+
Italic,
|
|
47
|
+
Underline,
|
|
48
|
+
BulletList,
|
|
49
|
+
OrderedList.extend({ addAttributes() {
|
|
50
|
+
return {};
|
|
51
|
+
} }),
|
|
52
|
+
ListItem,
|
|
53
|
+
HorizontalRule,
|
|
54
|
+
Link.extend({ addAttributes() {
|
|
55
|
+
return { href: {
|
|
56
|
+
default: null,
|
|
57
|
+
parseHTML: (element) => element.getAttribute("href"),
|
|
58
|
+
renderHTML: (attributes) => attributes.href ? { href: attributes.href } : {}
|
|
59
|
+
} };
|
|
60
|
+
} }).configure({
|
|
61
|
+
openOnClick: false,
|
|
62
|
+
autolink: true,
|
|
63
|
+
linkOnPaste: true,
|
|
64
|
+
defaultProtocol: "https",
|
|
65
|
+
protocols: ["mailto"],
|
|
66
|
+
isAllowedUri: (url) => isAllowedRichTextHref(url),
|
|
67
|
+
HTMLAttributes: {
|
|
68
|
+
rel: null,
|
|
69
|
+
target: null,
|
|
70
|
+
class: null
|
|
71
|
+
}
|
|
72
|
+
}),
|
|
73
|
+
UndoRedo,
|
|
74
|
+
maxLengthExtension(host),
|
|
75
|
+
Mention.extend({ addAttributes() {
|
|
76
|
+
return {
|
|
77
|
+
id: {
|
|
78
|
+
default: null,
|
|
79
|
+
parseHTML: (element) => element.getAttribute("data-id"),
|
|
80
|
+
renderHTML: (attributes) => attributes.id ? { "data-id": attributes.id } : {}
|
|
81
|
+
},
|
|
82
|
+
label: {
|
|
83
|
+
default: null,
|
|
84
|
+
parseHTML: (element) => element.getAttribute("data-label"),
|
|
85
|
+
renderHTML: (attributes) => attributes.label ? { "data-label": attributes.label } : {}
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
} }).configure({
|
|
89
|
+
HTMLAttributes: { class: MENTION_CHIP_CLASS },
|
|
90
|
+
renderText: ({ node }) => `@${node.attrs.label ?? node.attrs.id}`,
|
|
91
|
+
renderHTML: ({ options, node }) => [
|
|
92
|
+
"span",
|
|
93
|
+
mergeAttributes(options.HTMLAttributes),
|
|
94
|
+
`@${node.attrs.label ?? node.attrs.id}`
|
|
95
|
+
],
|
|
96
|
+
suggestion: {
|
|
97
|
+
char: "@",
|
|
98
|
+
allow: () => host.mentionEnabled(),
|
|
99
|
+
items: () => [],
|
|
100
|
+
command: ({ editor, range, props }) => {
|
|
101
|
+
editor.chain().focus().insertContentAt(range, [{
|
|
102
|
+
type: "mention",
|
|
103
|
+
attrs: {
|
|
104
|
+
id: props.id,
|
|
105
|
+
label: props.label
|
|
106
|
+
}
|
|
107
|
+
}, {
|
|
108
|
+
type: "text",
|
|
109
|
+
text: " "
|
|
110
|
+
}]).run();
|
|
111
|
+
},
|
|
112
|
+
render: () => ({
|
|
113
|
+
onStart: (props) => host.onSuggestion(props),
|
|
114
|
+
onUpdate: (props) => host.onSuggestion(props),
|
|
115
|
+
onKeyDown: (props) => host.onSuggestionKey(props),
|
|
116
|
+
onExit: () => host.onSuggestion(null)
|
|
117
|
+
})
|
|
118
|
+
}
|
|
119
|
+
})
|
|
120
|
+
];
|
|
121
|
+
//#endregion
|
|
122
|
+
export { buildExtensions };
|
|
123
|
+
|
|
124
|
+
//# sourceMappingURL=extensions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extensions.js","names":[],"sources":["../../../../../../../ui/src/components/edyn/rich-text-editor/extensions.ts"],"sourcesContent":["import { isAllowedRichTextHref } from '@edyn/ui/components/edyn/rich-text-content/allow-list';\nimport { Extension, mergeAttributes } from '@tiptap/core';\nimport { Bold } from '@tiptap/extension-bold';\nimport { Document } from '@tiptap/extension-document';\nimport { HardBreak } from '@tiptap/extension-hard-break';\nimport { HorizontalRule } from '@tiptap/extension-horizontal-rule';\nimport { Italic } from '@tiptap/extension-italic';\nimport { Link } from '@tiptap/extension-link';\nimport { BulletList, ListItem, OrderedList } from '@tiptap/extension-list';\nimport { Mention } from '@tiptap/extension-mention';\nimport { Paragraph } from '@tiptap/extension-paragraph';\nimport { Text } from '@tiptap/extension-text';\nimport { Underline } from '@tiptap/extension-underline';\nimport { UndoRedo } from '@tiptap/extensions';\nimport { Plugin, PluginKey } from '@tiptap/pm/state';\nimport type { SuggestionKeyDownProps, SuggestionProps } from '@tiptap/suggestion';\nimport { countCharacters, type TMentionToText } from './serialize';\nimport type { IRichTextMentionItem } from './types';\n\n/** What the editor needs from the component while it runs. Held in a ref, so the extensions are built once. */\nexport interface IEditorHost {\n mentionEnabled: () => boolean;\n maxLength: () => number | undefined;\n toText: () => TMentionToText;\n onSuggestion: (props: SuggestionProps<IRichTextMentionItem, IRichTextMentionItem> | null) => void;\n onSuggestionKey: (props: SuggestionKeyDownProps) => boolean;\n}\n\nconst MENTION_CHIP_CLASS = 'rounded-sm bg-primary/10 px-1 py-0.5 font-medium text-primary';\n\nconst limitKey = new PluginKey('richTextMaxLength');\n\n/** Refuses an edit that would take the text over the limit (a paste included) and lets one that shortens it through. */\nconst maxLengthExtension = (host: IEditorHost) =>\n Extension.create({\n name: 'maxLength',\n addProseMirrorPlugins() {\n return [\n new Plugin({\n key: limitKey,\n filterTransaction: (tr, state) => {\n const limit = host.maxLength();\n if (!tr.docChanged || limit === undefined) {\n return true;\n }\n const next = countCharacters(tr.doc, host.toText());\n return next <= limit || next <= countCharacters(state.doc, host.toText());\n },\n }),\n ];\n },\n });\n\n/**\n * The editor's whole schema: paragraph, line break, bold, italic, underline, bullet and numbered lists, link, and the\n * mention chip. Whatever else arrives (a paste, `value`) is not in the schema, so ProseMirror drops the markup and keeps\n * the text.\n */\nexport const buildExtensions = (host: IEditorHost) => [\n Document,\n Paragraph,\n Text,\n HardBreak,\n Bold,\n Italic,\n Underline,\n BulletList,\n // A list is numbered from 1; the `start` it would otherwise keep is an attribute outside the allow-list.\n OrderedList.extend({\n addAttributes() {\n return {};\n },\n }),\n ListItem,\n HorizontalRule,\n Link.extend({\n addAttributes() {\n return {\n href: {\n default: null,\n parseHTML: (element) => element.getAttribute('href'),\n renderHTML: (attributes) => (attributes.href ? { href: attributes.href } : {}),\n },\n };\n },\n }).configure({\n openOnClick: false,\n autolink: true,\n linkOnPaste: true,\n defaultProtocol: 'https',\n protocols: ['mailto'],\n isAllowedUri: (url) => isAllowedRichTextHref(url),\n HTMLAttributes: { rel: null, target: null, class: null },\n }),\n UndoRedo,\n maxLengthExtension(host),\n Mention.extend({\n addAttributes() {\n return {\n id: {\n default: null,\n parseHTML: (element) => element.getAttribute('data-id'),\n renderHTML: (attributes) => (attributes.id ? { 'data-id': attributes.id } : {}),\n },\n label: {\n default: null,\n parseHTML: (element) => element.getAttribute('data-label'),\n renderHTML: (attributes) => (attributes.label ? { 'data-label': attributes.label } : {}),\n },\n };\n },\n }).configure({\n HTMLAttributes: { class: MENTION_CHIP_CLASS },\n renderText: ({ node }) => `@${node.attrs.label ?? node.attrs.id}`,\n renderHTML: ({ options, node }) => ['span', mergeAttributes(options.HTMLAttributes), `@${node.attrs.label ?? node.attrs.id}`],\n suggestion: {\n char: '@',\n allow: () => host.mentionEnabled(),\n items: () => [],\n command: ({ editor, range, props }) => {\n editor\n .chain()\n .focus()\n .insertContentAt(range, [\n { type: 'mention', attrs: { id: props.id, label: props.label } },\n { type: 'text', text: ' ' },\n ])\n .run();\n },\n render: () => ({\n onStart: (props) => host.onSuggestion(props),\n onUpdate: (props) => host.onSuggestion(props),\n onKeyDown: (props) => host.onSuggestionKey(props),\n onExit: () => host.onSuggestion(null),\n }),\n },\n }),\n];\n"],"mappings":";;;;;;;;;;;;;;;;;AA4BA,IAAM,qBAAqB;AAE3B,IAAM,WAAW,IAAI,UAAU,mBAAmB;;AAGlD,IAAM,sBAAsB,SAC1B,UAAU,OAAO;CACf,MAAM;CACN,wBAAwB;EACtB,OAAO,CACL,IAAI,OAAO;GACT,KAAK;GACL,oBAAoB,IAAI,UAAU;IAChC,MAAM,QAAQ,KAAK,UAAU;IAC7B,IAAI,CAAC,GAAG,cAAc,UAAU,KAAA,GAC9B,OAAO;IAET,MAAM,OAAO,gBAAgB,GAAG,KAAK,KAAK,OAAO,CAAC;IAClD,OAAO,QAAQ,SAAS,QAAQ,gBAAgB,MAAM,KAAK,KAAK,OAAO,CAAC;GAC1E;EACF,CAAC,CACH;CACF;AACF,CAAC;;;;;;AAOH,IAAa,mBAAmB,SAAsB;CACpD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAEA,YAAY,OAAO,EACjB,gBAAgB;EACd,OAAO,CAAC;CACV,EACF,CAAC;CACD;CACA;CACA,KAAK,OAAO,EACV,gBAAgB;EACd,OAAO,EACL,MAAM;GACJ,SAAS;GACT,YAAY,YAAY,QAAQ,aAAa,MAAM;GACnD,aAAa,eAAgB,WAAW,OAAO,EAAE,MAAM,WAAW,KAAK,IAAI,CAAC;EAC9E,EACF;CACF,EACF,CAAC,CAAC,CAAC,UAAU;EACX,aAAa;EACb,UAAU;EACV,aAAa;EACb,iBAAiB;EACjB,WAAW,CAAC,QAAQ;EACpB,eAAe,QAAQ,sBAAsB,GAAG;EAChD,gBAAgB;GAAE,KAAK;GAAM,QAAQ;GAAM,OAAO;EAAK;CACzD,CAAC;CACD;CACA,mBAAmB,IAAI;CACvB,QAAQ,OAAO,EACb,gBAAgB;EACd,OAAO;GACL,IAAI;IACF,SAAS;IACT,YAAY,YAAY,QAAQ,aAAa,SAAS;IACtD,aAAa,eAAgB,WAAW,KAAK,EAAE,WAAW,WAAW,GAAG,IAAI,CAAC;GAC/E;GACA,OAAO;IACL,SAAS;IACT,YAAY,YAAY,QAAQ,aAAa,YAAY;IACzD,aAAa,eAAgB,WAAW,QAAQ,EAAE,cAAc,WAAW,MAAM,IAAI,CAAC;GACxF;EACF;CACF,EACF,CAAC,CAAC,CAAC,UAAU;EACX,gBAAgB,EAAE,OAAO,mBAAmB;EAC5C,aAAa,EAAE,WAAW,IAAI,KAAK,MAAM,SAAS,KAAK,MAAM;EAC7D,aAAa,EAAE,SAAS,WAAW;GAAC;GAAQ,gBAAgB,QAAQ,cAAc;GAAG,IAAI,KAAK,MAAM,SAAS,KAAK,MAAM;EAAI;EAC5H,YAAY;GACV,MAAM;GACN,aAAa,KAAK,eAAe;GACjC,aAAa,CAAC;GACd,UAAU,EAAE,QAAQ,OAAO,YAAY;IACrC,OACG,MAAM,CAAC,CACP,MAAM,CAAC,CACP,gBAAgB,OAAO,CACtB;KAAE,MAAM;KAAW,OAAO;MAAE,IAAI,MAAM;MAAI,OAAO,MAAM;KAAM;IAAE,GAC/D;KAAE,MAAM;KAAQ,MAAM;IAAI,CAC5B,CAAC,CAAC,CACD,IAAI;GACT;GACA,eAAe;IACb,UAAU,UAAU,KAAK,aAAa,KAAK;IAC3C,WAAW,UAAU,KAAK,aAAa,KAAK;IAC5C,YAAY,UAAU,KAAK,gBAAgB,KAAK;IAChD,cAAc,KAAK,aAAa,IAAI;GACtC;EACF;CACF,CAAC;AACH"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
import { IRichTextLabels, IRichTextMention, IRichTextMentionItem } from './types';
|
|
3
|
+
export interface IMentionListProps {
|
|
4
|
+
query: string;
|
|
5
|
+
/** Where the @ was typed. */
|
|
6
|
+
rect: (() => DOMRect | null) | null;
|
|
7
|
+
config: IRichTextMention;
|
|
8
|
+
labels: IRichTextLabels;
|
|
9
|
+
listId: string;
|
|
10
|
+
onPick: (item: IRichTextMentionItem) => void;
|
|
11
|
+
/** The editor keeps focus, so the list is driven by its keys: the editor calls this one. */
|
|
12
|
+
keyHandler: RefObject<((event: KeyboardEvent) => boolean) | null>;
|
|
13
|
+
/** The id of the option the editor should name as `aria-activedescendant`. */
|
|
14
|
+
onActiveChange: (optionId: string | undefined) => void;
|
|
15
|
+
}
|
|
16
|
+
/** The list that opens under the caret when the writer types @. */
|
|
17
|
+
export declare const MentionList: ({ query, rect, config, labels, listId, onPick, keyHandler, onActiveChange }: IMentionListProps) => import('react').JSX.Element;
|