@olddevs/ui 0.0.0-stage → 4.0.0
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/CHANGELOG.md +13 -0
- package/LICENSE +21 -0
- package/NOTICE +100 -0
- package/README.md +145 -2
- package/README.ru.md +146 -0
- package/dist/color.d.ts +22 -0
- package/dist/color.d.ts.map +1 -0
- package/dist/color.js +2 -0
- package/dist/color.js.map +1 -0
- package/dist/components/actions/Alert.d.ts +46 -0
- package/dist/components/actions/Alert.d.ts.map +1 -0
- package/dist/components/actions/Alert.js +20 -0
- package/dist/components/actions/Alert.js.map +1 -0
- package/dist/components/actions/Banner.d.ts +58 -0
- package/dist/components/actions/Banner.d.ts.map +1 -0
- package/dist/components/actions/Banner.js +20 -0
- package/dist/components/actions/Banner.js.map +1 -0
- package/dist/components/actions/Button.d.ts +79 -0
- package/dist/components/actions/Button.d.ts.map +1 -0
- package/dist/components/actions/Button.js +29 -0
- package/dist/components/actions/Button.js.map +1 -0
- package/dist/components/actions/ButtonGroup.d.ts +32 -0
- package/dist/components/actions/ButtonGroup.d.ts.map +1 -0
- package/dist/components/actions/ButtonGroup.js +10 -0
- package/dist/components/actions/ButtonGroup.js.map +1 -0
- package/dist/components/actions/Chip.d.ts +36 -0
- package/dist/components/actions/Chip.d.ts.map +1 -0
- package/dist/components/actions/Chip.js +16 -0
- package/dist/components/actions/Chip.js.map +1 -0
- package/dist/components/actions/CopyButton.d.ts +32 -0
- package/dist/components/actions/CopyButton.d.ts.map +1 -0
- package/dist/components/actions/CopyButton.js +41 -0
- package/dist/components/actions/CopyButton.js.map +1 -0
- package/dist/components/actions/Progress.d.ts +36 -0
- package/dist/components/actions/Progress.d.ts.map +1 -0
- package/dist/components/actions/Progress.js +14 -0
- package/dist/components/actions/Progress.js.map +1 -0
- package/dist/components/actions/Segmented.d.ts +64 -0
- package/dist/components/actions/Segmented.d.ts.map +1 -0
- package/dist/components/actions/Segmented.js +14 -0
- package/dist/components/actions/Segmented.js.map +1 -0
- package/dist/components/actions/Spinner.d.ts +46 -0
- package/dist/components/actions/Spinner.d.ts.map +1 -0
- package/dist/components/actions/Spinner.js +17 -0
- package/dist/components/actions/Spinner.js.map +1 -0
- package/dist/components/actions/SplitButton.d.ts +92 -0
- package/dist/components/actions/SplitButton.d.ts.map +1 -0
- package/dist/components/actions/SplitButton.js +21 -0
- package/dist/components/actions/SplitButton.js.map +1 -0
- package/dist/components/actions/StatusBadge.d.ts +26 -0
- package/dist/components/actions/StatusBadge.d.ts.map +1 -0
- package/dist/components/actions/StatusBadge.js +14 -0
- package/dist/components/actions/StatusBadge.js.map +1 -0
- package/dist/components/actions/Toaster.d.ts +83 -0
- package/dist/components/actions/Toaster.d.ts.map +1 -0
- package/dist/components/actions/Toaster.js +38 -0
- package/dist/components/actions/Toaster.js.map +1 -0
- package/dist/components/actions/Toggle.d.ts +75 -0
- package/dist/components/actions/Toggle.d.ts.map +1 -0
- package/dist/components/actions/Toggle.js +39 -0
- package/dist/components/actions/Toggle.js.map +1 -0
- package/dist/components/actions/ToggleGroup.d.ts +63 -0
- package/dist/components/actions/ToggleGroup.d.ts.map +1 -0
- package/dist/components/actions/ToggleGroup.js +30 -0
- package/dist/components/actions/ToggleGroup.js.map +1 -0
- package/dist/components/actions/Toolbar.d.ts +52 -0
- package/dist/components/actions/Toolbar.d.ts.map +1 -0
- package/dist/components/actions/Toolbar.js +98 -0
- package/dist/components/actions/Toolbar.js.map +1 -0
- package/dist/components/actions/Truncate.d.ts +31 -0
- package/dist/components/actions/Truncate.d.ts.map +1 -0
- package/dist/components/actions/Truncate.js +32 -0
- package/dist/components/actions/Truncate.js.map +1 -0
- package/dist/components/app-shell/AppShell.d.ts +106 -0
- package/dist/components/app-shell/AppShell.d.ts.map +1 -0
- package/dist/components/app-shell/AppShell.js +29 -0
- package/dist/components/app-shell/AppShell.js.map +1 -0
- package/dist/components/app-shell/MobileTabBar.d.ts +130 -0
- package/dist/components/app-shell/MobileTabBar.d.ts.map +1 -0
- package/dist/components/app-shell/MobileTabBar.js +50 -0
- package/dist/components/app-shell/MobileTabBar.js.map +1 -0
- package/dist/components/app-shell/NavItem.d.ts +72 -0
- package/dist/components/app-shell/NavItem.d.ts.map +1 -0
- package/dist/components/app-shell/NavItem.js +22 -0
- package/dist/components/app-shell/NavItem.js.map +1 -0
- package/dist/components/app-shell/SideNav.d.ts +65 -0
- package/dist/components/app-shell/SideNav.d.ts.map +1 -0
- package/dist/components/app-shell/SideNav.js +31 -0
- package/dist/components/app-shell/SideNav.js.map +1 -0
- package/dist/components/app-shell/SplitPanel.d.ts +121 -0
- package/dist/components/app-shell/SplitPanel.d.ts.map +1 -0
- package/dist/components/app-shell/SplitPanel.js +88 -0
- package/dist/components/app-shell/SplitPanel.js.map +1 -0
- package/dist/components/app-shell/TopBar.d.ts +43 -0
- package/dist/components/app-shell/TopBar.d.ts.map +1 -0
- package/dist/components/app-shell/TopBar.js +24 -0
- package/dist/components/app-shell/TopBar.js.map +1 -0
- package/dist/components/content/AspectRatio.d.ts +25 -0
- package/dist/components/content/AspectRatio.d.ts.map +1 -0
- package/dist/components/content/AspectRatio.js +7 -0
- package/dist/components/content/AspectRatio.js.map +1 -0
- package/dist/components/content/Avatar.d.ts +22 -0
- package/dist/components/content/Avatar.d.ts.map +1 -0
- package/dist/components/content/Avatar.js +23 -0
- package/dist/components/content/Avatar.js.map +1 -0
- package/dist/components/content/AvatarGroup.d.ts +42 -0
- package/dist/components/content/AvatarGroup.d.ts.map +1 -0
- package/dist/components/content/AvatarGroup.js +11 -0
- package/dist/components/content/AvatarGroup.js.map +1 -0
- package/dist/components/content/Badge.d.ts +41 -0
- package/dist/components/content/Badge.d.ts.map +1 -0
- package/dist/components/content/Badge.js +13 -0
- package/dist/components/content/Badge.js.map +1 -0
- package/dist/components/content/Card.d.ts +59 -0
- package/dist/components/content/Card.d.ts.map +1 -0
- package/dist/components/content/Card.js +20 -0
- package/dist/components/content/Card.js.map +1 -0
- package/dist/components/content/Carousel.d.ts +79 -0
- package/dist/components/content/Carousel.d.ts.map +1 -0
- package/dist/components/content/Carousel.js +172 -0
- package/dist/components/content/Carousel.js.map +1 -0
- package/dist/components/content/CodeView.d.ts +76 -0
- package/dist/components/content/CodeView.d.ts.map +1 -0
- package/dist/components/content/CodeView.js +12 -0
- package/dist/components/content/CodeView.js.map +1 -0
- package/dist/components/content/DescriptionList.d.ts +31 -0
- package/dist/components/content/DescriptionList.d.ts.map +1 -0
- package/dist/components/content/DescriptionList.js +10 -0
- package/dist/components/content/DescriptionList.js.map +1 -0
- package/dist/components/content/EditableList.d.ts +162 -0
- package/dist/components/content/EditableList.d.ts.map +1 -0
- package/dist/components/content/EditableList.js +241 -0
- package/dist/components/content/EditableList.js.map +1 -0
- package/dist/components/content/EmptyState.d.ts +31 -0
- package/dist/components/content/EmptyState.d.ts.map +1 -0
- package/dist/components/content/EmptyState.js +9 -0
- package/dist/components/content/EmptyState.js.map +1 -0
- package/dist/components/content/ErrorState.d.ts +52 -0
- package/dist/components/content/ErrorState.d.ts.map +1 -0
- package/dist/components/content/ErrorState.js +16 -0
- package/dist/components/content/ErrorState.js.map +1 -0
- package/dist/components/content/Grid.d.ts +57 -0
- package/dist/components/content/Grid.d.ts.map +1 -0
- package/dist/components/content/Grid.js +85 -0
- package/dist/components/content/Grid.js.map +1 -0
- package/dist/components/content/Heading.d.ts +43 -0
- package/dist/components/content/Heading.d.ts.map +1 -0
- package/dist/components/content/Heading.js +21 -0
- package/dist/components/content/Heading.js.map +1 -0
- package/dist/components/content/Image.d.ts +94 -0
- package/dist/components/content/Image.d.ts.map +1 -0
- package/dist/components/content/Image.js +41 -0
- package/dist/components/content/Image.js.map +1 -0
- package/dist/components/content/Kbd.d.ts +31 -0
- package/dist/components/content/Kbd.d.ts.map +1 -0
- package/dist/components/content/Kbd.js +13 -0
- package/dist/components/content/Kbd.js.map +1 -0
- package/dist/components/content/Keyboard.d.ts +32 -0
- package/dist/components/content/Keyboard.d.ts.map +1 -0
- package/dist/components/content/Keyboard.js +381 -0
- package/dist/components/content/Keyboard.js.map +1 -0
- package/dist/components/content/Link.d.ts +46 -0
- package/dist/components/content/Link.d.ts.map +1 -0
- package/dist/components/content/Link.js +38 -0
- package/dist/components/content/Link.js.map +1 -0
- package/dist/components/content/MediaCard.d.ts +56 -0
- package/dist/components/content/MediaCard.d.ts.map +1 -0
- package/dist/components/content/MediaCard.js +15 -0
- package/dist/components/content/MediaCard.js.map +1 -0
- package/dist/components/content/NotificationCenter.d.ts +68 -0
- package/dist/components/content/NotificationCenter.d.ts.map +1 -0
- package/dist/components/content/NotificationCenter.js +14 -0
- package/dist/components/content/NotificationCenter.js.map +1 -0
- package/dist/components/content/NotificationList.d.ts +111 -0
- package/dist/components/content/NotificationList.d.ts.map +1 -0
- package/dist/components/content/NotificationList.js +48 -0
- package/dist/components/content/NotificationList.js.map +1 -0
- package/dist/components/content/ScrollArea.d.ts +30 -0
- package/dist/components/content/ScrollArea.d.ts.map +1 -0
- package/dist/components/content/ScrollArea.js +7 -0
- package/dist/components/content/ScrollArea.js.map +1 -0
- package/dist/components/content/Separator.d.ts +19 -0
- package/dist/components/content/Separator.d.ts.map +1 -0
- package/dist/components/content/Separator.js +14 -0
- package/dist/components/content/Separator.js.map +1 -0
- package/dist/components/content/Skeleton.d.ts +24 -0
- package/dist/components/content/Skeleton.d.ts.map +1 -0
- package/dist/components/content/Skeleton.js +8 -0
- package/dist/components/content/Skeleton.js.map +1 -0
- package/dist/components/content/SortableList.d.ts +98 -0
- package/dist/components/content/SortableList.d.ts.map +1 -0
- package/dist/components/content/SortableList.js +46 -0
- package/dist/components/content/SortableList.js.map +1 -0
- package/dist/components/content/Stat.d.ts +46 -0
- package/dist/components/content/Stat.d.ts.map +1 -0
- package/dist/components/content/Stat.js +12 -0
- package/dist/components/content/Stat.js.map +1 -0
- package/dist/components/content/Table.d.ts +110 -0
- package/dist/components/content/Table.d.ts.map +1 -0
- package/dist/components/content/Table.js +66 -0
- package/dist/components/content/Table.js.map +1 -0
- package/dist/components/content/TagGroup.d.ts +120 -0
- package/dist/components/content/TagGroup.d.ts.map +1 -0
- package/dist/components/content/TagGroup.js +20 -0
- package/dist/components/content/TagGroup.js.map +1 -0
- package/dist/components/content/Text.d.ts +55 -0
- package/dist/components/content/Text.d.ts.map +1 -0
- package/dist/components/content/Text.js +27 -0
- package/dist/components/content/Text.js.map +1 -0
- package/dist/components/content/Timeline.d.ts +50 -0
- package/dist/components/content/Timeline.d.ts.map +1 -0
- package/dist/components/content/Timeline.js +15 -0
- package/dist/components/content/Timeline.js.map +1 -0
- package/dist/components/content/VirtualGrid.d.ts +171 -0
- package/dist/components/content/VirtualGrid.d.ts.map +1 -0
- package/dist/components/content/VirtualGrid.js +267 -0
- package/dist/components/content/VirtualGrid.js.map +1 -0
- package/dist/components/content/VisuallyHidden.d.ts +24 -0
- package/dist/components/content/VisuallyHidden.d.ts.map +1 -0
- package/dist/components/content/VisuallyHidden.js +3 -0
- package/dist/components/content/VisuallyHidden.js.map +1 -0
- package/dist/components/content/keyboardEditing.d.ts +15 -0
- package/dist/components/content/keyboardEditing.d.ts.map +1 -0
- package/dist/components/content/keyboardEditing.js +28 -0
- package/dist/components/content/keyboardEditing.js.map +1 -0
- package/dist/components/content/useDragToSelect.d.ts +41 -0
- package/dist/components/content/useDragToSelect.d.ts.map +1 -0
- package/dist/components/content/useDragToSelect.js +190 -0
- package/dist/components/content/useDragToSelect.js.map +1 -0
- package/dist/components/date-time/Calendar.d.ts +67 -0
- package/dist/components/date-time/Calendar.d.ts.map +1 -0
- package/dist/components/date-time/Calendar.js +28 -0
- package/dist/components/date-time/Calendar.js.map +1 -0
- package/dist/components/date-time/DatePicker.d.ts +57 -0
- package/dist/components/date-time/DatePicker.d.ts.map +1 -0
- package/dist/components/date-time/DatePicker.js +37 -0
- package/dist/components/date-time/DatePicker.js.map +1 -0
- package/dist/components/date-time/DateRangePicker.d.ts +91 -0
- package/dist/components/date-time/DateRangePicker.d.ts.map +1 -0
- package/dist/components/date-time/DateRangePicker.js +72 -0
- package/dist/components/date-time/DateRangePicker.js.map +1 -0
- package/dist/components/date-time/DateTimePicker.d.ts +55 -0
- package/dist/components/date-time/DateTimePicker.d.ts.map +1 -0
- package/dist/components/date-time/DateTimePicker.js +9 -0
- package/dist/components/date-time/DateTimePicker.js.map +1 -0
- package/dist/components/date-time/RangeCalendar.d.ts +50 -0
- package/dist/components/date-time/RangeCalendar.d.ts.map +1 -0
- package/dist/components/date-time/RangeCalendar.js +17 -0
- package/dist/components/date-time/RangeCalendar.js.map +1 -0
- package/dist/components/date-time/TimePicker.d.ts +47 -0
- package/dist/components/date-time/TimePicker.d.ts.map +1 -0
- package/dist/components/date-time/TimePicker.js +148 -0
- package/dist/components/date-time/TimePicker.js.map +1 -0
- package/dist/components/inputs/Checkbox.d.ts +140 -0
- package/dist/components/inputs/Checkbox.d.ts.map +1 -0
- package/dist/components/inputs/Checkbox.js +29 -0
- package/dist/components/inputs/Checkbox.js.map +1 -0
- package/dist/components/inputs/CheckboxCard.d.ts +17 -0
- package/dist/components/inputs/CheckboxCard.d.ts.map +1 -0
- package/dist/components/inputs/CheckboxCard.js +25 -0
- package/dist/components/inputs/CheckboxCard.js.map +1 -0
- package/dist/components/inputs/CheckboxGroup.d.ts +68 -0
- package/dist/components/inputs/CheckboxGroup.d.ts.map +1 -0
- package/dist/components/inputs/CheckboxGroup.js +14 -0
- package/dist/components/inputs/CheckboxGroup.js.map +1 -0
- package/dist/components/inputs/ChoiceCardBody.d.ts +16 -0
- package/dist/components/inputs/ChoiceCardBody.d.ts.map +1 -0
- package/dist/components/inputs/ChoiceCardBody.js +10 -0
- package/dist/components/inputs/ChoiceCardBody.js.map +1 -0
- package/dist/components/inputs/ColorPicker.d.ts +71 -0
- package/dist/components/inputs/ColorPicker.d.ts.map +1 -0
- package/dist/components/inputs/ColorPicker.js +30 -0
- package/dist/components/inputs/ColorPicker.js.map +1 -0
- package/dist/components/inputs/Combobox.d.ts +41 -0
- package/dist/components/inputs/Combobox.d.ts.map +1 -0
- package/dist/components/inputs/Combobox.js +16 -0
- package/dist/components/inputs/Combobox.js.map +1 -0
- package/dist/components/inputs/FileDropzone.d.ts +51 -0
- package/dist/components/inputs/FileDropzone.d.ts.map +1 -0
- package/dist/components/inputs/FileDropzone.js +75 -0
- package/dist/components/inputs/FileDropzone.js.map +1 -0
- package/dist/components/inputs/Form.d.ts +50 -0
- package/dist/components/inputs/Form.d.ts.map +1 -0
- package/dist/components/inputs/Form.js +14 -0
- package/dist/components/inputs/Form.js.map +1 -0
- package/dist/components/inputs/FormField.d.ts +89 -0
- package/dist/components/inputs/FormField.d.ts.map +1 -0
- package/dist/components/inputs/FormField.js +24 -0
- package/dist/components/inputs/FormField.js.map +1 -0
- package/dist/components/inputs/FormLayout.d.ts +47 -0
- package/dist/components/inputs/FormLayout.d.ts.map +1 -0
- package/dist/components/inputs/FormLayout.js +12 -0
- package/dist/components/inputs/FormLayout.js.map +1 -0
- package/dist/components/inputs/InlineEdit.d.ts +50 -0
- package/dist/components/inputs/InlineEdit.d.ts.map +1 -0
- package/dist/components/inputs/InlineEdit.js +70 -0
- package/dist/components/inputs/InlineEdit.js.map +1 -0
- package/dist/components/inputs/MaskedInput.d.ts +66 -0
- package/dist/components/inputs/MaskedInput.d.ts.map +1 -0
- package/dist/components/inputs/MaskedInput.js +73 -0
- package/dist/components/inputs/MaskedInput.js.map +1 -0
- package/dist/components/inputs/NumberInput.d.ts +53 -0
- package/dist/components/inputs/NumberInput.d.ts.map +1 -0
- package/dist/components/inputs/NumberInput.js +17 -0
- package/dist/components/inputs/NumberInput.js.map +1 -0
- package/dist/components/inputs/PasswordInput.d.ts +49 -0
- package/dist/components/inputs/PasswordInput.d.ts.map +1 -0
- package/dist/components/inputs/PasswordInput.js +49 -0
- package/dist/components/inputs/PasswordInput.js.map +1 -0
- package/dist/components/inputs/PhoneInput.d.ts +35 -0
- package/dist/components/inputs/PhoneInput.d.ts.map +1 -0
- package/dist/components/inputs/PhoneInput.js +9 -0
- package/dist/components/inputs/PhoneInput.js.map +1 -0
- package/dist/components/inputs/PinInput.d.ts +50 -0
- package/dist/components/inputs/PinInput.d.ts.map +1 -0
- package/dist/components/inputs/PinInput.js +67 -0
- package/dist/components/inputs/PinInput.js.map +1 -0
- package/dist/components/inputs/RadioGroup.d.ts +86 -0
- package/dist/components/inputs/RadioGroup.d.ts.map +1 -0
- package/dist/components/inputs/RadioGroup.js +51 -0
- package/dist/components/inputs/RadioGroup.js.map +1 -0
- package/dist/components/inputs/Rating.d.ts +69 -0
- package/dist/components/inputs/Rating.d.ts.map +1 -0
- package/dist/components/inputs/Rating.js +51 -0
- package/dist/components/inputs/Rating.js.map +1 -0
- package/dist/components/inputs/SearchControl.d.ts +85 -0
- package/dist/components/inputs/SearchControl.d.ts.map +1 -0
- package/dist/components/inputs/SearchControl.js +62 -0
- package/dist/components/inputs/SearchControl.js.map +1 -0
- package/dist/components/inputs/Select.d.ts +205 -0
- package/dist/components/inputs/Select.d.ts.map +1 -0
- package/dist/components/inputs/Select.js +136 -0
- package/dist/components/inputs/Select.js.map +1 -0
- package/dist/components/inputs/Slider.d.ts +59 -0
- package/dist/components/inputs/Slider.d.ts.map +1 -0
- package/dist/components/inputs/Slider.js +153 -0
- package/dist/components/inputs/Slider.js.map +1 -0
- package/dist/components/inputs/SwatchGroup.d.ts +101 -0
- package/dist/components/inputs/SwatchGroup.d.ts.map +1 -0
- package/dist/components/inputs/SwatchGroup.js +57 -0
- package/dist/components/inputs/SwatchGroup.js.map +1 -0
- package/dist/components/inputs/TagInput.d.ts +45 -0
- package/dist/components/inputs/TagInput.d.ts.map +1 -0
- package/dist/components/inputs/TagInput.js +56 -0
- package/dist/components/inputs/TagInput.js.map +1 -0
- package/dist/components/inputs/TextControl.d.ts +101 -0
- package/dist/components/inputs/TextControl.d.ts.map +1 -0
- package/dist/components/inputs/TextControl.js +31 -0
- package/dist/components/inputs/TextControl.js.map +1 -0
- package/dist/components/inputs/Transfer.d.ts +84 -0
- package/dist/components/inputs/Transfer.d.ts.map +1 -0
- package/dist/components/inputs/Transfer.js +112 -0
- package/dist/components/inputs/Transfer.js.map +1 -0
- package/dist/components/inputs/TreeSelect.d.ts +73 -0
- package/dist/components/inputs/TreeSelect.d.ts.map +1 -0
- package/dist/components/inputs/TreeSelect.js +60 -0
- package/dist/components/inputs/TreeSelect.js.map +1 -0
- package/dist/components/inputs/UploadQueue.d.ts +84 -0
- package/dist/components/inputs/UploadQueue.d.ts.map +1 -0
- package/dist/components/inputs/UploadQueue.js +30 -0
- package/dist/components/inputs/UploadQueue.js.map +1 -0
- package/dist/components/navigation/Accordion.d.ts +44 -0
- package/dist/components/navigation/Accordion.d.ts.map +1 -0
- package/dist/components/navigation/Accordion.js +12 -0
- package/dist/components/navigation/Accordion.js.map +1 -0
- package/dist/components/navigation/Breadcrumbs.d.ts +35 -0
- package/dist/components/navigation/Breadcrumbs.d.ts.map +1 -0
- package/dist/components/navigation/Breadcrumbs.js +17 -0
- package/dist/components/navigation/Breadcrumbs.js.map +1 -0
- package/dist/components/navigation/ContextualSaveBar.d.ts +90 -0
- package/dist/components/navigation/ContextualSaveBar.d.ts.map +1 -0
- package/dist/components/navigation/ContextualSaveBar.js +20 -0
- package/dist/components/navigation/ContextualSaveBar.js.map +1 -0
- package/dist/components/navigation/PageHeader.d.ts +17 -0
- package/dist/components/navigation/PageHeader.d.ts.map +1 -0
- package/dist/components/navigation/PageHeader.js +8 -0
- package/dist/components/navigation/PageHeader.js.map +1 -0
- package/dist/components/navigation/Pagination.d.ts +44 -0
- package/dist/components/navigation/Pagination.d.ts.map +1 -0
- package/dist/components/navigation/Pagination.js +57 -0
- package/dist/components/navigation/Pagination.js.map +1 -0
- package/dist/components/navigation/SectionHeader.d.ts +32 -0
- package/dist/components/navigation/SectionHeader.d.ts.map +1 -0
- package/dist/components/navigation/SectionHeader.js +13 -0
- package/dist/components/navigation/SectionHeader.js.map +1 -0
- package/dist/components/navigation/SelectionBar.d.ts +65 -0
- package/dist/components/navigation/SelectionBar.d.ts.map +1 -0
- package/dist/components/navigation/SelectionBar.js +24 -0
- package/dist/components/navigation/SelectionBar.js.map +1 -0
- package/dist/components/navigation/Stepper.d.ts +45 -0
- package/dist/components/navigation/Stepper.d.ts.map +1 -0
- package/dist/components/navigation/Stepper.js +16 -0
- package/dist/components/navigation/Stepper.js.map +1 -0
- package/dist/components/navigation/Tabs.d.ts +45 -0
- package/dist/components/navigation/Tabs.d.ts.map +1 -0
- package/dist/components/navigation/Tabs.js +51 -0
- package/dist/components/navigation/Tabs.js.map +1 -0
- package/dist/components/navigation/TreeView.d.ts +101 -0
- package/dist/components/navigation/TreeView.d.ts.map +1 -0
- package/dist/components/navigation/TreeView.js +27 -0
- package/dist/components/navigation/TreeView.js.map +1 -0
- package/dist/components/overlays/CommandPalette.d.ts +115 -0
- package/dist/components/overlays/CommandPalette.d.ts.map +1 -0
- package/dist/components/overlays/CommandPalette.js +43 -0
- package/dist/components/overlays/CommandPalette.js.map +1 -0
- package/dist/components/overlays/ConfirmDialog.d.ts +67 -0
- package/dist/components/overlays/ConfirmDialog.d.ts.map +1 -0
- package/dist/components/overlays/ConfirmDialog.js +47 -0
- package/dist/components/overlays/ConfirmDialog.js.map +1 -0
- package/dist/components/overlays/ContextMenu.d.ts +122 -0
- package/dist/components/overlays/ContextMenu.d.ts.map +1 -0
- package/dist/components/overlays/ContextMenu.js +39 -0
- package/dist/components/overlays/ContextMenu.js.map +1 -0
- package/dist/components/overlays/Dialog.d.ts +113 -0
- package/dist/components/overlays/Dialog.d.ts.map +1 -0
- package/dist/components/overlays/Dialog.js +43 -0
- package/dist/components/overlays/Dialog.js.map +1 -0
- package/dist/components/overlays/Drawer.d.ts +53 -0
- package/dist/components/overlays/Drawer.d.ts.map +1 -0
- package/dist/components/overlays/Drawer.js +32 -0
- package/dist/components/overlays/Drawer.js.map +1 -0
- package/dist/components/overlays/HelpTooltip.d.ts +41 -0
- package/dist/components/overlays/HelpTooltip.d.ts.map +1 -0
- package/dist/components/overlays/HelpTooltip.js +10 -0
- package/dist/components/overlays/HelpTooltip.js.map +1 -0
- package/dist/components/overlays/HoverCard.d.ts +62 -0
- package/dist/components/overlays/HoverCard.d.ts.map +1 -0
- package/dist/components/overlays/HoverCard.js +175 -0
- package/dist/components/overlays/HoverCard.js.map +1 -0
- package/dist/components/overlays/Menu.d.ts +113 -0
- package/dist/components/overlays/Menu.d.ts.map +1 -0
- package/dist/components/overlays/Menu.js +26 -0
- package/dist/components/overlays/Menu.js.map +1 -0
- package/dist/components/overlays/ModalHeader.d.ts +77 -0
- package/dist/components/overlays/ModalHeader.d.ts.map +1 -0
- package/dist/components/overlays/ModalHeader.js +11 -0
- package/dist/components/overlays/ModalHeader.js.map +1 -0
- package/dist/components/overlays/ModalOverlay.d.ts +45 -0
- package/dist/components/overlays/ModalOverlay.d.ts.map +1 -0
- package/dist/components/overlays/ModalOverlay.js +29 -0
- package/dist/components/overlays/ModalOverlay.js.map +1 -0
- package/dist/components/overlays/Popover.d.ts +56 -0
- package/dist/components/overlays/Popover.d.ts.map +1 -0
- package/dist/components/overlays/Popover.js +16 -0
- package/dist/components/overlays/Popover.js.map +1 -0
- package/dist/components/overlays/ShortcutsHelp.d.ts +70 -0
- package/dist/components/overlays/ShortcutsHelp.d.ts.map +1 -0
- package/dist/components/overlays/ShortcutsHelp.js +20 -0
- package/dist/components/overlays/ShortcutsHelp.js.map +1 -0
- package/dist/components/overlays/Tooltip.d.ts +35 -0
- package/dist/components/overlays/Tooltip.d.ts.map +1 -0
- package/dist/components/overlays/Tooltip.js +18 -0
- package/dist/components/overlays/Tooltip.js.map +1 -0
- package/dist/components/table/DataTable.d.ts +60 -0
- package/dist/components/table/DataTable.d.ts.map +1 -0
- package/dist/components/table/DataTable.js +20 -0
- package/dist/components/table/DataTable.js.map +1 -0
- package/dist/components/table/FilterBar.d.ts +35 -0
- package/dist/components/table/FilterBar.d.ts.map +1 -0
- package/dist/components/table/FilterBar.js +17 -0
- package/dist/components/table/FilterBar.js.map +1 -0
- package/dist/components/table/FilterBarAdd.d.ts +57 -0
- package/dist/components/table/FilterBarAdd.d.ts.map +1 -0
- package/dist/components/table/FilterBarAdd.js +83 -0
- package/dist/components/table/FilterBarAdd.js.map +1 -0
- package/dist/components/table/SavedViews.d.ts +83 -0
- package/dist/components/table/SavedViews.d.ts.map +1 -0
- package/dist/components/table/SavedViews.js +12 -0
- package/dist/components/table/SavedViews.js.map +1 -0
- package/dist/components/table/TablePreferences.d.ts +45 -0
- package/dist/components/table/TablePreferences.d.ts.map +1 -0
- package/dist/components/table/TablePreferences.js +41 -0
- package/dist/components/table/TablePreferences.js.map +1 -0
- package/dist/components/table/TableToolbar.d.ts +38 -0
- package/dist/components/table/TableToolbar.d.ts.map +1 -0
- package/dist/components/table/TableToolbar.js +11 -0
- package/dist/components/table/TableToolbar.js.map +1 -0
- package/dist/editor/RichTextEditor.d.ts +274 -0
- package/dist/editor/RichTextEditor.d.ts.map +1 -0
- package/dist/editor/RichTextEditor.js +671 -0
- package/dist/editor/RichTextEditor.js.map +1 -0
- package/dist/editor/RichTextView.d.ts +70 -0
- package/dist/editor/RichTextView.d.ts.map +1 -0
- package/dist/editor/RichTextView.js +24 -0
- package/dist/editor/RichTextView.js.map +1 -0
- package/dist/editor/core/atomText.d.ts +21 -0
- package/dist/editor/core/atomText.d.ts.map +1 -0
- package/dist/editor/core/atomText.js +77 -0
- package/dist/editor/core/atomText.js.map +1 -0
- package/dist/editor/core/blockCommands.d.ts +94 -0
- package/dist/editor/core/blockCommands.d.ts.map +1 -0
- package/dist/editor/core/blockCommands.js +188 -0
- package/dist/editor/core/blockCommands.js.map +1 -0
- package/dist/editor/core/blockTypes.d.ts +89 -0
- package/dist/editor/core/blockTypes.d.ts.map +1 -0
- package/dist/editor/core/blockTypes.js +121 -0
- package/dist/editor/core/blockTypes.js.map +1 -0
- package/dist/editor/core/containers.d.ts +43 -0
- package/dist/editor/core/containers.d.ts.map +1 -0
- package/dist/editor/core/containers.js +52 -0
- package/dist/editor/core/containers.js.map +1 -0
- package/dist/editor/core/customMarkdown.d.ts +8 -0
- package/dist/editor/core/customMarkdown.d.ts.map +1 -0
- package/dist/editor/core/customMarkdown.js +34 -0
- package/dist/editor/core/customMarkdown.js.map +1 -0
- package/dist/editor/core/customTool.d.ts +407 -0
- package/dist/editor/core/customTool.d.ts.map +1 -0
- package/dist/editor/core/customTool.js +31 -0
- package/dist/editor/core/customTool.js.map +1 -0
- package/dist/editor/core/customToolEngine.d.ts +31 -0
- package/dist/editor/core/customToolEngine.d.ts.map +1 -0
- package/dist/editor/core/customToolEngine.js +324 -0
- package/dist/editor/core/customToolEngine.js.map +1 -0
- package/dist/editor/core/document.d.ts +17 -0
- package/dist/editor/core/document.d.ts.map +1 -0
- package/dist/editor/core/document.js +11 -0
- package/dist/editor/core/document.js.map +1 -0
- package/dist/editor/core/emptiness.d.ts +18 -0
- package/dist/editor/core/emptiness.d.ts.map +1 -0
- package/dist/editor/core/emptiness.js +14 -0
- package/dist/editor/core/emptiness.js.map +1 -0
- package/dist/editor/core/extensions.d.ts +78 -0
- package/dist/editor/core/extensions.d.ts.map +1 -0
- package/dist/editor/core/extensions.js +134 -0
- package/dist/editor/core/extensions.js.map +1 -0
- package/dist/editor/core/fieldNotice.d.ts +48 -0
- package/dist/editor/core/fieldNotice.d.ts.map +1 -0
- package/dist/editor/core/fieldNotice.js +18 -0
- package/dist/editor/core/fieldNotice.js.map +1 -0
- package/dist/editor/core/handle.d.ts +110 -0
- package/dist/editor/core/handle.d.ts.map +1 -0
- package/dist/editor/core/handle.js +149 -0
- package/dist/editor/core/handle.js.map +1 -0
- package/dist/editor/core/insertItems.d.ts +147 -0
- package/dist/editor/core/insertItems.d.ts.map +1 -0
- package/dist/editor/core/insertItems.js +215 -0
- package/dist/editor/core/insertItems.js.map +1 -0
- package/dist/editor/core/jsonDocument.d.ts +42 -0
- package/dist/editor/core/jsonDocument.d.ts.map +1 -0
- package/dist/editor/core/jsonDocument.js +44 -0
- package/dist/editor/core/jsonDocument.js.map +1 -0
- package/dist/editor/core/markdown.d.ts +47 -0
- package/dist/editor/core/markdown.d.ts.map +1 -0
- package/dist/editor/core/markdown.js +169 -0
- package/dist/editor/core/markdown.js.map +1 -0
- package/dist/editor/core/maxLength.d.ts +43 -0
- package/dist/editor/core/maxLength.d.ts.map +1 -0
- package/dist/editor/core/maxLength.js +45 -0
- package/dist/editor/core/maxLength.js.map +1 -0
- package/dist/editor/core/pasteTrim.d.ts +8 -0
- package/dist/editor/core/pasteTrim.d.ts.map +1 -0
- package/dist/editor/core/pasteTrim.js +61 -0
- package/dist/editor/core/pasteTrim.js.map +1 -0
- package/dist/editor/core/schema.d.ts +479 -0
- package/dist/editor/core/schema.d.ts.map +1 -0
- package/dist/editor/core/schema.js +371 -0
- package/dist/editor/core/schema.js.map +1 -0
- package/dist/editor/core/schemaConform.d.ts +30 -0
- package/dist/editor/core/schemaConform.d.ts.map +1 -0
- package/dist/editor/core/schemaConform.js +72 -0
- package/dist/editor/core/schemaConform.js.map +1 -0
- package/dist/editor/core/shortcuts.d.ts +110 -0
- package/dist/editor/core/shortcuts.d.ts.map +1 -0
- package/dist/editor/core/shortcuts.js +299 -0
- package/dist/editor/core/shortcuts.js.map +1 -0
- package/dist/editor/core/skeleton.d.ts +11 -0
- package/dist/editor/core/skeleton.d.ts.map +1 -0
- package/dist/editor/core/skeleton.js +48 -0
- package/dist/editor/core/skeleton.js.map +1 -0
- package/dist/editor/core/slashCommand.d.ts +46 -0
- package/dist/editor/core/slashCommand.d.ts.map +1 -0
- package/dist/editor/core/slashCommand.js +67 -0
- package/dist/editor/core/slashCommand.js.map +1 -0
- package/dist/editor/core/sourceFormat.d.ts +30 -0
- package/dist/editor/core/sourceFormat.d.ts.map +1 -0
- package/dist/editor/core/sourceFormat.js +136 -0
- package/dist/editor/core/sourceFormat.js.map +1 -0
- package/dist/editor/core/toolButtons.d.ts +58 -0
- package/dist/editor/core/toolButtons.d.ts.map +1 -0
- package/dist/editor/core/toolButtons.js +64 -0
- package/dist/editor/core/toolButtons.js.map +1 -0
- package/dist/editor/core/toolDescriptor.d.ts +304 -0
- package/dist/editor/core/toolDescriptor.d.ts.map +1 -0
- package/dist/editor/core/toolDescriptor.js +29 -0
- package/dist/editor/core/toolDescriptor.js.map +1 -0
- package/dist/editor/core/toolEntryShortcuts.d.ts +20 -0
- package/dist/editor/core/toolEntryShortcuts.d.ts.map +1 -0
- package/dist/editor/core/toolEntryShortcuts.js +46 -0
- package/dist/editor/core/toolEntryShortcuts.js.map +1 -0
- package/dist/editor/core/toolLoader.d.ts +14 -0
- package/dist/editor/core/toolLoader.d.ts.map +1 -0
- package/dist/editor/core/toolLoader.js +20 -0
- package/dist/editor/core/toolLoader.js.map +1 -0
- package/dist/editor/core/tools.d.ts +90 -0
- package/dist/editor/core/tools.d.ts.map +1 -0
- package/dist/editor/core/tools.js +56 -0
- package/dist/editor/core/tools.js.map +1 -0
- package/dist/editor/core/viewIsland.d.ts +17 -0
- package/dist/editor/core/viewIsland.d.ts.map +1 -0
- package/dist/editor/core/viewIsland.js +4 -0
- package/dist/editor/core/viewIsland.js.map +1 -0
- package/dist/editor/features/builtins.d.ts +25 -0
- package/dist/editor/features/builtins.d.ts.map +1 -0
- package/dist/editor/features/builtins.js +88 -0
- package/dist/editor/features/builtins.js.map +1 -0
- package/dist/editor/features/code/CodeBlockView.d.ts +38 -0
- package/dist/editor/features/code/CodeBlockView.d.ts.map +1 -0
- package/dist/editor/features/code/CodeBlockView.js +98 -0
- package/dist/editor/features/code/CodeBlockView.js.map +1 -0
- package/dist/editor/features/code/CodeCopyButton.d.ts +20 -0
- package/dist/editor/features/code/CodeCopyButton.d.ts.map +1 -0
- package/dist/editor/features/code/CodeCopyButton.js +29 -0
- package/dist/editor/features/code/CodeCopyButton.js.map +1 -0
- package/dist/editor/features/code/CodeCopyIsland.d.ts +37 -0
- package/dist/editor/features/code/CodeCopyIsland.d.ts.map +1 -0
- package/dist/editor/features/code/CodeCopyIsland.js +21 -0
- package/dist/editor/features/code/CodeCopyIsland.js.map +1 -0
- package/dist/editor/features/code/codeBlock.d.ts +25 -0
- package/dist/editor/features/code/codeBlock.d.ts.map +1 -0
- package/dist/editor/features/code/codeBlock.js +116 -0
- package/dist/editor/features/code/codeBlock.js.map +1 -0
- package/dist/editor/features/code/codeBlockTool.d.ts +24 -0
- package/dist/editor/features/code/codeBlockTool.d.ts.map +1 -0
- package/dist/editor/features/code/codeBlockTool.js +66 -0
- package/dist/editor/features/code/codeBlockTool.js.map +1 -0
- package/dist/editor/features/code/codeHeader.d.ts +41 -0
- package/dist/editor/features/code/codeHeader.d.ts.map +1 -0
- package/dist/editor/features/code/codeHeader.js +25 -0
- package/dist/editor/features/code/codeHeader.js.map +1 -0
- package/dist/editor/features/code/codeLanguages.d.ts +76 -0
- package/dist/editor/features/code/codeLanguages.d.ts.map +1 -0
- package/dist/editor/features/code/codeLanguages.js +24 -0
- package/dist/editor/features/code/codeLanguages.js.map +1 -0
- package/dist/editor/features/code/highlight.d.ts +20 -0
- package/dist/editor/features/code/highlight.d.ts.map +1 -0
- package/dist/editor/features/code/highlight.js +51 -0
- package/dist/editor/features/code/highlight.js.map +1 -0
- package/dist/editor/features/code/highlightNodes.d.ts +31 -0
- package/dist/editor/features/code/highlightNodes.d.ts.map +1 -0
- package/dist/editor/features/code/highlightNodes.js +25 -0
- package/dist/editor/features/code/highlightNodes.js.map +1 -0
- package/dist/editor/features/code/lowlight.d.ts +20 -0
- package/dist/editor/features/code/lowlight.d.ts.map +1 -0
- package/dist/editor/features/code/lowlight.js +26 -0
- package/dist/editor/features/code/lowlight.js.map +1 -0
- package/dist/editor/features/color/CustomColorPopover.d.ts +40 -0
- package/dist/editor/features/color/CustomColorPopover.d.ts.map +1 -0
- package/dist/editor/features/color/CustomColorPopover.js +70 -0
- package/dist/editor/features/color/CustomColorPopover.js.map +1 -0
- package/dist/editor/features/color/contrast.d.ts +26 -0
- package/dist/editor/features/color/contrast.d.ts.map +1 -0
- package/dist/editor/features/color/contrast.js +27 -0
- package/dist/editor/features/color/contrast.js.map +1 -0
- package/dist/editor/features/color/customColor.d.ts +65 -0
- package/dist/editor/features/color/customColor.d.ts.map +1 -0
- package/dist/editor/features/color/customColor.js +29 -0
- package/dist/editor/features/color/customColor.js.map +1 -0
- package/dist/editor/features/color/styleExtensions.d.ts +28 -0
- package/dist/editor/features/color/styleExtensions.d.ts.map +1 -0
- package/dist/editor/features/color/styleExtensions.js +172 -0
- package/dist/editor/features/color/styleExtensions.js.map +1 -0
- package/dist/editor/features/emoji/EmojiGrid.d.ts +34 -0
- package/dist/editor/features/emoji/EmojiGrid.d.ts.map +1 -0
- package/dist/editor/features/emoji/EmojiGrid.js +71 -0
- package/dist/editor/features/emoji/EmojiGrid.js.map +1 -0
- package/dist/editor/features/emoji/emoji.d.ts +47 -0
- package/dist/editor/features/emoji/emoji.d.ts.map +1 -0
- package/dist/editor/features/emoji/emoji.js +108 -0
- package/dist/editor/features/emoji/emoji.js.map +1 -0
- package/dist/editor/features/emoji/emojiTool.d.ts +32 -0
- package/dist/editor/features/emoji/emojiTool.d.ts.map +1 -0
- package/dist/editor/features/emoji/emojiTool.js +34 -0
- package/dist/editor/features/emoji/emojiTool.js.map +1 -0
- package/dist/editor/features/image/ImagePopover.d.ts +29 -0
- package/dist/editor/features/image/ImagePopover.d.ts.map +1 -0
- package/dist/editor/features/image/ImagePopover.js +89 -0
- package/dist/editor/features/image/ImagePopover.js.map +1 -0
- package/dist/editor/features/image/ImageToolbar.d.ts +25 -0
- package/dist/editor/features/image/ImageToolbar.d.ts.map +1 -0
- package/dist/editor/features/image/ImageToolbar.js +49 -0
- package/dist/editor/features/image/ImageToolbar.js.map +1 -0
- package/dist/editor/features/image/image.d.ts +115 -0
- package/dist/editor/features/image/image.d.ts.map +1 -0
- package/dist/editor/features/image/image.js +539 -0
- package/dist/editor/features/image/image.js.map +1 -0
- package/dist/editor/features/image/imageNotice.d.ts +6 -0
- package/dist/editor/features/image/imageNotice.d.ts.map +1 -0
- package/dist/editor/features/image/imageNotice.js +16 -0
- package/dist/editor/features/image/imageNotice.js.map +1 -0
- package/dist/editor/features/layout/columnLayouts.d.ts +36 -0
- package/dist/editor/features/layout/columnLayouts.d.ts.map +1 -0
- package/dist/editor/features/layout/columnLayouts.js +33 -0
- package/dist/editor/features/layout/columnLayouts.js.map +1 -0
- package/dist/editor/features/layout/layout.d.ts +81 -0
- package/dist/editor/features/layout/layout.d.ts.map +1 -0
- package/dist/editor/features/layout/layout.js +318 -0
- package/dist/editor/features/layout/layout.js.map +1 -0
- package/dist/editor/features/link/LinkPopover.d.ts +21 -0
- package/dist/editor/features/link/LinkPopover.d.ts.map +1 -0
- package/dist/editor/features/link/LinkPopover.js +54 -0
- package/dist/editor/features/link/LinkPopover.js.map +1 -0
- package/dist/editor/features/link/link.d.ts +41 -0
- package/dist/editor/features/link/link.d.ts.map +1 -0
- package/dist/editor/features/link/link.js +66 -0
- package/dist/editor/features/link/link.js.map +1 -0
- package/dist/editor/features/link/linkTool.d.ts +13 -0
- package/dist/editor/features/link/linkTool.d.ts.map +1 -0
- package/dist/editor/features/link/linkTool.js +25 -0
- package/dist/editor/features/link/linkTool.js.map +1 -0
- package/dist/editor/features/search/SearchPanel.d.ts +31 -0
- package/dist/editor/features/search/SearchPanel.d.ts.map +1 -0
- package/dist/editor/features/search/SearchPanel.js +101 -0
- package/dist/editor/features/search/SearchPanel.js.map +1 -0
- package/dist/editor/features/search/revealMatch.d.ts +25 -0
- package/dist/editor/features/search/revealMatch.d.ts.map +1 -0
- package/dist/editor/features/search/revealMatch.js +41 -0
- package/dist/editor/features/search/revealMatch.js.map +1 -0
- package/dist/editor/features/search/searchMatch.d.ts +53 -0
- package/dist/editor/features/search/searchMatch.d.ts.map +1 -0
- package/dist/editor/features/search/searchMatch.js +67 -0
- package/dist/editor/features/search/searchMatch.js.map +1 -0
- package/dist/editor/features/search/searchPlugin.d.ts +48 -0
- package/dist/editor/features/search/searchPlugin.d.ts.map +1 -0
- package/dist/editor/features/search/searchPlugin.js +151 -0
- package/dist/editor/features/search/searchPlugin.js.map +1 -0
- package/dist/editor/features/search/searchTool.d.ts +13 -0
- package/dist/editor/features/search/searchTool.d.ts.map +1 -0
- package/dist/editor/features/search/searchTool.js +18 -0
- package/dist/editor/features/search/searchTool.js.map +1 -0
- package/dist/editor/features/table/TableInsertDialog.d.ts +29 -0
- package/dist/editor/features/table/TableInsertDialog.d.ts.map +1 -0
- package/dist/editor/features/table/TableInsertDialog.js +37 -0
- package/dist/editor/features/table/TableInsertDialog.js.map +1 -0
- package/dist/editor/features/table/TableMenuButton.d.ts +40 -0
- package/dist/editor/features/table/TableMenuButton.d.ts.map +1 -0
- package/dist/editor/features/table/TableMenuButton.js +97 -0
- package/dist/editor/features/table/TableMenuButton.js.map +1 -0
- package/dist/editor/features/table/TableSizeGrid.d.ts +60 -0
- package/dist/editor/features/table/TableSizeGrid.d.ts.map +1 -0
- package/dist/editor/features/table/TableSizeGrid.js +88 -0
- package/dist/editor/features/table/TableSizeGrid.js.map +1 -0
- package/dist/editor/features/table/tableActions.d.ts +110 -0
- package/dist/editor/features/table/tableActions.d.ts.map +1 -0
- package/dist/editor/features/table/tableActions.js +254 -0
- package/dist/editor/features/table/tableActions.js.map +1 -0
- package/dist/editor/features/table/tableCells.d.ts +41 -0
- package/dist/editor/features/table/tableCells.d.ts.map +1 -0
- package/dist/editor/features/table/tableCells.js +38 -0
- package/dist/editor/features/table/tableCells.js.map +1 -0
- package/dist/editor/features/table/tableChunk.d.ts +4 -0
- package/dist/editor/features/table/tableChunk.d.ts.map +1 -0
- package/dist/editor/features/table/tableChunk.js +5 -0
- package/dist/editor/features/table/tableChunk.js.map +1 -0
- package/dist/editor/features/table/tableTool.d.ts +22 -0
- package/dist/editor/features/table/tableTool.d.ts.map +1 -0
- package/dist/editor/features/table/tableTool.js +42 -0
- package/dist/editor/features/table/tableTool.js.map +1 -0
- package/dist/editor/features/table/tables.d.ts +79 -0
- package/dist/editor/features/table/tables.d.ts.map +1 -0
- package/dist/editor/features/table/tables.js +118 -0
- package/dist/editor/features/table/tables.js.map +1 -0
- package/dist/editor/features/wrapper/wrapper.d.ts +73 -0
- package/dist/editor/features/wrapper/wrapper.d.ts.map +1 -0
- package/dist/editor/features/wrapper/wrapper.js +198 -0
- package/dist/editor/features/wrapper/wrapper.js.map +1 -0
- package/dist/editor/features/wrapper/wrapperTones.d.ts +39 -0
- package/dist/editor/features/wrapper/wrapperTones.d.ts.map +1 -0
- package/dist/editor/features/wrapper/wrapperTones.js +19 -0
- package/dist/editor/features/wrapper/wrapperTones.js.map +1 -0
- package/dist/editor/highlight-entry.d.ts +24 -0
- package/dist/editor/highlight-entry.d.ts.map +1 -0
- package/dist/editor/highlight-entry.js +3 -0
- package/dist/editor/highlight-entry.js.map +1 -0
- package/dist/editor/hooks/useChangeThrottle.d.ts +24 -0
- package/dist/editor/hooks/useChangeThrottle.d.ts.map +1 -0
- package/dist/editor/hooks/useChangeThrottle.js +35 -0
- package/dist/editor/hooks/useChangeThrottle.js.map +1 -0
- package/dist/editor/hooks/useCoarsePointer.d.ts +17 -0
- package/dist/editor/hooks/useCoarsePointer.d.ts.map +1 -0
- package/dist/editor/hooks/useCoarsePointer.js +19 -0
- package/dist/editor/hooks/useCoarsePointer.js.map +1 -0
- package/dist/editor/hooks/useFieldsetDisabled.d.ts +22 -0
- package/dist/editor/hooks/useFieldsetDisabled.d.ts.map +1 -0
- package/dist/editor/hooks/useFieldsetDisabled.js +29 -0
- package/dist/editor/hooks/useFieldsetDisabled.js.map +1 -0
- package/dist/editor/hooks/useRichTextEditorState.d.ts +25 -0
- package/dist/editor/hooks/useRichTextEditorState.d.ts.map +1 -0
- package/dist/editor/hooks/useRichTextEditorState.js +17 -0
- package/dist/editor/hooks/useRichTextEditorState.js.map +1 -0
- package/dist/editor/hooks/useSubmenuPlacement.d.ts +19 -0
- package/dist/editor/hooks/useSubmenuPlacement.d.ts.map +1 -0
- package/dist/editor/hooks/useSubmenuPlacement.js +20 -0
- package/dist/editor/hooks/useSubmenuPlacement.js.map +1 -0
- package/dist/editor/index.d.ts +32 -0
- package/dist/editor/index.d.ts.map +1 -0
- package/dist/editor/index.js +7 -0
- package/dist/editor/index.js.map +1 -0
- package/dist/editor/schema-entry.d.ts +29 -0
- package/dist/editor/schema-entry.d.ts.map +1 -0
- package/dist/editor/schema-entry.js +3 -0
- package/dist/editor/schema-entry.js.map +1 -0
- package/dist/editor/styles/codeTheme.d.ts +49 -0
- package/dist/editor/styles/codeTheme.d.ts.map +1 -0
- package/dist/editor/styles/codeTheme.js +11 -0
- package/dist/editor/styles/codeTheme.js.map +1 -0
- package/dist/editor/styles/glass.d.ts +40 -0
- package/dist/editor/styles/glass.d.ts.map +1 -0
- package/dist/editor/styles/glass.js +15 -0
- package/dist/editor/styles/glass.js.map +1 -0
- package/dist/editor/styles/palette.d.ts +181 -0
- package/dist/editor/styles/palette.d.ts.map +1 -0
- package/dist/editor/styles/palette.js +57 -0
- package/dist/editor/styles/palette.js.map +1 -0
- package/dist/editor/styles/prose.d.ts +56 -0
- package/dist/editor/styles/prose.d.ts.map +1 -0
- package/dist/editor/styles/prose.js +154 -0
- package/dist/editor/styles/prose.js.map +1 -0
- package/dist/editor/styles/surface.d.ts +22 -0
- package/dist/editor/styles/surface.d.ts.map +1 -0
- package/dist/editor/styles/surface.js +4 -0
- package/dist/editor/styles/surface.js.map +1 -0
- package/dist/editor/styles/tokens.d.ts +136 -0
- package/dist/editor/styles/tokens.d.ts.map +1 -0
- package/dist/editor/styles/tokens.js +38 -0
- package/dist/editor/styles/tokens.js.map +1 -0
- package/dist/editor/ui/BlockHandle.d.ts +40 -0
- package/dist/editor/ui/BlockHandle.d.ts.map +1 -0
- package/dist/editor/ui/BlockHandle.js +394 -0
- package/dist/editor/ui/BlockHandle.js.map +1 -0
- package/dist/editor/ui/BlockIsland.d.ts +3 -0
- package/dist/editor/ui/BlockIsland.d.ts.map +1 -0
- package/dist/editor/ui/BlockIsland.js +8 -0
- package/dist/editor/ui/BlockIsland.js.map +1 -0
- package/dist/editor/ui/BlockIslandSlots.d.ts +31 -0
- package/dist/editor/ui/BlockIslandSlots.d.ts.map +1 -0
- package/dist/editor/ui/BlockIslandSlots.js +61 -0
- package/dist/editor/ui/BlockIslandSlots.js.map +1 -0
- package/dist/editor/ui/ColorMenus.d.ts +18 -0
- package/dist/editor/ui/ColorMenus.d.ts.map +1 -0
- package/dist/editor/ui/ColorMenus.js +281 -0
- package/dist/editor/ui/ColorMenus.js.map +1 -0
- package/dist/editor/ui/EditorToolbar.d.ts +71 -0
- package/dist/editor/ui/EditorToolbar.d.ts.map +1 -0
- package/dist/editor/ui/EditorToolbar.js +197 -0
- package/dist/editor/ui/EditorToolbar.js.map +1 -0
- package/dist/editor/ui/FieldResizer.d.ts +22 -0
- package/dist/editor/ui/FieldResizer.d.ts.map +1 -0
- package/dist/editor/ui/FieldResizer.js +75 -0
- package/dist/editor/ui/FieldResizer.js.map +1 -0
- package/dist/editor/ui/FieldStatus.d.ts +32 -0
- package/dist/editor/ui/FieldStatus.d.ts.map +1 -0
- package/dist/editor/ui/FieldStatus.js +15 -0
- package/dist/editor/ui/FieldStatus.js.map +1 -0
- package/dist/editor/ui/FloatingToolbar.d.ts +32 -0
- package/dist/editor/ui/FloatingToolbar.d.ts.map +1 -0
- package/dist/editor/ui/FloatingToolbar.js +17 -0
- package/dist/editor/ui/FloatingToolbar.js.map +1 -0
- package/dist/editor/ui/FormatMenus.d.ts +210 -0
- package/dist/editor/ui/FormatMenus.d.ts.map +1 -0
- package/dist/editor/ui/FormatMenus.js +296 -0
- package/dist/editor/ui/FormatMenus.js.map +1 -0
- package/dist/editor/ui/InsertMenuButton.d.ts +25 -0
- package/dist/editor/ui/InsertMenuButton.d.ts.map +1 -0
- package/dist/editor/ui/InsertMenuButton.js +28 -0
- package/dist/editor/ui/InsertMenuButton.js.map +1 -0
- package/dist/editor/ui/SelectionBubble.d.ts +46 -0
- package/dist/editor/ui/SelectionBubble.d.ts.map +1 -0
- package/dist/editor/ui/SelectionBubble.js +90 -0
- package/dist/editor/ui/SelectionBubble.js.map +1 -0
- package/dist/editor/ui/ShortcutsButton.d.ts +29 -0
- package/dist/editor/ui/ShortcutsButton.d.ts.map +1 -0
- package/dist/editor/ui/ShortcutsButton.js +34 -0
- package/dist/editor/ui/ShortcutsButton.js.map +1 -0
- package/dist/editor/ui/SlashMenu.d.ts +42 -0
- package/dist/editor/ui/SlashMenu.d.ts.map +1 -0
- package/dist/editor/ui/SlashMenu.js +114 -0
- package/dist/editor/ui/SlashMenu.js.map +1 -0
- package/dist/editor/ui/SuggestionList.d.ts +60 -0
- package/dist/editor/ui/SuggestionList.d.ts.map +1 -0
- package/dist/editor/ui/SuggestionList.js +61 -0
- package/dist/editor/ui/SuggestionList.js.map +1 -0
- package/dist/editor/ui/TextCard.d.ts +20 -0
- package/dist/editor/ui/TextCard.d.ts.map +1 -0
- package/dist/editor/ui/TextCard.js +192 -0
- package/dist/editor/ui/TextCard.js.map +1 -0
- package/dist/editor/ui/ToolButtonView.d.ts +58 -0
- package/dist/editor/ui/ToolButtonView.d.ts.map +1 -0
- package/dist/editor/ui/ToolButtonView.js +86 -0
- package/dist/editor/ui/ToolButtonView.js.map +1 -0
- package/dist/editor/ui/TriggerMenu.d.ts +25 -0
- package/dist/editor/ui/TriggerMenu.d.ts.map +1 -0
- package/dist/editor/ui/TriggerMenu.js +180 -0
- package/dist/editor/ui/TriggerMenu.js.map +1 -0
- package/dist/editor/ui/focusWithin.d.ts +22 -0
- package/dist/editor/ui/focusWithin.d.ts.map +1 -0
- package/dist/editor/ui/focusWithin.js +5 -0
- package/dist/editor/ui/focusWithin.js.map +1 -0
- package/dist/editor/ui/lockableMenu.d.ts +28 -0
- package/dist/editor/ui/lockableMenu.d.ts.map +1 -0
- package/dist/editor/ui/lockableMenu.js +17 -0
- package/dist/editor/ui/lockableMenu.js.map +1 -0
- package/dist/editor/ui/rowMarks.d.ts +21 -0
- package/dist/editor/ui/rowMarks.d.ts.map +1 -0
- package/dist/editor/ui/rowMarks.js +35 -0
- package/dist/editor/ui/rowMarks.js.map +1 -0
- package/dist/editor/ui/selectionMenu.d.ts +61 -0
- package/dist/editor/ui/selectionMenu.d.ts.map +1 -0
- package/dist/editor/ui/selectionMenu.js +32 -0
- package/dist/editor/ui/selectionMenu.js.map +1 -0
- package/dist/hooks/useFieldDescription.d.ts +45 -0
- package/dist/hooks/useFieldDescription.d.ts.map +1 -0
- package/dist/hooks/useFieldDescription.js +23 -0
- package/dist/hooks/useFieldDescription.js.map +1 -0
- package/dist/hooks/useMediaQuery.d.ts +25 -0
- package/dist/hooks/useMediaQuery.d.ts.map +1 -0
- package/dist/hooks/useMediaQuery.js +14 -0
- package/dist/hooks/useMediaQuery.js.map +1 -0
- package/dist/hooks/useOpenerFocus.d.ts +10 -0
- package/dist/hooks/useOpenerFocus.d.ts.map +1 -0
- package/dist/hooks/useOpenerFocus.js +35 -0
- package/dist/hooks/useOpenerFocus.js.map +1 -0
- package/dist/hooks/useOverlayLayer.d.ts +23 -0
- package/dist/hooks/useOverlayLayer.d.ts.map +1 -0
- package/dist/hooks/useOverlayLayer.js +19 -0
- package/dist/hooks/useOverlayLayer.js.map +1 -0
- package/dist/hooks/useScrollLock.d.ts +3 -0
- package/dist/hooks/useScrollLock.d.ts.map +1 -0
- package/dist/hooks/useScrollLock.js +52 -0
- package/dist/hooks/useScrollLock.js.map +1 -0
- package/dist/hooks/useStickyOffset.d.ts +53 -0
- package/dist/hooks/useStickyOffset.d.ts.map +1 -0
- package/dist/hooks/useStickyOffset.js +91 -0
- package/dist/hooks/useStickyOffset.js.map +1 -0
- package/dist/hooks/useTableState.d.ts +35 -0
- package/dist/hooks/useTableState.d.ts.map +1 -0
- package/dist/hooks/useTableState.js +23 -0
- package/dist/hooks/useTableState.js.map +1 -0
- package/dist/i18n/UiProvider.d.ts +53 -0
- package/dist/i18n/UiProvider.d.ts.map +1 -0
- package/dist/i18n/UiProvider.js +63 -0
- package/dist/i18n/UiProvider.js.map +1 -0
- package/dist/i18n/context.d.ts +26 -0
- package/dist/i18n/context.d.ts.map +1 -0
- package/dist/i18n/context.js +4 -0
- package/dist/i18n/context.js.map +1 -0
- package/dist/i18n/defaults.d.ts +19 -0
- package/dist/i18n/defaults.d.ts.map +1 -0
- package/dist/i18n/defaults.js +574 -0
- package/dist/i18n/defaults.js.map +1 -0
- package/dist/i18n/messages.d.ts +1178 -0
- package/dist/i18n/messages.d.ts.map +1 -0
- package/dist/i18n/messages.js +2 -0
- package/dist/i18n/messages.js.map +1 -0
- package/dist/i18n/useMessages.d.ts +26 -0
- package/dist/i18n/useMessages.d.ts.map +1 -0
- package/dist/i18n/useMessages.js +22 -0
- package/dist/i18n/useMessages.js.map +1 -0
- package/dist/icons.d.ts +437 -0
- package/dist/icons.d.ts.map +1 -0
- package/dist/icons.js +2 -0
- package/dist/icons.js.map +1 -0
- package/dist/index.d.ts +250 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +128 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/accessible-name.d.ts +34 -0
- package/dist/lib/accessible-name.d.ts.map +1 -0
- package/dist/lib/accessible-name.js +2 -0
- package/dist/lib/accessible-name.js.map +1 -0
- package/dist/lib/bottom-bar-slot.d.ts +24 -0
- package/dist/lib/bottom-bar-slot.d.ts.map +1 -0
- package/dist/lib/bottom-bar-slot.js +4 -0
- package/dist/lib/bottom-bar-slot.js.map +1 -0
- package/dist/lib/button.d.ts +36 -0
- package/dist/lib/button.d.ts.map +1 -0
- package/dist/lib/button.js +35 -0
- package/dist/lib/button.js.map +1 -0
- package/dist/lib/choice-card.d.ts +64 -0
- package/dist/lib/choice-card.d.ts.map +1 -0
- package/dist/lib/choice-card.js +15 -0
- package/dist/lib/choice-card.js.map +1 -0
- package/dist/lib/clamp.d.ts +17 -0
- package/dist/lib/clamp.d.ts.map +1 -0
- package/dist/lib/clamp.js +4 -0
- package/dist/lib/clamp.js.map +1 -0
- package/dist/lib/cn.d.ts +12 -0
- package/dist/lib/cn.d.ts.map +1 -0
- package/dist/lib/cn.js +14 -0
- package/dist/lib/cn.js.map +1 -0
- package/dist/lib/date.d.ts +61 -0
- package/dist/lib/date.d.ts.map +1 -0
- package/dist/lib/date.js +30 -0
- package/dist/lib/date.js.map +1 -0
- package/dist/lib/dev-warn.d.ts +26 -0
- package/dist/lib/dev-warn.d.ts.map +1 -0
- package/dist/lib/dev-warn.js +28 -0
- package/dist/lib/dev-warn.js.map +1 -0
- package/dist/lib/empty.d.ts +35 -0
- package/dist/lib/empty.d.ts.map +1 -0
- package/dist/lib/empty.js +11 -0
- package/dist/lib/empty.js.map +1 -0
- package/dist/lib/field.d.ts +105 -0
- package/dist/lib/field.d.ts.map +1 -0
- package/dist/lib/field.js +18 -0
- package/dist/lib/field.js.map +1 -0
- package/dist/lib/filter-range.d.ts +24 -0
- package/dist/lib/filter-range.d.ts.map +1 -0
- package/dist/lib/filter-range.js +27 -0
- package/dist/lib/filter-range.js.map +1 -0
- package/dist/lib/interaction-modality.d.ts +40 -0
- package/dist/lib/interaction-modality.d.ts.map +1 -0
- package/dist/lib/interaction-modality.js +60 -0
- package/dist/lib/interaction-modality.js.map +1 -0
- package/dist/lib/mask.d.ts +94 -0
- package/dist/lib/mask.d.ts.map +1 -0
- package/dist/lib/mask.js +114 -0
- package/dist/lib/mask.js.map +1 -0
- package/dist/lib/menu.d.ts +85 -0
- package/dist/lib/menu.d.ts.map +1 -0
- package/dist/lib/menu.js +33 -0
- package/dist/lib/menu.js.map +1 -0
- package/dist/lib/overlay-layer.d.ts +101 -0
- package/dist/lib/overlay-layer.d.ts.map +1 -0
- package/dist/lib/overlay-layer.js +40 -0
- package/dist/lib/overlay-layer.js.map +1 -0
- package/dist/lib/period.d.ts +82 -0
- package/dist/lib/period.d.ts.map +1 -0
- package/dist/lib/period.js +58 -0
- package/dist/lib/period.js.map +1 -0
- package/dist/lib/progress-status.d.ts +38 -0
- package/dist/lib/progress-status.d.ts.map +1 -0
- package/dist/lib/progress-status.js +7 -0
- package/dist/lib/progress-status.js.map +1 -0
- package/dist/lib/published-height.d.ts +16 -0
- package/dist/lib/published-height.d.ts.map +1 -0
- package/dist/lib/published-height.js +72 -0
- package/dist/lib/published-height.js.map +1 -0
- package/dist/lib/reorder.d.ts +44 -0
- package/dist/lib/reorder.d.ts.map +1 -0
- package/dist/lib/reorder.js +22 -0
- package/dist/lib/reorder.js.map +1 -0
- package/dist/lib/responsive.d.ts +51 -0
- package/dist/lib/responsive.d.ts.map +1 -0
- package/dist/lib/responsive.js +12 -0
- package/dist/lib/responsive.js.map +1 -0
- package/dist/lib/state.d.ts +25 -0
- package/dist/lib/state.d.ts.map +1 -0
- package/dist/lib/state.js +21 -0
- package/dist/lib/state.js.map +1 -0
- package/dist/lib/table-state.d.ts +105 -0
- package/dist/lib/table-state.d.ts.map +1 -0
- package/dist/lib/table-state.js +121 -0
- package/dist/lib/table-state.js.map +1 -0
- package/dist/lib/tag.d.ts +25 -0
- package/dist/lib/tag.d.ts.map +1 -0
- package/dist/lib/tag.js +6 -0
- package/dist/lib/tag.js.map +1 -0
- package/dist/lib/themes.d.ts +54 -0
- package/dist/lib/themes.d.ts.map +1 -0
- package/dist/lib/themes.js +40 -0
- package/dist/lib/themes.js.map +1 -0
- package/dist/lib/time.d.ts +35 -0
- package/dist/lib/time.d.ts.map +1 -0
- package/dist/lib/time.js +68 -0
- package/dist/lib/time.js.map +1 -0
- package/dist/lib/toolbar-axis.d.ts +17 -0
- package/dist/lib/toolbar-axis.d.ts.map +1 -0
- package/dist/lib/toolbar-axis.js +10 -0
- package/dist/lib/toolbar-axis.js.map +1 -0
- package/dist/lib/touch.d.ts +16 -0
- package/dist/lib/touch.d.ts.map +1 -0
- package/dist/lib/touch.js +2 -0
- package/dist/lib/touch.js.map +1 -0
- package/dist/lib/variants.d.ts +204 -0
- package/dist/lib/variants.d.ts.map +1 -0
- package/dist/lib/variants.js +127 -0
- package/dist/lib/variants.js.map +1 -0
- package/dist/locales/en.d.ts +11 -0
- package/dist/locales/en.d.ts.map +1 -0
- package/dist/locales/en.js +3 -0
- package/dist/locales/en.js.map +1 -0
- package/dist/locales/ru.d.ts +5 -0
- package/dist/locales/ru.d.ts.map +1 -0
- package/dist/locales/ru.js +591 -0
- package/dist/locales/ru.js.map +1 -0
- package/docs/accessibility.en.md +79 -0
- package/docs/accessibility.md +73 -0
- package/docs/api/editor-extension.en.md +309 -0
- package/docs/api/editor-extension.md +308 -0
- package/docs/api/messages.md +750 -0
- package/docs/api/migration-notes.en.md +885 -0
- package/docs/api/migration-notes.md +890 -0
- package/docs/api/utilities.md +252 -0
- package/docs/component-selection.en.md +48 -0
- package/docs/component-selection.md +44 -0
- package/docs/components/actions/button.en.md +59 -0
- package/docs/components/actions/button.md +58 -0
- package/docs/components/actions/chip.en.md +47 -0
- package/docs/components/actions/chip.md +46 -0
- package/docs/components/actions/copy-and-truncate.en.md +98 -0
- package/docs/components/actions/copy-and-truncate.md +96 -0
- package/docs/components/actions/feedback.en.md +69 -0
- package/docs/components/actions/feedback.md +68 -0
- package/docs/components/actions/split-button.en.md +76 -0
- package/docs/components/actions/split-button.md +75 -0
- package/docs/components/actions/toggles.en.md +139 -0
- package/docs/components/actions/toggles.md +136 -0
- package/docs/components/actions/toolbar.en.md +197 -0
- package/docs/components/actions/toolbar.md +192 -0
- package/docs/components/app-shell/app-shell.en.md +172 -0
- package/docs/components/app-shell/app-shell.md +172 -0
- package/docs/components/app-shell/mobile-tab-bar.en.md +207 -0
- package/docs/components/app-shell/mobile-tab-bar.md +210 -0
- package/docs/components/app-shell/side-nav.en.md +153 -0
- package/docs/components/app-shell/side-nav.md +152 -0
- package/docs/components/app-shell/split-panel.en.md +148 -0
- package/docs/components/app-shell/split-panel.md +147 -0
- package/docs/components/app-shell/top-bar.en.md +103 -0
- package/docs/components/app-shell/top-bar.md +100 -0
- package/docs/components/content/avatar.en.md +123 -0
- package/docs/components/content/avatar.md +119 -0
- package/docs/components/content/card.en.md +123 -0
- package/docs/components/content/card.md +122 -0
- package/docs/components/content/carousel.en.md +236 -0
- package/docs/components/content/carousel.md +227 -0
- package/docs/components/content/code-view.en.md +177 -0
- package/docs/components/content/code-view.md +172 -0
- package/docs/components/content/data-display.en.md +205 -0
- package/docs/components/content/data-display.md +212 -0
- package/docs/components/content/editable-list.en.md +437 -0
- package/docs/components/content/editable-list.md +418 -0
- package/docs/components/content/empty-and-loading.en.md +149 -0
- package/docs/components/content/empty-and-loading.md +149 -0
- package/docs/components/content/grid.en.md +148 -0
- package/docs/components/content/grid.md +142 -0
- package/docs/components/content/image.en.md +115 -0
- package/docs/components/content/image.md +114 -0
- package/docs/components/content/keyboard.en.md +129 -0
- package/docs/components/content/keyboard.md +129 -0
- package/docs/components/content/layout-primitives.en.md +105 -0
- package/docs/components/content/layout-primitives.md +104 -0
- package/docs/components/content/media-card.en.md +137 -0
- package/docs/components/content/media-card.md +132 -0
- package/docs/components/content/notifications.en.md +216 -0
- package/docs/components/content/notifications.md +207 -0
- package/docs/components/content/rich-text-view.en.md +325 -0
- package/docs/components/content/rich-text-view.md +324 -0
- package/docs/components/content/sortable-list.en.md +212 -0
- package/docs/components/content/sortable-list.md +206 -0
- package/docs/components/content/tag-group.en.md +158 -0
- package/docs/components/content/tag-group.md +151 -0
- package/docs/components/content/timeline.en.md +77 -0
- package/docs/components/content/timeline.md +76 -0
- package/docs/components/content/typography.en.md +152 -0
- package/docs/components/content/typography.md +146 -0
- package/docs/components/content/virtual-grid.en.md +305 -0
- package/docs/components/content/virtual-grid.md +315 -0
- package/docs/components/date-time/calendar.en.md +47 -0
- package/docs/components/date-time/calendar.md +46 -0
- package/docs/components/date-time/date-picker.en.md +52 -0
- package/docs/components/date-time/date-picker.md +50 -0
- package/docs/components/date-time/date-range-picker.en.md +58 -0
- package/docs/components/date-time/date-range-picker.md +57 -0
- package/docs/components/date-time/date-time-picker.en.md +44 -0
- package/docs/components/date-time/date-time-picker.md +43 -0
- package/docs/components/date-time/range-calendar.en.md +47 -0
- package/docs/components/date-time/range-calendar.md +46 -0
- package/docs/components/date-time/time-picker.en.md +47 -0
- package/docs/components/date-time/time-picker.md +51 -0
- package/docs/components/index.en.md +155 -0
- package/docs/components/index.md +150 -0
- package/docs/components/inputs/choice-controls.en.md +118 -0
- package/docs/components/inputs/choice-controls.md +112 -0
- package/docs/components/inputs/color-picker.en.md +126 -0
- package/docs/components/inputs/color-picker.md +122 -0
- package/docs/components/inputs/combobox.en.md +62 -0
- package/docs/components/inputs/combobox.md +58 -0
- package/docs/components/inputs/file-dropzone.en.md +51 -0
- package/docs/components/inputs/file-dropzone.md +50 -0
- package/docs/components/inputs/form-layout.en.md +99 -0
- package/docs/components/inputs/form-layout.md +97 -0
- package/docs/components/inputs/form.en.md +87 -0
- package/docs/components/inputs/form.md +86 -0
- package/docs/components/inputs/inline-edit.en.md +93 -0
- package/docs/components/inputs/inline-edit.md +94 -0
- package/docs/components/inputs/masked-input.en.md +149 -0
- package/docs/components/inputs/masked-input.md +147 -0
- package/docs/components/inputs/number-input.en.md +81 -0
- package/docs/components/inputs/number-input.md +80 -0
- package/docs/components/inputs/password-input.en.md +101 -0
- package/docs/components/inputs/password-input.md +97 -0
- package/docs/components/inputs/phone-input.en.md +78 -0
- package/docs/components/inputs/phone-input.md +76 -0
- package/docs/components/inputs/pin-input.en.md +109 -0
- package/docs/components/inputs/pin-input.md +108 -0
- package/docs/components/inputs/rating.en.md +100 -0
- package/docs/components/inputs/rating.md +99 -0
- package/docs/components/inputs/rich-text-editor.en.md +1539 -0
- package/docs/components/inputs/rich-text-editor.md +1538 -0
- package/docs/components/inputs/search-control.en.md +60 -0
- package/docs/components/inputs/search-control.md +58 -0
- package/docs/components/inputs/select.en.md +68 -0
- package/docs/components/inputs/select.md +65 -0
- package/docs/components/inputs/slider.en.md +60 -0
- package/docs/components/inputs/slider.md +59 -0
- package/docs/components/inputs/swatch-group.en.md +181 -0
- package/docs/components/inputs/swatch-group.md +177 -0
- package/docs/components/inputs/tag-input.en.md +50 -0
- package/docs/components/inputs/tag-input.md +48 -0
- package/docs/components/inputs/text-control.en.md +76 -0
- package/docs/components/inputs/text-control.md +74 -0
- package/docs/components/inputs/transfer.en.md +118 -0
- package/docs/components/inputs/transfer.md +114 -0
- package/docs/components/inputs/tree-select.en.md +91 -0
- package/docs/components/inputs/tree-select.md +89 -0
- package/docs/components/inputs/upload-queue.en.md +160 -0
- package/docs/components/inputs/upload-queue.md +158 -0
- package/docs/components/navigation/accordion.en.md +76 -0
- package/docs/components/navigation/accordion.md +75 -0
- package/docs/components/navigation/breadcrumbs.en.md +73 -0
- package/docs/components/navigation/breadcrumbs.md +72 -0
- package/docs/components/navigation/contextual-save-bar.en.md +104 -0
- package/docs/components/navigation/contextual-save-bar.md +103 -0
- package/docs/components/navigation/page-header.en.md +71 -0
- package/docs/components/navigation/page-header.md +70 -0
- package/docs/components/navigation/pagination.en.md +69 -0
- package/docs/components/navigation/pagination.md +69 -0
- package/docs/components/navigation/section-header.en.md +67 -0
- package/docs/components/navigation/section-header.md +66 -0
- package/docs/components/navigation/selection-bar.en.md +83 -0
- package/docs/components/navigation/selection-bar.md +83 -0
- package/docs/components/navigation/stepper.en.md +78 -0
- package/docs/components/navigation/stepper.md +77 -0
- package/docs/components/navigation/tabs.en.md +71 -0
- package/docs/components/navigation/tabs.md +70 -0
- package/docs/components/navigation/tree-view.en.md +173 -0
- package/docs/components/navigation/tree-view.md +172 -0
- package/docs/components/overlays/command-palette.en.md +153 -0
- package/docs/components/overlays/command-palette.md +147 -0
- package/docs/components/overlays/confirm-dialog.en.md +134 -0
- package/docs/components/overlays/confirm-dialog.md +127 -0
- package/docs/components/overlays/context-menu.en.md +115 -0
- package/docs/components/overlays/context-menu.md +113 -0
- package/docs/components/overlays/dialog.en.md +120 -0
- package/docs/components/overlays/dialog.md +117 -0
- package/docs/components/overlays/drawer.en.md +87 -0
- package/docs/components/overlays/drawer.md +88 -0
- package/docs/components/overlays/hover-card.en.md +179 -0
- package/docs/components/overlays/hover-card.md +175 -0
- package/docs/components/overlays/menu.en.md +103 -0
- package/docs/components/overlays/menu.md +100 -0
- package/docs/components/overlays/popover.en.md +78 -0
- package/docs/components/overlays/popover.md +77 -0
- package/docs/components/overlays/shortcuts-help.en.md +190 -0
- package/docs/components/overlays/shortcuts-help.md +186 -0
- package/docs/components/overlays/tooltip.en.md +78 -0
- package/docs/components/overlays/tooltip.md +77 -0
- package/docs/components/table/data-table.en.md +137 -0
- package/docs/components/table/data-table.md +133 -0
- package/docs/components/table/filter-bar.en.md +161 -0
- package/docs/components/table/filter-bar.md +155 -0
- package/docs/components/table/saved-views.en.md +117 -0
- package/docs/components/table/saved-views.md +115 -0
- package/docs/components/table/toolbar.en.md +100 -0
- package/docs/components/table/toolbar.md +97 -0
- package/docs/conventions.md +358 -0
- package/docs/getting-started.en.md +382 -0
- package/docs/getting-started.md +381 -0
- package/docs/glossary.en.md +179 -0
- package/docs/glossary.md +174 -0
- package/docs/i18n.en.md +147 -0
- package/docs/i18n.md +143 -0
- package/docs/icons.en.md +252 -0
- package/docs/icons.md +251 -0
- package/docs/index.md +62 -0
- package/docs/palette.en.md +400 -0
- package/docs/palette.md +396 -0
- package/docs/theming.en.md +522 -0
- package/docs/theming.md +518 -0
- package/llms.txt +144 -0
- package/package.json +173 -4
- package/src/color.ts +21 -0
- package/src/components/actions/Alert.tsx +121 -0
- package/src/components/actions/Banner.tsx +120 -0
- package/src/components/actions/Button.tsx +241 -0
- package/src/components/actions/ButtonGroup.tsx +65 -0
- package/src/components/actions/Chip.tsx +113 -0
- package/src/components/actions/CopyButton.tsx +112 -0
- package/src/components/actions/Progress.tsx +103 -0
- package/src/components/actions/Segmented.tsx +162 -0
- package/src/components/actions/Spinner.tsx +80 -0
- package/src/components/actions/SplitButton.tsx +164 -0
- package/src/components/actions/StatusBadge.tsx +61 -0
- package/src/components/actions/Toaster.tsx +148 -0
- package/src/components/actions/Toggle.tsx +224 -0
- package/src/components/actions/ToggleGroup.tsx +147 -0
- package/src/components/actions/Toolbar.tsx +223 -0
- package/src/components/actions/Truncate.tsx +96 -0
- package/src/components/app-shell/AppShell.tsx +268 -0
- package/src/components/app-shell/MobileTabBar.tsx +305 -0
- package/src/components/app-shell/NavItem.tsx +149 -0
- package/src/components/app-shell/SideNav.tsx +217 -0
- package/src/components/app-shell/SplitPanel.tsx +381 -0
- package/src/components/app-shell/TopBar.tsx +115 -0
- package/src/components/content/AspectRatio.tsx +45 -0
- package/src/components/content/Avatar.tsx +132 -0
- package/src/components/content/AvatarGroup.tsx +92 -0
- package/src/components/content/Badge.tsx +78 -0
- package/src/components/content/Card.tsx +117 -0
- package/src/components/content/Carousel.tsx +427 -0
- package/src/components/content/CodeView.tsx +178 -0
- package/src/components/content/DescriptionList.tsx +64 -0
- package/src/components/content/EditableList.tsx +879 -0
- package/src/components/content/EmptyState.tsx +65 -0
- package/src/components/content/ErrorState.tsx +100 -0
- package/src/components/content/Grid.tsx +208 -0
- package/src/components/content/Heading.tsx +81 -0
- package/src/components/content/Image.tsx +235 -0
- package/src/components/content/Kbd.tsx +67 -0
- package/src/components/content/Keyboard.tsx +634 -0
- package/src/components/content/Link.tsx +199 -0
- package/src/components/content/MediaCard.tsx +167 -0
- package/src/components/content/NotificationCenter.tsx +168 -0
- package/src/components/content/NotificationList.tsx +329 -0
- package/src/components/content/ScrollArea.tsx +69 -0
- package/src/components/content/Separator.tsx +62 -0
- package/src/components/content/Skeleton.tsx +40 -0
- package/src/components/content/SortableList.tsx +249 -0
- package/src/components/content/Stat.tsx +75 -0
- package/src/components/content/Table.tsx +500 -0
- package/src/components/content/TagGroup.tsx +222 -0
- package/src/components/content/Text.tsx +127 -0
- package/src/components/content/Timeline.tsx +126 -0
- package/src/components/content/VirtualGrid.tsx +726 -0
- package/src/components/content/VisuallyHidden.tsx +25 -0
- package/src/components/content/keyboardEditing.ts +51 -0
- package/src/components/content/useDragToSelect.ts +255 -0
- package/src/components/date-time/Calendar.tsx +181 -0
- package/src/components/date-time/DatePicker.tsx +143 -0
- package/src/components/date-time/DateRangePicker.tsx +349 -0
- package/src/components/date-time/DateTimePicker.tsx +92 -0
- package/src/components/date-time/RangeCalendar.tsx +156 -0
- package/src/components/date-time/TimePicker.tsx +377 -0
- package/src/components/inputs/Checkbox.tsx +284 -0
- package/src/components/inputs/CheckboxCard.tsx +132 -0
- package/src/components/inputs/CheckboxGroup.tsx +140 -0
- package/src/components/inputs/ChoiceCardBody.tsx +53 -0
- package/src/components/inputs/ColorPicker.tsx +221 -0
- package/src/components/inputs/Combobox.tsx +156 -0
- package/src/components/inputs/FileDropzone.tsx +253 -0
- package/src/components/inputs/Form.tsx +77 -0
- package/src/components/inputs/FormField.tsx +235 -0
- package/src/components/inputs/FormLayout.tsx +80 -0
- package/src/components/inputs/InlineEdit.tsx +205 -0
- package/src/components/inputs/MaskedInput.tsx +288 -0
- package/src/components/inputs/NumberInput.tsx +138 -0
- package/src/components/inputs/PasswordInput.tsx +166 -0
- package/src/components/inputs/PhoneInput.tsx +55 -0
- package/src/components/inputs/PinInput.tsx +197 -0
- package/src/components/inputs/RadioGroup.tsx +322 -0
- package/src/components/inputs/Rating.tsx +224 -0
- package/src/components/inputs/SearchControl.tsx +278 -0
- package/src/components/inputs/Select.tsx +741 -0
- package/src/components/inputs/Slider.tsx +436 -0
- package/src/components/inputs/SwatchGroup.tsx +342 -0
- package/src/components/inputs/TagInput.tsx +221 -0
- package/src/components/inputs/TextControl.tsx +335 -0
- package/src/components/inputs/Transfer.tsx +368 -0
- package/src/components/inputs/TreeSelect.tsx +275 -0
- package/src/components/inputs/UploadQueue.tsx +240 -0
- package/src/components/navigation/Accordion.tsx +118 -0
- package/src/components/navigation/Breadcrumbs.tsx +112 -0
- package/src/components/navigation/ContextualSaveBar.tsx +174 -0
- package/src/components/navigation/PageHeader.tsx +41 -0
- package/src/components/navigation/Pagination.tsx +184 -0
- package/src/components/navigation/SectionHeader.tsx +54 -0
- package/src/components/navigation/SelectionBar.tsx +151 -0
- package/src/components/navigation/Stepper.tsx +153 -0
- package/src/components/navigation/Tabs.tsx +130 -0
- package/src/components/navigation/TreeView.tsx +246 -0
- package/src/components/overlays/CommandPalette.tsx +343 -0
- package/src/components/overlays/ConfirmDialog.tsx +272 -0
- package/src/components/overlays/ContextMenu.tsx +284 -0
- package/src/components/overlays/Dialog.tsx +283 -0
- package/src/components/overlays/Drawer.tsx +193 -0
- package/src/components/overlays/HelpTooltip.tsx +96 -0
- package/src/components/overlays/HoverCard.tsx +404 -0
- package/src/components/overlays/Menu.tsx +243 -0
- package/src/components/overlays/ModalHeader.tsx +125 -0
- package/src/components/overlays/ModalOverlay.tsx +108 -0
- package/src/components/overlays/Popover.tsx +120 -0
- package/src/components/overlays/ShortcutsHelp.tsx +147 -0
- package/src/components/overlays/Tooltip.tsx +89 -0
- package/src/components/table/DataTable.tsx +164 -0
- package/src/components/table/FilterBar.tsx +114 -0
- package/src/components/table/FilterBarAdd.tsx +268 -0
- package/src/components/table/SavedViews.tsx +122 -0
- package/src/components/table/TablePreferences.tsx +173 -0
- package/src/components/table/TableToolbar.tsx +74 -0
- package/src/editor/RichTextEditor.tsx +1747 -0
- package/src/editor/RichTextView.tsx +119 -0
- package/src/editor/core/atomText.ts +140 -0
- package/src/editor/core/blockCommands.ts +329 -0
- package/src/editor/core/blockTypes.ts +252 -0
- package/src/editor/core/containers.ts +100 -0
- package/src/editor/core/customMarkdown.ts +74 -0
- package/src/editor/core/customTool.ts +472 -0
- package/src/editor/core/customToolEngine.ts +442 -0
- package/src/editor/core/document.ts +27 -0
- package/src/editor/core/emptiness.ts +31 -0
- package/src/editor/core/extensions.ts +295 -0
- package/src/editor/core/fieldNotice.ts +75 -0
- package/src/editor/core/handle.ts +311 -0
- package/src/editor/core/insertItems.ts +434 -0
- package/src/editor/core/jsonDocument.ts +99 -0
- package/src/editor/core/markdown.ts +313 -0
- package/src/editor/core/maxLength.ts +99 -0
- package/src/editor/core/pasteTrim.ts +85 -0
- package/src/editor/core/schema.ts +986 -0
- package/src/editor/core/schemaConform.ts +122 -0
- package/src/editor/core/shortcuts.ts +435 -0
- package/src/editor/core/skeleton.ts +108 -0
- package/src/editor/core/slashCommand.ts +143 -0
- package/src/editor/core/sourceFormat.ts +194 -0
- package/src/editor/core/toolButtons.ts +133 -0
- package/src/editor/core/toolDescriptor.ts +359 -0
- package/src/editor/core/toolEntryShortcuts.ts +66 -0
- package/src/editor/core/toolLoader.ts +50 -0
- package/src/editor/core/tools.ts +150 -0
- package/src/editor/core/viewIsland.ts +35 -0
- package/src/editor/features/builtins.ts +145 -0
- package/src/editor/features/code/CodeBlockView.tsx +240 -0
- package/src/editor/features/code/CodeCopyButton.tsx +76 -0
- package/src/editor/features/code/CodeCopyIsland.tsx +71 -0
- package/src/editor/features/code/codeBlock.ts +188 -0
- package/src/editor/features/code/codeBlockTool.ts +107 -0
- package/src/editor/features/code/codeHeader.ts +97 -0
- package/src/editor/features/code/codeLanguages.ts +62 -0
- package/src/editor/features/code/highlight.ts +109 -0
- package/src/editor/features/code/highlightNodes.ts +65 -0
- package/src/editor/features/code/lowlight.ts +45 -0
- package/src/editor/features/color/CustomColorPopover.tsx +180 -0
- package/src/editor/features/color/contrast.ts +52 -0
- package/src/editor/features/color/customColor.ts +91 -0
- package/src/editor/features/color/styleExtensions.ts +316 -0
- package/src/editor/features/emoji/EmojiGrid.tsx +160 -0
- package/src/editor/features/emoji/emoji.ts +156 -0
- package/src/editor/features/emoji/emojiTool.tsx +67 -0
- package/src/editor/features/image/ImagePopover.tsx +254 -0
- package/src/editor/features/image/ImageToolbar.tsx +147 -0
- package/src/editor/features/image/image.ts +821 -0
- package/src/editor/features/image/imageNotice.ts +27 -0
- package/src/editor/features/layout/columnLayouts.ts +71 -0
- package/src/editor/features/layout/layout.ts +537 -0
- package/src/editor/features/link/LinkPopover.tsx +114 -0
- package/src/editor/features/link/link.ts +112 -0
- package/src/editor/features/link/linkTool.tsx +36 -0
- package/src/editor/features/search/SearchPanel.tsx +264 -0
- package/src/editor/features/search/revealMatch.ts +69 -0
- package/src/editor/features/search/searchMatch.ts +129 -0
- package/src/editor/features/search/searchPlugin.ts +254 -0
- package/src/editor/features/search/searchTool.ts +30 -0
- package/src/editor/features/table/TableInsertDialog.tsx +129 -0
- package/src/editor/features/table/TableMenuButton.tsx +503 -0
- package/src/editor/features/table/TableSizeGrid.tsx +265 -0
- package/src/editor/features/table/tableActions.ts +380 -0
- package/src/editor/features/table/tableCells.ts +63 -0
- package/src/editor/features/table/tableChunk.ts +11 -0
- package/src/editor/features/table/tableTool.ts +74 -0
- package/src/editor/features/table/tables.ts +220 -0
- package/src/editor/features/wrapper/wrapper.ts +350 -0
- package/src/editor/features/wrapper/wrapperTones.ts +51 -0
- package/src/editor/highlight-entry.ts +23 -0
- package/src/editor/highlight-grammars.d.ts +12 -0
- package/src/editor/hooks/useChangeThrottle.ts +62 -0
- package/src/editor/hooks/useCoarsePointer.ts +36 -0
- package/src/editor/hooks/useFieldsetDisabled.ts +53 -0
- package/src/editor/hooks/useRichTextEditorState.ts +51 -0
- package/src/editor/hooks/useSubmenuPlacement.ts +40 -0
- package/src/editor/index.ts +59 -0
- package/src/editor/schema-entry.ts +40 -0
- package/src/editor/styles/codeTheme.ts +66 -0
- package/src/editor/styles/glass.ts +66 -0
- package/src/editor/styles/palette.ts +191 -0
- package/src/editor/styles/prose.ts +429 -0
- package/src/editor/styles/surface.ts +24 -0
- package/src/editor/styles/tokens.ts +173 -0
- package/src/editor/ui/BlockHandle.tsx +601 -0
- package/src/editor/ui/BlockIsland.tsx +23 -0
- package/src/editor/ui/BlockIslandSlots.tsx +114 -0
- package/src/editor/ui/ColorMenus.tsx +613 -0
- package/src/editor/ui/EditorToolbar.tsx +630 -0
- package/src/editor/ui/FieldResizer.tsx +155 -0
- package/src/editor/ui/FieldStatus.tsx +85 -0
- package/src/editor/ui/FloatingToolbar.tsx +77 -0
- package/src/editor/ui/FormatMenus.tsx +706 -0
- package/src/editor/ui/InsertMenuButton.tsx +104 -0
- package/src/editor/ui/SelectionBubble.tsx +317 -0
- package/src/editor/ui/ShortcutsButton.tsx +128 -0
- package/src/editor/ui/SlashMenu.tsx +199 -0
- package/src/editor/ui/SuggestionList.tsx +217 -0
- package/src/editor/ui/TextCard.tsx +312 -0
- package/src/editor/ui/ToolButtonView.tsx +242 -0
- package/src/editor/ui/TriggerMenu.tsx +255 -0
- package/src/editor/ui/focusWithin.ts +26 -0
- package/src/editor/ui/lockableMenu.ts +37 -0
- package/src/editor/ui/rowMarks.ts +66 -0
- package/src/editor/ui/selectionMenu.ts +97 -0
- package/src/hooks/useFieldDescription.ts +126 -0
- package/src/hooks/useMediaQuery.ts +46 -0
- package/src/hooks/useOpenerFocus.ts +118 -0
- package/src/hooks/useOverlayLayer.ts +42 -0
- package/src/hooks/useScrollLock.ts +92 -0
- package/src/hooks/useStickyOffset.ts +228 -0
- package/src/hooks/useTableState.ts +76 -0
- package/src/i18n/UiProvider.tsx +152 -0
- package/src/i18n/context.ts +30 -0
- package/src/i18n/defaults.ts +657 -0
- package/src/i18n/messages.ts +1183 -0
- package/src/i18n/useMessages.ts +47 -0
- package/src/icons.ts +566 -0
- package/src/index.ts +502 -0
- package/src/lib/accessible-name.ts +35 -0
- package/src/lib/bottom-bar-slot.ts +27 -0
- package/src/lib/button.ts +158 -0
- package/src/lib/choice-card.ts +79 -0
- package/src/lib/clamp.ts +18 -0
- package/src/lib/cn.ts +48 -0
- package/src/lib/date.ts +87 -0
- package/src/lib/dev-warn.ts +82 -0
- package/src/lib/empty.ts +43 -0
- package/src/lib/field.ts +125 -0
- package/src/lib/filter-range.ts +48 -0
- package/src/lib/interaction-modality.ts +134 -0
- package/src/lib/mask.ts +226 -0
- package/src/lib/menu.ts +196 -0
- package/src/lib/overlay-layer.ts +163 -0
- package/src/lib/period.ts +167 -0
- package/src/lib/progress-status.ts +44 -0
- package/src/lib/published-height.ts +147 -0
- package/src/lib/reorder.ts +65 -0
- package/src/lib/responsive.ts +71 -0
- package/src/lib/state.ts +39 -0
- package/src/lib/table-state.ts +264 -0
- package/src/lib/tag.ts +31 -0
- package/src/lib/themes.ts +144 -0
- package/src/lib/time.ts +107 -0
- package/src/lib/toolbar-axis.tsx +31 -0
- package/src/lib/touch.ts +15 -0
- package/src/lib/variants.ts +342 -0
- package/src/locales/en.ts +10 -0
- package/src/locales/ru.ts +695 -0
- package/styles.css +1650 -0
|
@@ -0,0 +1,1747 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// Происхождение: minimal-tiptap, `minimal-tiptap.tsx` и `hooks/use-minimal-tiptap.ts`
|
|
4
|
+
// (MIT, © 2024 Aslam, https://github.com/Aslam97/minimal-tiptap). Оставлены
|
|
5
|
+
// обёртка над `useEditor` и `EditorContent`, рамка поля и плейсхолдер; Панель —
|
|
6
|
+
// в `EditorToolbar.tsx`. Лицензия — NOTICE в корне пакета.
|
|
7
|
+
|
|
8
|
+
import { createDocument } from "@tiptap/core";
|
|
9
|
+
import { closeHistory } from "@tiptap/pm/history";
|
|
10
|
+
import { EditorContent, useEditor, type Editor } from "@tiptap/react";
|
|
11
|
+
import {
|
|
12
|
+
forwardRef,
|
|
13
|
+
lazy,
|
|
14
|
+
Suspense,
|
|
15
|
+
useEffect,
|
|
16
|
+
useId,
|
|
17
|
+
useImperativeHandle,
|
|
18
|
+
useLayoutEffect,
|
|
19
|
+
useMemo,
|
|
20
|
+
useRef,
|
|
21
|
+
useState,
|
|
22
|
+
useSyncExternalStore,
|
|
23
|
+
type CSSProperties,
|
|
24
|
+
type ReactNode,
|
|
25
|
+
} from "react";
|
|
26
|
+
import { useDescribedBy, useFieldInvalid, useFieldLabelId } from "../hooks/useFieldDescription.js";
|
|
27
|
+
import { useMessages } from "../i18n/useMessages.js";
|
|
28
|
+
import { cn } from "../lib/cn.js";
|
|
29
|
+
import { FIELD_SHELL_CLASS } from "../lib/field.js";
|
|
30
|
+
import { BlockHandle } from "./ui/BlockHandle.js";
|
|
31
|
+
import { expandTools } from "./features/builtins.js";
|
|
32
|
+
import {
|
|
33
|
+
createHandleMethods,
|
|
34
|
+
notifyHandleEditor,
|
|
35
|
+
type RichTextEditorHandleMethods,
|
|
36
|
+
} from "./core/handle.js";
|
|
37
|
+
import { EditorToolbar, ToolbarSkeleton } from "./ui/EditorToolbar.js";
|
|
38
|
+
import { searchState } from "./features/search/searchPlugin.js";
|
|
39
|
+
import { isDocumentEmpty } from "./core/emptiness.js";
|
|
40
|
+
import { FieldNoticeView, StatusLine } from "./ui/FieldStatus.js";
|
|
41
|
+
import type { FieldNotice } from "./core/fieldNotice.js";
|
|
42
|
+
import { FLOATING_TOOLBAR_KEY, FloatingToolbar } from "./ui/FloatingToolbar.js";
|
|
43
|
+
import { createEditorExtensions } from "./core/extensions.js";
|
|
44
|
+
import type { ToolEntry } from "./core/customTool.js";
|
|
45
|
+
import { customToolsError, FALLBACK_EXTENSIONS } from "./core/customToolEngine.js";
|
|
46
|
+
import { startLoad, type ToolLoad } from "./core/toolLoader.js";
|
|
47
|
+
import { skeletonHtml } from "./core/skeleton.js";
|
|
48
|
+
import { Button } from "../components/actions/Button.js";
|
|
49
|
+
import { devError } from "../lib/dev-warn.js";
|
|
50
|
+
import { describeImageNotice } from "./features/image/imageNotice.js";
|
|
51
|
+
import { insertItemsFor } from "./core/insertItems.js";
|
|
52
|
+
import type { CustomColorKind } from "./features/color/customColor.js";
|
|
53
|
+
import { isImageSelection } from "./features/image/image.js";
|
|
54
|
+
import { ImagePopover } from "./features/image/ImagePopover.js";
|
|
55
|
+
import { ImageToolbar } from "./features/image/ImageToolbar.js";
|
|
56
|
+
import { textCardsOf, triggersOf } from "./core/toolDescriptor.js";
|
|
57
|
+
import type { ToolPopoverRequest } from "./core/toolButtons.js";
|
|
58
|
+
import type { TextCardControl } from "./ui/TextCard.js";
|
|
59
|
+
import { SelectionPopover } from "./ui/ToolButtonView.js";
|
|
60
|
+
import { tableChunk } from "./features/table/tableTool.js";
|
|
61
|
+
import { replaceWithMarkdown } from "./core/markdown.js";
|
|
62
|
+
import {
|
|
63
|
+
documentFromJSON,
|
|
64
|
+
documentToJSON,
|
|
65
|
+
replaceWithJSON,
|
|
66
|
+
type RichTextDocument,
|
|
67
|
+
} from "./core/jsonDocument.js";
|
|
68
|
+
import { markdownOf } from "./core/atomText.js";
|
|
69
|
+
import { countCharacters, EXTERNAL_CHANGE } from "./core/maxLength.js";
|
|
70
|
+
import { proseClass } from "./styles/prose.js";
|
|
71
|
+
import { SELECTION_BUBBLE_KEY, SelectionBubble } from "./ui/SelectionBubble.js";
|
|
72
|
+
import { useSlashMenu } from "./ui/SlashMenu.js";
|
|
73
|
+
import { useTriggerMenu } from "./ui/TriggerMenu.js";
|
|
74
|
+
import { FIELD_MIN_HEIGHT, FieldResizer } from "./ui/FieldResizer.js";
|
|
75
|
+
import { formatSourceHtml } from "./core/sourceFormat.js";
|
|
76
|
+
import { surfaceAttributes, type RichTextSurface } from "./styles/surface.js";
|
|
77
|
+
import { EDITOR_PAPER_TOKENS_CLASS, EDITOR_TOKENS_CLASS } from "./styles/tokens.js";
|
|
78
|
+
import type { RichTextEditorPreset } from "./core/tools.js";
|
|
79
|
+
import { useChangeThrottle } from "./hooks/useChangeThrottle.js";
|
|
80
|
+
import { useCoarsePointer } from "./hooks/useCoarsePointer.js";
|
|
81
|
+
import { useFieldsetDisabled } from "./hooks/useFieldsetDisabled.js";
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Поповер произвольного цвета грузится при первом «Свой цвет…»: он тянет
|
|
85
|
+
* `ColorPicker` и цветовую подсистему `react-aria-components` (61 кБ gzip,
|
|
86
|
+
* ADR-0038), а нужен немногим. Статический импорт поднял бы вход
|
|
87
|
+
* `@olddevs/ui/editor` вдвое для всех.
|
|
88
|
+
*/
|
|
89
|
+
const CustomColorPopover = lazy(() =>
|
|
90
|
+
import("./features/color/CustomColorPopover.js").then((module) => ({
|
|
91
|
+
default: module.CustomColorPopover,
|
|
92
|
+
}))
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Карточка у текста грузится, когда у набора `tools` есть хотя бы одна
|
|
97
|
+
* Карточка: рамка, пересчёт диапазонов и живой регион нужны только тому,
|
|
98
|
+
* кто описал Карточку, а статический импорт лёг бы на всех потребителей.
|
|
99
|
+
*/
|
|
100
|
+
const TextCard = lazy(() =>
|
|
101
|
+
import("./ui/TextCard.js").then((module) => ({ default: module.TextCard }))
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Панель «Поиск и замена» грузится при первом открытии: поля,
|
|
106
|
+
* флажки и переключатель нужны только тому, кто ищет, а `search` есть и в
|
|
107
|
+
* `basic`, который меряется бюджетом «старта». Плагин подсветки и сочетания
|
|
108
|
+
* маленькие и стоят в движке сразу.
|
|
109
|
+
*/
|
|
110
|
+
const SearchPanel = lazy(() =>
|
|
111
|
+
import("./features/search/SearchPanel.js").then((module) => ({ default: module.SearchPanel }))
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
/** Место панели поиска: под правым краем Панели, на телефоне — во всю ширину поля. */
|
|
115
|
+
const SEARCH_PANEL_PLACE_CLASS = "absolute top-full right-2 left-2 z-[2] mt-2 sm:left-auto sm:w-80";
|
|
116
|
+
/** Место панели поиска без фиксированной Панели — верхний угол поля. */
|
|
117
|
+
const SEARCH_PANEL_CORNER_CLASS = "absolute top-2 right-2 left-2 sm:left-auto sm:w-80";
|
|
118
|
+
|
|
119
|
+
export interface RichTextEditorProps {
|
|
120
|
+
/**
|
|
121
|
+
* Документ — HTML-строка, ограниченная Схемой. Пустой документ — `""`.
|
|
122
|
+
*
|
|
123
|
+
* Всё, чего нет в Схеме (теги, атрибуты, `style`, обработчики, `javascript:`),
|
|
124
|
+
* отбрасывается при загрузке. Единственный `style`, который Схема знает, —
|
|
125
|
+
* цвет автора в строгой форме `color:#rrggbb` на `span` и
|
|
126
|
+
* `background-color:#rrggbb` на `mark` (`customColor.ts`). Это НЕ санитизация: HTML от пользователя
|
|
127
|
+
* чистит сервер потребителя, клиентская очистка от XSS не защищает.
|
|
128
|
+
*/
|
|
129
|
+
value?: string;
|
|
130
|
+
/**
|
|
131
|
+
* Начальный документ неуправляемого режима: HTML-строка или JSON-конверт
|
|
132
|
+
* (`getJSON()`). Конверт проходит Схему, как `setJSON()`;
|
|
133
|
+
* отвергнутый — пустой документ и ошибка в консоли разработки. До Готовности
|
|
134
|
+
* Скелет при конверте — рамка без Документа: HTML конверта знает только движок.
|
|
135
|
+
* `onChange` и скрытое поле формы получают HTML, как всегда.
|
|
136
|
+
*/
|
|
137
|
+
defaultValue?: string | RichTextDocument;
|
|
138
|
+
/**
|
|
139
|
+
* Новый HTML — не чаще раза в `changeDelay` мс, а также сразу на `blur`,
|
|
140
|
+
* перед отправкой формы и на применение правки HTML-режима. Замена документа
|
|
141
|
+
* новым `value` сюда не приходит.
|
|
142
|
+
*/
|
|
143
|
+
onChange?: (html: string) => void;
|
|
144
|
+
/**
|
|
145
|
+
* Редактор готов: движок создан, методы Хэндла (`ref`) уже действуют — например,
|
|
146
|
+
* вставить шаблон. Без аргументов, один раз за монтаж, в том числе при
|
|
147
|
+
* `readOnly` и `disabled`; перерисовка и смена колбэка повторного вызова не
|
|
148
|
+
* дают. Ждёт загрузчики Частей для движка своих Инструментов. Серверный
|
|
149
|
+
* рендер, ошибка набора `tools` и упавший загрузчик (движка нет) его не вызывают.
|
|
150
|
+
*/
|
|
151
|
+
onReady?: () => void;
|
|
152
|
+
/**
|
|
153
|
+
* Фокус вошёл в поле. Поле — целиком: Документ, Панель, поповеры кита и поле
|
|
154
|
+
* HTML; переход между ними фокус поля не теряет и `onFocus` не повторяет.
|
|
155
|
+
* Без аргументов: DOM-событие не пробрасывается.
|
|
156
|
+
*/
|
|
157
|
+
onFocus?: () => void;
|
|
158
|
+
/**
|
|
159
|
+
* Фокус ушёл из поля (см. `onFocus`). Перед вызовом отложенный `onChange`
|
|
160
|
+
* выталкивается, поэтому автосохранение по `onBlur` получает свежий HTML.
|
|
161
|
+
* Вызов отложен на такт: за это время фокус может вернуться в поле — из
|
|
162
|
+
* Документа в Панель или поповер и обратно `onBlur` не даёт.
|
|
163
|
+
*/
|
|
164
|
+
onBlur?: () => void;
|
|
165
|
+
/**
|
|
166
|
+
* Задержка `onChange`, мс. По умолчанию 300.
|
|
167
|
+
*
|
|
168
|
+
* Сериализация в HTML — проход по всему документу, и на документе в десятки
|
|
169
|
+
* тысяч символов она на каждую букву тормозила бы ввод. `0` — отдавать каждую
|
|
170
|
+
* правку сразу.
|
|
171
|
+
*/
|
|
172
|
+
changeDelay?: number;
|
|
173
|
+
/** Имя поля формы: рендерит `<input type="hidden">` с текущим HTML. */
|
|
174
|
+
name?: string;
|
|
175
|
+
/**
|
|
176
|
+
* `id` редактируемой области — для внешних ссылок и тестов. Имя от подписи
|
|
177
|
+
* `FormField` от него не зависит: оно приходит контекстом.
|
|
178
|
+
*/
|
|
179
|
+
id?: string;
|
|
180
|
+
/** Плейсхолдер пустого документа; по умолчанию — из каталога. */
|
|
181
|
+
placeholder?: string;
|
|
182
|
+
/**
|
|
183
|
+
* Предел символов. Счётчик остатка появляется у 80 % предела, ввод сверх
|
|
184
|
+
* него блокируется, вставка обрезается до предела. Длинный `value` грузится
|
|
185
|
+
* целиком: его можно сокращать, но не удлинять.
|
|
186
|
+
*/
|
|
187
|
+
maxLength?: number;
|
|
188
|
+
/** Только чтение: текст выделяется и уходит в форму, но не правится. */
|
|
189
|
+
readOnly?: boolean;
|
|
190
|
+
/** Выключено, как у прочих полей: не правится, приглушено, не уходит в форму. */
|
|
191
|
+
disabled?: boolean;
|
|
192
|
+
/**
|
|
193
|
+
* Обязательное поле: `aria-required`, а в обычной `<form>` ещё и блокировка
|
|
194
|
+
* отправки, пока Документ пуст (нет ни текста, ни Атома, ни таблицы).
|
|
195
|
+
* Браузер покажет сообщение из каталога (`editor.required`) и вернёт фокус
|
|
196
|
+
* в Редактор. `readOnly` и `disabled` не проверяются — как у нативных полей.
|
|
197
|
+
* В `Form` из кита (`noValidate`) браузерной проверки нет — ошибку показывает
|
|
198
|
+
* потребитель.
|
|
199
|
+
*/
|
|
200
|
+
required?: boolean;
|
|
201
|
+
/** Имя поля, когда подписи `FormField` нет. */
|
|
202
|
+
"aria-label"?: string;
|
|
203
|
+
/** Имя поля ссылкой на уже нарисованную подпись. Сильнее `aria-label`. */
|
|
204
|
+
"aria-labelledby"?: string;
|
|
205
|
+
/** Своё описание. Сливается с подсказкой и ошибкой `FormField`. */
|
|
206
|
+
"aria-describedby"?: string;
|
|
207
|
+
/** Невалидность. Без пропа берётся у `FormField` с `error`. */
|
|
208
|
+
"aria-invalid"?: boolean;
|
|
209
|
+
/**
|
|
210
|
+
* Панель форматирования. `"fixed"` (по умолчанию) — над полем, липнет при
|
|
211
|
+
* прокрутке под шапкой приложения (`--topbar-h`, ADR-0016); `"floating"` —
|
|
212
|
+
* над непустым выделением, а на сенсорном экране (`pointer: coarse`) —
|
|
213
|
+
* фиксированная: системное меню выделения iOS и Android она не перекрывает;
|
|
214
|
+
* `"bubble"` — Меню выделения вместо Панели: компактная плашка на инверсной
|
|
215
|
+
* поверхности над непустым выделением («¶», жирный, курсив, зачёркнутый,
|
|
216
|
+
* «…», ссылка, эмодзи), на сенсорном экране — так же фиксированная Панель;
|
|
217
|
+
* `"none"` — без Панели: форматирование остаётся за клавиатурой. В режиме
|
|
218
|
+
* `readOnly` Панели нет в любом случае. `Alt+F10` из Документа переводит
|
|
219
|
+
* фокус в Панель или Меню выделения.
|
|
220
|
+
*/
|
|
221
|
+
toolbar?: "fixed" | "floating" | "bubble" | "none";
|
|
222
|
+
/**
|
|
223
|
+
* Меню выделения поверх фиксированной Панели. По умолчанию `true`: при
|
|
224
|
+
* `toolbar="fixed"` над непустым выделением появляется то же Меню
|
|
225
|
+
* выделения, что в режиме `"bubble"` (решение владельца: Панель
|
|
226
|
+
* сверху — для всего, Меню выделения — чтобы не уводить мышь от текста).
|
|
227
|
+
* `false` оставляет одну Панель. Остальные режимы проп не меняет: у
|
|
228
|
+
* `"bubble"` Меню выделения и так есть, у `"floating"` над выделением уже
|
|
229
|
+
* стоит Панель. На сенсорном экране Меню выделения кита нет — системное
|
|
230
|
+
* меню выделения iOS и Android занимает то же место.
|
|
231
|
+
*/
|
|
232
|
+
selectionMenu?: boolean;
|
|
233
|
+
/**
|
|
234
|
+
* Пресет — готовый набор встроенных Инструментов: `"full"` (по умолчанию) —
|
|
235
|
+
* всё; `"basic"` — для комментариев: жирный, курсив, зачёркнутый, строчный
|
|
236
|
+
* код, ссылка, два вида списков, цитата, отмена и повтор. Игнорируется, если
|
|
237
|
+
* передан `tools`.
|
|
238
|
+
*/
|
|
239
|
+
preset?: RichTextEditorPreset;
|
|
240
|
+
/**
|
|
241
|
+
* Точный список Инструментов; сильнее `preset`. Выключенный Инструмент
|
|
242
|
+
* убирает и кнопку, и Блок или Метку из Схемы: их не получить ни сочетанием
|
|
243
|
+
* клавиш, ни markdown-шорткатом, ни вставкой.
|
|
244
|
+
*
|
|
245
|
+
* Вперемешку с именами кита — описания своих Инструментов (`CustomTool`):
|
|
246
|
+
* `[...RICH_TEXT_PRESETS.full, mergeTagTool]`. Неизвестное имя отбрасывается
|
|
247
|
+
* молча; описание с ошибкой (имя без Префикса потребителя, совпадение имён,
|
|
248
|
+
* Часть для движка мимо правил Схемы) — ошибка поля: движок не создаётся,
|
|
249
|
+
* значение формы остаётся входящим, причина — в консоли разработчика.
|
|
250
|
+
*
|
|
251
|
+
* `preset` и `tools` читаются при создании движка: Схема ProseMirror после
|
|
252
|
+
* этого не меняется. Чтобы сменить набор у живого поля, перемонтируйте его
|
|
253
|
+
* (`key`) — история правок при этом теряется.
|
|
254
|
+
*/
|
|
255
|
+
tools?: readonly ToolEntry[];
|
|
256
|
+
/**
|
|
257
|
+
* Загрузка картинки: получает файл, отдаёт абсолютный `http(s)`-адрес, по
|
|
258
|
+
* которому картинка будет жить, или отклоняет обещание.
|
|
259
|
+
*
|
|
260
|
+
* С ним картинку можно вставить из буфера, перетащить в поле и выбрать
|
|
261
|
+
* файлом в поповере картинки. Пока обещание не решено, на месте картинки
|
|
262
|
+
* плейсхолдер, а в Документе её нет; при отказе Документ не меняется, под
|
|
263
|
+
* полем — сообщение. Без него файлы не принимаются — только вставка по
|
|
264
|
+
* адресу. `data:` и `blob:` в Документ не пишутся никогда: адрес вне
|
|
265
|
+
* политики считается отказом. Читается в момент вставки — менять можно на
|
|
266
|
+
* лету.
|
|
267
|
+
*/
|
|
268
|
+
onUploadImage?: (file: File) => Promise<string>;
|
|
269
|
+
/**
|
|
270
|
+
* Поверхность Документа: `"theme"` (по умолчанию) — в теме приложения;
|
|
271
|
+
* `"paper"` — светлый Лист в любой теме, для писем, печати и PDF. Лист —
|
|
272
|
+
* только редактируемая область: Панель, поповеры, меню и рамка фокуса поля
|
|
273
|
+
* остаются в теме приложения.
|
|
274
|
+
*/
|
|
275
|
+
surface?: RichTextSurface;
|
|
276
|
+
/**
|
|
277
|
+
* Строка статуса: React-узел внутри рамки поля, в строке счётчика
|
|
278
|
+
* `maxLength` — своё содержимое у начала, счётчик кита в конце (число слов,
|
|
279
|
+
* «Сохранено», соавтор). Видна и при `readOnly`, и при `disabled`.
|
|
280
|
+
*
|
|
281
|
+
* Кит её не озвучивает: контейнер без `role`, и число слов не зачитывается на
|
|
282
|
+
* каждую правку. Чтобы «Сохранено» прозвучало, оберните его в
|
|
283
|
+
* `role="status"` сами. Данные берите из своего состояния: Строка статуса —
|
|
284
|
+
* пропс экрана, у Инструментов к ней доступа нет.
|
|
285
|
+
*/
|
|
286
|
+
status?: ReactNode;
|
|
287
|
+
/**
|
|
288
|
+
* Предел высоты области Документа (ADR-0059): число — пиксели, строка —
|
|
289
|
+
* любая CSS-длина (`"32rem"`, `"60vh"`). До предела поле растёт вместе с
|
|
290
|
+
* Документом, дальше Документ прокручивается внутри рамки; Панель над ним и
|
|
291
|
+
* Строка статуса под ним остаются на месте. Без пропа своей прокрутки у поля
|
|
292
|
+
* нет. Предела в строках, как `maxRows` у `TextControl`, здесь нет: у Блоков
|
|
293
|
+
* разная высота.
|
|
294
|
+
*/
|
|
295
|
+
maxHeight?: number | string;
|
|
296
|
+
/**
|
|
297
|
+
* Ручка высоты в углу области Документа: высоту тянут по вертикали. С
|
|
298
|
+
* `maxHeight` она задаёт стартовую высоту, а не предел — две системы,
|
|
299
|
+
* одновременно распоряжающиеся высотой, дают прыгающее поле (тот же довод у
|
|
300
|
+
* `autosize` в `TextControl`). Без `maxHeight` старт — высота Документа.
|
|
301
|
+
*/
|
|
302
|
+
resizable?: boolean;
|
|
303
|
+
/** Классы на корень: ширина, отступы снаружи. */
|
|
304
|
+
className?: string;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Императивный доступ к Редактору. Вставка, чтение текста, фокус с позицией и
|
|
309
|
+
* история — `RichTextEditorHandleMethods` (`handle.ts`).
|
|
310
|
+
*/
|
|
311
|
+
export interface RichTextEditorHandle extends RichTextEditorHandleMethods {
|
|
312
|
+
/**
|
|
313
|
+
* Текущий HTML — сейчас, без ожидания `changeDelay`. Пустой документ — `""`.
|
|
314
|
+
* В HTML-режиме сначала применяет правку поля HTML (через Схему, с
|
|
315
|
+
* `onChange`, если Документ изменился).
|
|
316
|
+
*/
|
|
317
|
+
getHTML(): string;
|
|
318
|
+
/** Очистить документ. Владелец значения узнаёт об этом через `onChange("")`. */
|
|
319
|
+
clear(): void;
|
|
320
|
+
/**
|
|
321
|
+
* Документ как Markdown — сейчас, без ожидания `changeDelay`. Пустой документ
|
|
322
|
+
* и вызов до монтажа (в серверном рендере движка нет) — `""`.
|
|
323
|
+
*
|
|
324
|
+
* Цвет, выравнивание, подчёркивание и размер картинки в Markdown не
|
|
325
|
+
* выражаются и при выгрузке теряются. В HTML-режиме — как `getHTML()`:
|
|
326
|
+
* сначала применяется правка поля HTML.
|
|
327
|
+
*/
|
|
328
|
+
getMarkdown(): string;
|
|
329
|
+
/**
|
|
330
|
+
* Заменить документ разобранным Markdown. Как `clear()`, это замена снаружи:
|
|
331
|
+
* владелец значения узнаёт о ней через `onChange` сразу, предел `maxLength`
|
|
332
|
+
* её не режет. Всё, чего нет в Схеме, отбрасывается. До монтажа — ничего.
|
|
333
|
+
*/
|
|
334
|
+
setMarkdown(markdown: string): void;
|
|
335
|
+
/**
|
|
336
|
+
* Документ как JSON-конверт — сейчас, без ожидания `changeDelay`.
|
|
337
|
+
* В отличие от Markdown, ничего не теряет. До монтажа и в серверном рендере —
|
|
338
|
+
* `null`. В HTML-режиме — как `getHTML()`: сначала применяется правка поля HTML.
|
|
339
|
+
*/
|
|
340
|
+
getJSON(): RichTextDocument | null;
|
|
341
|
+
/**
|
|
342
|
+
* Заменить документ JSON-конвертом. Параметр — `unknown`: главный источник —
|
|
343
|
+
* `JSON.parse` файла, и форму проверяет Редактор. `true` — заменён, `false` —
|
|
344
|
+
* конверт отвергнут (не тот формат или версия, кривое дерево) или движка ещё
|
|
345
|
+
* нет; тогда Документ не тронут. Замена — снаружи, как `setMarkdown()`:
|
|
346
|
+
* `onChange` сразу, `maxLength` её не режет, всё, чего нет в Схеме,
|
|
347
|
+
* отбрасывается по тем же правилам, что у HTML.
|
|
348
|
+
*/
|
|
349
|
+
setJSON(document: unknown): boolean;
|
|
350
|
+
/**
|
|
351
|
+
* Открыть панель «Поиск и замена» из кода экрана — то же, что
|
|
352
|
+
* кнопка «Поиск» и `Mod+F`; `replace` — фокус в поле замены. Без Инструмента
|
|
353
|
+
* `search`, в HTML-режиме и до монтажа — ничего.
|
|
354
|
+
*/
|
|
355
|
+
openSearch(options?: { replace?: boolean }): void;
|
|
356
|
+
/**
|
|
357
|
+
* Сырой движок Tiptap: честный выход для команд Меток, Блоков и своих
|
|
358
|
+
* Инструментов (`editor.chain().focus()…run()`). Его API следует мажору Tiptap,
|
|
359
|
+
* а не контракту кита. До монтажа и в серверном рендере — `null`.
|
|
360
|
+
*/
|
|
361
|
+
editor: Editor | null;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/** Пустой документ — пустая строка, а не `<p></p>`: так его видит форма. */
|
|
365
|
+
// Снимок «мы в браузере после гидратации» для `useSyncExternalStore`: не меняется.
|
|
366
|
+
const subscribeNever = () => () => {};
|
|
367
|
+
const isBrowser = () => true;
|
|
368
|
+
const isServer = () => false;
|
|
369
|
+
|
|
370
|
+
/** Длина `maxHeight`: число — пиксели, строка — CSS-длина как есть. */
|
|
371
|
+
const cssLength = (value: number | string) => (typeof value === "number" ? `${value}px` : value);
|
|
372
|
+
|
|
373
|
+
function serialize(editor: Editor): string {
|
|
374
|
+
return isDocumentEmpty(editor.state.doc) ? "" : editor.getHTML();
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/*
|
|
378
|
+
Плейсхолдер — псевдоэлементом на первом пустом абзаце; текст кладёт
|
|
379
|
+
расширение в `data-placeholder`. Скринридеру он объявлен `aria-placeholder`
|
|
380
|
+
на самом поле: содержимое `::before` читается не везде.
|
|
381
|
+
*/
|
|
382
|
+
const PLACEHOLDER_CLASS =
|
|
383
|
+
"[&_p.is-editor-empty:first-child]:before:pointer-events-none " +
|
|
384
|
+
"[&_p.is-editor-empty:first-child]:before:float-left " +
|
|
385
|
+
"[&_p.is-editor-empty:first-child]:before:h-0 " +
|
|
386
|
+
"[&_p.is-editor-empty:first-child]:before:text-(--rte-muted-foreground) " +
|
|
387
|
+
"[&_p.is-editor-empty:first-child]:before:content-[attr(data-placeholder)]";
|
|
388
|
+
|
|
389
|
+
/*
|
|
390
|
+
Картинка в правке — то, чего нет в сохранённом HTML и `RichTextView`:
|
|
391
|
+
контур выделенной картинки, ручки ширины у неё (только в редактируемом
|
|
392
|
+
поле), подсказка пустой подписи и пустая подпись, спрятанная в поле только
|
|
393
|
+
для чтения. Классы `rte-caption-empty` и `rte-resize-handle` ставит
|
|
394
|
+
`image.ts` — декорацией и в представлении узла, в Документ они не уходят.
|
|
395
|
+
*/
|
|
396
|
+
const IMAGE_EDITING_CLASS =
|
|
397
|
+
"[&_figure.ProseMirror-selectednode_img]:outline-2 " +
|
|
398
|
+
"[&_figure.ProseMirror-selectednode_img]:outline-offset-2 " +
|
|
399
|
+
"[&_figure.ProseMirror-selectednode_img]:outline-(--rte-primary) " +
|
|
400
|
+
"[&[contenteditable=true]_figure.ProseMirror-selectednode_.rte-resize-handle]:block " +
|
|
401
|
+
"[&_figcaption.rte-caption-empty]:before:pointer-events-none " +
|
|
402
|
+
"[&_figcaption.rte-caption-empty]:before:float-left " +
|
|
403
|
+
"[&_figcaption.rte-caption-empty]:before:h-0 " +
|
|
404
|
+
"[&_figcaption.rte-caption-empty]:before:w-full " +
|
|
405
|
+
"[&_figcaption.rte-caption-empty]:before:text-(--rte-muted-foreground) " +
|
|
406
|
+
"[&_figcaption.rte-caption-empty]:before:content-[attr(data-placeholder)] " +
|
|
407
|
+
"[&[contenteditable=false]_figcaption.rte-caption-empty]:hidden";
|
|
408
|
+
|
|
409
|
+
/*
|
|
410
|
+
Подсветка совпадений поиска: классы ставит плагин поиска
|
|
411
|
+
декорацией, в Документ они не уходят. Все совпадения — мягкой заливкой
|
|
412
|
+
тона `warning`, как маркер текстовыделителя, текущее — плотнее и с рамкой
|
|
413
|
+
того же тона: его видно и среди соседних, и на жёлтом маркере. Текст не
|
|
414
|
+
перекрашивается: заливка полупрозрачная, и цвет Метки под ней читается.
|
|
415
|
+
*/
|
|
416
|
+
const SEARCH_HIGHLIGHT_CLASS =
|
|
417
|
+
"[&_.rte-search-match]:rounded-[2px] " +
|
|
418
|
+
"[&_.rte-search-match]:bg-[color-mix(in_srgb,var(--warning)_30%,transparent)] " +
|
|
419
|
+
"[&_.rte-search-current]:bg-[color-mix(in_srgb,var(--warning)_60%,transparent)] " +
|
|
420
|
+
"[&_.rte-search-current]:shadow-[0_0_0_1px_var(--warning)]";
|
|
421
|
+
|
|
422
|
+
// Рамка фиксированной Панели — у неё и у её Скелета (почему такая — у разметки ниже).
|
|
423
|
+
const TOOLBAR_SHELL_CLASS =
|
|
424
|
+
"bg-bg-2 border-line-soft rounded-t-control sticky top-[var(--topbar-h,0px)] z-[1] " +
|
|
425
|
+
"-mx-3 border-b px-1.5 py-1";
|
|
426
|
+
|
|
427
|
+
/*
|
|
428
|
+
Поле HTML-режима и его зеркало — одна типографика: высоту поля задаёт
|
|
429
|
+
невидимый близнец в той же ячейке грида, как у `TextControl` с ростом
|
|
430
|
+
(там же — почему не `scrollHeight`). Поверхность всегда тёмная, цветом кита
|
|
431
|
+
(`--rte-source-*` в `styles.css`): в тёмных темах — подложка темы, в светлой
|
|
432
|
+
и на листе — значения тёмной темы. Скругление — как у кода, шрифт —
|
|
433
|
+
моноширинный 13 px, как у `CodeView`. Режим читается как «код», а не как ещё
|
|
434
|
+
одно текстовое поле.
|
|
435
|
+
*/
|
|
436
|
+
const SOURCE_BOX_CLASS =
|
|
437
|
+
"col-start-1 row-start-1 w-full rounded-(--rte-radius) border px-3 py-2 " +
|
|
438
|
+
"font-mono text-[13px] leading-5 break-words whitespace-pre-wrap";
|
|
439
|
+
const SOURCE_FIELD_CLASS =
|
|
440
|
+
"border-(--rte-source-border) bg-(--rte-source-background) text-(--rte-source-foreground) " +
|
|
441
|
+
"caret-(--rte-source-foreground) " +
|
|
442
|
+
// Выделение — тоже тёмной темы: глобальный `::selection` в
|
|
443
|
+
// светлой теме — светлая заливка с тёмным текстом, на тёмном поле нечитаемо.
|
|
444
|
+
"selection:bg-(--rte-source-selection) selection:text-(--rte-source-foreground) " +
|
|
445
|
+
"resize-y outline-none disabled:cursor-not-allowed";
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Поле форматированного текста на Tiptap v3 — отдельный вход
|
|
449
|
+
* `@olddevs/ui/editor` (ADR-0050).
|
|
450
|
+
*
|
|
451
|
+
* ЗНАЧЕНИЕ И КУРСОР. Последний HTML, о котором знает владелец значения,
|
|
452
|
+
* хранится рядом с движком. Входящий `value`, равный ему, — эхо нашей же
|
|
453
|
+
* правки: документ не пересоздаётся, курсор остаётся на месте. Иначе
|
|
454
|
+
* управляемый режим сбрасывал бы курсор в начало на каждой букве.
|
|
455
|
+
*
|
|
456
|
+
* ФОРМА. Скрытое поле и `onChange` получают HTML по одному и тому же таймеру;
|
|
457
|
+
* отправка формы и `new FormData(form)` сбрасывают его досрочно, поэтому в
|
|
458
|
+
* отправке значение свежее даже посреди задержки.
|
|
459
|
+
*
|
|
460
|
+
* SSR И СКЕЛЕТ. Движок создаётся только в браузере (`immediatelyRender:
|
|
461
|
+
* false`) и после загрузчиков Инструментов: до того — на сервере, после
|
|
462
|
+
* гидратации, при сбое загрузчика — рисуется Скелет: рамка, место Панели и
|
|
463
|
+
* Документ статичным HTML с классом Документа, без ввода и без прыжка высоты.
|
|
464
|
+
* Документ Скелета — `value`, очищенный Схемой (`skeleton.ts`), и только в
|
|
465
|
+
* браузере после монтирования: на сервере Скелет — рамка и место Панели.
|
|
466
|
+
*/
|
|
467
|
+
export const RichTextEditor = forwardRef<RichTextEditorHandle, RichTextEditorProps>(
|
|
468
|
+
function RichTextEditor(
|
|
469
|
+
{
|
|
470
|
+
value,
|
|
471
|
+
defaultValue,
|
|
472
|
+
onChange,
|
|
473
|
+
onReady,
|
|
474
|
+
onFocus,
|
|
475
|
+
onBlur,
|
|
476
|
+
changeDelay = 300,
|
|
477
|
+
name,
|
|
478
|
+
id,
|
|
479
|
+
placeholder,
|
|
480
|
+
maxLength,
|
|
481
|
+
readOnly = false,
|
|
482
|
+
disabled: disabledProp = false,
|
|
483
|
+
required = false,
|
|
484
|
+
"aria-label": ariaLabel,
|
|
485
|
+
"aria-labelledby": ariaLabelledBy,
|
|
486
|
+
"aria-describedby": ariaDescribedBy,
|
|
487
|
+
"aria-invalid": ariaInvalid,
|
|
488
|
+
toolbar = "fixed",
|
|
489
|
+
selectionMenu = true,
|
|
490
|
+
preset = "full",
|
|
491
|
+
tools,
|
|
492
|
+
onUploadImage,
|
|
493
|
+
status,
|
|
494
|
+
surface = "theme",
|
|
495
|
+
maxHeight,
|
|
496
|
+
resizable = false,
|
|
497
|
+
className,
|
|
498
|
+
},
|
|
499
|
+
ref
|
|
500
|
+
) {
|
|
501
|
+
const messages = useMessages();
|
|
502
|
+
/*
|
|
503
|
+
Набор инструментов замораживается при монтаже: из него собрана Схема, а
|
|
504
|
+
Схему у живого движка не поменять. Панель читает тот же замороженный
|
|
505
|
+
набор — иначе новый `tools` показал бы кнопку, которой Схема не знает.
|
|
506
|
+
Набор — список описаний Инструментов (`features/builtins.ts`), реестры
|
|
507
|
+
читают его проекцию.
|
|
508
|
+
*/
|
|
509
|
+
const [enabledTools] = useState(() => expandTools(preset, tools));
|
|
510
|
+
/*
|
|
511
|
+
Загрузчики Частей для движка (ADR-0058, п. 11.3–11.6). Загрузка стартует
|
|
512
|
+
в рендере, а не в эффекте: с первого рендера в браузере, ещё до монтажа;
|
|
513
|
+
на сервере — никогда. Промис кэширован на загрузчике (`toolLoader.ts`):
|
|
514
|
+
повторный рендер и второй Редактор его не зовут. Набор движка собирается,
|
|
515
|
+
только когда отработали все (`ready`): Схема фиксируется при создании, и
|
|
516
|
+
Блоки из `value` без Части для движка потерялись бы при разборе.
|
|
517
|
+
*/
|
|
518
|
+
const loaders = enabledTools.descriptors.flatMap((descriptor) => descriptor.load ?? []);
|
|
519
|
+
const loads = loaders.map((loader) =>
|
|
520
|
+
typeof window === "undefined" ? ({} as ToolLoad) : startLoad(loader)
|
|
521
|
+
);
|
|
522
|
+
const loading = loads.some((load) => !load.done && !load.failed);
|
|
523
|
+
const ready = loads.every((load) => load.done);
|
|
524
|
+
const [, setLoadRound] = useState(0);
|
|
525
|
+
useEffect(() => {
|
|
526
|
+
if (!loading) return;
|
|
527
|
+
let live = true;
|
|
528
|
+
void Promise.all(loads.map((load) => load.promise)).then(
|
|
529
|
+
() => live && setLoadRound((round) => round + 1)
|
|
530
|
+
);
|
|
531
|
+
return () => void (live = false);
|
|
532
|
+
}, [loading]);
|
|
533
|
+
// «Повторить» зовёт заново только упавшие загрузчики: удачные — в кэше.
|
|
534
|
+
// Сбой виден после первого эффекта (`engine` ниже): строка, которой не было
|
|
535
|
+
// на сервере, сломала бы гидратацию.
|
|
536
|
+
const retryLoads = () => {
|
|
537
|
+
for (const loader of loaders) startLoad(loader, true);
|
|
538
|
+
setLoadRound((round) => round + 1);
|
|
539
|
+
};
|
|
540
|
+
const editorRef = useRef<Editor | null>(null);
|
|
541
|
+
const rootRef = useRef<HTMLDivElement>(null);
|
|
542
|
+
// Выключенный `<fieldset>` выключает и редактор, как нативное поле: так
|
|
543
|
+
// же ведёт себя `Form pending`, а чужой `fieldset` покрывается тем же
|
|
544
|
+
// правилом.
|
|
545
|
+
const inDisabledFieldset = useFieldsetDisabled(rootRef);
|
|
546
|
+
const disabled = disabledProp || inDisabledFieldset;
|
|
547
|
+
const hiddenRef = useRef<HTMLInputElement>(null);
|
|
548
|
+
const proxyRef = useRef<HTMLInputElement>(null);
|
|
549
|
+
/*
|
|
550
|
+
Начальный конверт: HTML из него собирает только движок по своей Схеме,
|
|
551
|
+
поэтому до него значение — пустая строка, а Документ встаёт при появлении
|
|
552
|
+
движка (эффект ниже). `value` главнее, как и HTML-строки в `defaultValue`.
|
|
553
|
+
*/
|
|
554
|
+
const initialDocument =
|
|
555
|
+
value === undefined && typeof defaultValue === "object" ? defaultValue : undefined;
|
|
556
|
+
const initialDocumentRef = useRef(initialDocument);
|
|
557
|
+
initialDocumentRef.current = initialDocument;
|
|
558
|
+
const initial = value ?? (typeof defaultValue === "string" ? defaultValue : "");
|
|
559
|
+
/*
|
|
560
|
+
Последний HTML, о котором владелец значения знает: отданный в `onChange`
|
|
561
|
+
или полученный в `value`. Входящий `value`, равный ему, — эхо нашей же
|
|
562
|
+
правки, и пересоздавать по нему документ нельзя.
|
|
563
|
+
*/
|
|
564
|
+
const knownRef = useRef(initial);
|
|
565
|
+
const onChangeRef = useRef(onChange);
|
|
566
|
+
onChangeRef.current = onChange;
|
|
567
|
+
// Колбэки событий — тоже через ref: они читаются позже рендера (эффект
|
|
568
|
+
// готовности, таймер ухода фокуса), а новый колбэк события не повторяет.
|
|
569
|
+
const onReadyRef = useRef(onReady);
|
|
570
|
+
onReadyRef.current = onReady;
|
|
571
|
+
const onFocusRef = useRef(onFocus);
|
|
572
|
+
onFocusRef.current = onFocus;
|
|
573
|
+
const onBlurRef = useRef(onBlur);
|
|
574
|
+
onBlurRef.current = onBlur;
|
|
575
|
+
/*
|
|
576
|
+
Предел и плейсхолдер расширения читают через ref: набор расширений живёт
|
|
577
|
+
столько же, сколько движок, а пересоздавать движок ради нового числа или
|
|
578
|
+
смены локали значило бы терять историю правок и курсор.
|
|
579
|
+
*/
|
|
580
|
+
const limitRef = useRef(maxLength);
|
|
581
|
+
limitRef.current = maxLength;
|
|
582
|
+
const placeholderText = placeholder ?? messages.editor.placeholder;
|
|
583
|
+
const placeholderRef = useRef(placeholderText);
|
|
584
|
+
placeholderRef.current = placeholderText;
|
|
585
|
+
const taskCheckboxRef = useRef(messages.editor.taskCheckbox);
|
|
586
|
+
taskCheckboxRef.current = messages.editor.taskCheckbox;
|
|
587
|
+
// Загрузчик и строки картинки — тоже через ref: расширение их читает в
|
|
588
|
+
// момент вставки файла и при перерисовке подписи, а не при создании движка.
|
|
589
|
+
const uploadRef = useRef(onUploadImage);
|
|
590
|
+
uploadRef.current = onUploadImage;
|
|
591
|
+
const imageMessagesRef = useRef(messages.editor);
|
|
592
|
+
imageMessagesRef.current = messages.editor;
|
|
593
|
+
|
|
594
|
+
/*
|
|
595
|
+
Число символов держится состоянием только при `maxLength`: без предела
|
|
596
|
+
счётчика нет, и пересчитывать документ на каждую букву незачем. Функции
|
|
597
|
+
ниже читают только ref и сеттер состояния, поэтому в зависимостях
|
|
598
|
+
эффектов им делать нечего.
|
|
599
|
+
*/
|
|
600
|
+
const [count, setCount] = useState(0);
|
|
601
|
+
/**
|
|
602
|
+
* Поповер записи описания у выделения или у Блока (`ToolButtonView.tsx`):
|
|
603
|
+
* его открывают сочетание кнопки, кнопка ссылки, пункт вставки и Действие
|
|
604
|
+
* над Блоком — командой движка. После закрытия запрос остаётся
|
|
605
|
+
* (`open: false`), чтобы рамка закрылась штатно.
|
|
606
|
+
*/
|
|
607
|
+
const [toolPopover, setToolPopover] = useState<{
|
|
608
|
+
request: ToolPopoverRequest;
|
|
609
|
+
open: boolean;
|
|
610
|
+
} | null>(null);
|
|
611
|
+
// Поповер произвольного цвета: `null` — не открывали; после закрытия остаётся
|
|
612
|
+
// смонтированным (`open: false`), чтобы не грузить модуль заново.
|
|
613
|
+
const [customColor, setCustomColor] = useState<{
|
|
614
|
+
kind: CustomColorKind;
|
|
615
|
+
open: boolean;
|
|
616
|
+
} | null>(null);
|
|
617
|
+
const openCustomColor = (kind: CustomColorKind) => setCustomColor({ kind, open: true });
|
|
618
|
+
/** Открыт ли поповер картинки: кнопка Панели, пункт Меню вставки, панель картинки. */
|
|
619
|
+
const [imageOpen, setImageOpen] = useState(false);
|
|
620
|
+
// Окно «Вставить таблицу» — у Редактора, а не у меню: см. `TableInsertDialog`.
|
|
621
|
+
// Окно — из ленивого чанка таблицы (`tableTool.ts`): движок с таблицей
|
|
622
|
+
// создаётся после него, а без движка окна нет.
|
|
623
|
+
const TableInsertDialog = tableChunk()?.TableInsertDialog;
|
|
624
|
+
const [tableDialogOpen, setTableDialogOpen] = useState(false);
|
|
625
|
+
/**
|
|
626
|
+
* Сообщение поля (`showNotice`, `fieldNotice.ts`): одно, последнее. `status`
|
|
627
|
+
* — для живого региона, `error` — видимая строка под полем; правка
|
|
628
|
+
* Документа снимает `error`.
|
|
629
|
+
*/
|
|
630
|
+
const [notice, setNotice] = useState<FieldNotice | null>(null);
|
|
631
|
+
/*
|
|
632
|
+
HTML-режим: `null` — визуальный, иначе текст поля HTML и
|
|
633
|
+
высота Документа при входе — ниже неё поле не бывает, и страница не
|
|
634
|
+
прыгает. Режим — состояние Редактора, а не проп: движок остаётся
|
|
635
|
+
смонтированным и скрытым, история правок живёт.
|
|
636
|
+
|
|
637
|
+
Текст и база сравнения дублируются в ref: применение зовут обработчики
|
|
638
|
+
формы и `ref`-хэндл, у которых нет свежего замыкания. База — текст на
|
|
639
|
+
входе или после последнего применения: неизменённый текст не порождает
|
|
640
|
+
ни транзакции, ни шага истории, ни `onChange`.
|
|
641
|
+
*/
|
|
642
|
+
const [source, setSource] = useState<{ text: string; minHeight: number } | null>(null);
|
|
643
|
+
const sourceOpen = source !== null;
|
|
644
|
+
/**
|
|
645
|
+
* Панель поиска: `token` растёт с каждым открытием — повторный
|
|
646
|
+
* `Mod+F` при открытой панели заново ставит фокус в поле поиска; `query` —
|
|
647
|
+
* текст, выделенный в Документе в момент открытия.
|
|
648
|
+
*/
|
|
649
|
+
const [searchPanel, setSearchPanel] = useState<{
|
|
650
|
+
token: number;
|
|
651
|
+
replace: boolean;
|
|
652
|
+
query: string;
|
|
653
|
+
} | null>(null);
|
|
654
|
+
const sourceFieldRef = useRef<HTMLTextAreaElement>(null);
|
|
655
|
+
const sourceTextRef = useRef<string | null>(null);
|
|
656
|
+
const sourceBaseRef = useRef("");
|
|
657
|
+
/** Куда поставить фокус после смены режима: вход — в поле, выход кнопкой — в Документ. */
|
|
658
|
+
const switchFocusRef = useRef<"source" | "document" | null>(null);
|
|
659
|
+
// Расширение живёт столько же, сколько движок, а режим Панели меняется на
|
|
660
|
+
// лету (`pointer: coarse`): обработчик `Alt+F10` читается через ref.
|
|
661
|
+
const focusToolbarRef = useRef<() => boolean>(() => false);
|
|
662
|
+
// `Mod+/` — меню ручки Блока; обработчик кладёт сама ручка (`BlockHandle`).
|
|
663
|
+
const openBlockMenuRef = useRef<() => boolean>(() => false);
|
|
664
|
+
// `Alt+F10` ведёт в открытую Карточку у текста раньше, чем в Панель (`TextCard`).
|
|
665
|
+
const textCardRef = useRef<TextCardControl | null>(null);
|
|
666
|
+
const recount = (current: Editor) => {
|
|
667
|
+
if (limitRef.current !== undefined) setCount(countCharacters(current.state.doc));
|
|
668
|
+
};
|
|
669
|
+
const emit = (html: string) => {
|
|
670
|
+
knownRef.current = html;
|
|
671
|
+
if (hiddenRef.current) hiddenRef.current.value = html;
|
|
672
|
+
onChangeRef.current?.(html);
|
|
673
|
+
};
|
|
674
|
+
|
|
675
|
+
/*
|
|
676
|
+
Проверка обязательности. Пустым документ считается по правилу кита
|
|
677
|
+
(`emptiness.ts`): атом (`hr`, картинка, свой атом) и таблица, даже с
|
|
678
|
+
пустыми ячейками, — содержимое, документ из одного такого блока форму не
|
|
679
|
+
блокирует. Эта же проверка решает, что в скрытое поле уходит `""`.
|
|
680
|
+
|
|
681
|
+
Вызывается на каждую правку, а не по таймеру `onChange`: отправка может
|
|
682
|
+
случиться через 50 мс после первой буквы, и запоздавшая валидность
|
|
683
|
+
заблокировала бы форму с текстом.
|
|
684
|
+
|
|
685
|
+
В HTML-режиме с неприменённой правкой пустоту решает текст поля, а не
|
|
686
|
+
Документ: браузер проверяет ограничения ДО события `submit`, а правку
|
|
687
|
+
применяет его захват — `form.requestSubmit()` с фокусом в поле иначе
|
|
688
|
+
заблокировал бы форму с текстом в поле как пустую (и пропустил бы
|
|
689
|
+
очищенное поле). Текст разбирается тем же `createDocument` Tiptap со Схемой, что
|
|
690
|
+
и при применении, а пустота — то же правило кита, что у Документа.
|
|
691
|
+
Разбор — только когда проверка включена: без `required` он ни к чему.
|
|
692
|
+
*/
|
|
693
|
+
const validatableRef = useRef(false);
|
|
694
|
+
const requiredMessageRef = useRef(messages.editor.required);
|
|
695
|
+
requiredMessageRef.current = messages.editor.required;
|
|
696
|
+
const fieldEmpty = (current: Editor) => {
|
|
697
|
+
const text = sourceTextRef.current;
|
|
698
|
+
return text !== null && text !== sourceBaseRef.current
|
|
699
|
+
? isDocumentEmpty(createDocument(text, current.schema))
|
|
700
|
+
: isDocumentEmpty(current.state.doc);
|
|
701
|
+
};
|
|
702
|
+
const syncValidity = (current: Editor) => {
|
|
703
|
+
proxyRef.current?.setCustomValidity(
|
|
704
|
+
validatableRef.current && fieldEmpty(current) ? requiredMessageRef.current : ""
|
|
705
|
+
);
|
|
706
|
+
};
|
|
707
|
+
|
|
708
|
+
const throttle = useChangeThrottle(() => {
|
|
709
|
+
const current = editorRef.current;
|
|
710
|
+
if (current && !current.isDestroyed) emit(serialize(current));
|
|
711
|
+
}, changeDelay);
|
|
712
|
+
|
|
713
|
+
/*
|
|
714
|
+
Применение HTML-режима: текст поля проходит тем же разбором Схемой, что
|
|
715
|
+
входящий `value`, и заменяет Документ одной транзакцией — одним шагом
|
|
716
|
+
истории, который `Ctrl/⌘+Z` в Документе откатывает целиком. Зовётся на
|
|
717
|
+
выход из режима, `blur` поля, отправку формы, `formdata`, `getHTML()`,
|
|
718
|
+
`getMarkdown()` и переход в `readOnly`.
|
|
719
|
+
|
|
720
|
+
Неизменённый текст и текст, разбор которого дал тот же Документ (только
|
|
721
|
+
пробелы между Блоками), ничего не меняют: «открыл — посмотрел — закрыл»
|
|
722
|
+
не пачкает отмену и не зовёт `onChange`.
|
|
723
|
+
|
|
724
|
+
Замена — снаружи для предела (`EXTERNAL_CHANGE`): как `setMarkdown`, она
|
|
725
|
+
не режется, а счётчик показывает превышение. `onChange` — сразу, как на
|
|
726
|
+
`blur`, без `changeDelay`; ожидающий таймер снимается после замены, иначе
|
|
727
|
+
он отдал бы то же значение вторично. `closeHistory` с обеих сторон:
|
|
728
|
+
применение не сливается ни с правкой до входа, ни с первой правкой после.
|
|
729
|
+
*/
|
|
730
|
+
const applySource = () => {
|
|
731
|
+
const current = editorRef.current;
|
|
732
|
+
const text = sourceTextRef.current;
|
|
733
|
+
if (!current || current.isDestroyed || text === null || text === sourceBaseRef.current) {
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
sourceBaseRef.current = text;
|
|
737
|
+
const next = createDocument(text, current.schema);
|
|
738
|
+
if (next.eq(current.state.doc)) return;
|
|
739
|
+
current
|
|
740
|
+
.chain()
|
|
741
|
+
.setMeta(EXTERNAL_CHANGE, true)
|
|
742
|
+
.command(({ tr }) => {
|
|
743
|
+
closeHistory(tr);
|
|
744
|
+
return true;
|
|
745
|
+
})
|
|
746
|
+
.setContent(next, { emitUpdate: false })
|
|
747
|
+
.run();
|
|
748
|
+
current.view.dispatch(closeHistory(current.state.tr));
|
|
749
|
+
throttle.cancel();
|
|
750
|
+
recount(current);
|
|
751
|
+
syncValidity(current);
|
|
752
|
+
emit(serialize(current));
|
|
753
|
+
};
|
|
754
|
+
const applySourceRef = useRef(applySource);
|
|
755
|
+
applySourceRef.current = applySource;
|
|
756
|
+
/*
|
|
757
|
+
Размонтирование применяет правку, как `blur`: Escape в поле HTML внутри
|
|
758
|
+
`Dialog` закрывает окно, и Редактор уходит из дерева без `blur` поля —
|
|
759
|
+
правка пропала бы молча. Движок к этому моменту жив: `useEditor` Tiptap
|
|
760
|
+
уничтожает его таймером после своей очистки, а очистки эффектов идут
|
|
761
|
+
одним проходом раньше таймера. Отданный `onChange` — тот же, что на
|
|
762
|
+
`blur`; без правки (`sourceBaseRef`) ничего не зовётся.
|
|
763
|
+
*/
|
|
764
|
+
useEffect(() => () => applySourceRef.current(), []);
|
|
765
|
+
|
|
766
|
+
/** Текст поля HTML — форматированием Документа как есть: вход и замены снаружи. */
|
|
767
|
+
const writeSource = (current: Editor) => {
|
|
768
|
+
const text = formatSourceHtml(serialize(current));
|
|
769
|
+
sourceTextRef.current = text;
|
|
770
|
+
sourceBaseRef.current = text;
|
|
771
|
+
return text;
|
|
772
|
+
};
|
|
773
|
+
/*
|
|
774
|
+
Документ заменён снаружи в режиме (`value`, `setMarkdown`, `clear`):
|
|
775
|
+
текст поля перезаписывается новым Документом — владелец значения главнее
|
|
776
|
+
несохранённой правки, как и в визуальном режиме.
|
|
777
|
+
*/
|
|
778
|
+
const rewriteSource = (current: Editor) => {
|
|
779
|
+
if (sourceTextRef.current === null) return;
|
|
780
|
+
const text = writeSource(current);
|
|
781
|
+
setSource((previous) => previous && { ...previous, text });
|
|
782
|
+
};
|
|
783
|
+
const openSource = () => {
|
|
784
|
+
const current = editorRef.current;
|
|
785
|
+
if (!current) return;
|
|
786
|
+
// Документа на экране не будет — искать в нём негде.
|
|
787
|
+
if (searchPanel) closeSearch(false);
|
|
788
|
+
const text = writeSource(current);
|
|
789
|
+
switchFocusRef.current = "source";
|
|
790
|
+
setSource({ text, minHeight: current.view.dom.getBoundingClientRect().height });
|
|
791
|
+
};
|
|
792
|
+
const closeSource = (focusDocument: boolean) => {
|
|
793
|
+
applySource();
|
|
794
|
+
sourceTextRef.current = null;
|
|
795
|
+
switchFocusRef.current = focusDocument ? "document" : null;
|
|
796
|
+
setSource(null);
|
|
797
|
+
};
|
|
798
|
+
/** Фокус в поле: в HTML-режиме — поле HTML, иначе Документ. */
|
|
799
|
+
const focusField = () => {
|
|
800
|
+
if (sourceTextRef.current !== null) sourceFieldRef.current?.focus();
|
|
801
|
+
else editorRef.current?.commands.focus();
|
|
802
|
+
};
|
|
803
|
+
const focusFieldRef = useRef(focusField);
|
|
804
|
+
focusFieldRef.current = focusField;
|
|
805
|
+
|
|
806
|
+
/*
|
|
807
|
+
Открыть панель поиска: кнопка Панели, `Mod+F`/`Mod+Alt+F` из движка и
|
|
808
|
+
`openSearch()` Хэндла. Выделенный текст одного Блока становится запросом,
|
|
809
|
+
как в редакторах кода; выделение через Блоки — нет: запрос не переходит
|
|
810
|
+
границу Блока, и такой текст не нашёлся бы. В HTML-режиме Документа на
|
|
811
|
+
экране нет — искать негде, и `Mod+F` остаётся браузеру.
|
|
812
|
+
*/
|
|
813
|
+
const openSearch = (replace: boolean): boolean => {
|
|
814
|
+
const current = editorRef.current;
|
|
815
|
+
if (!current || !enabledTools.has("search") || sourceTextRef.current !== null) return false;
|
|
816
|
+
const { $from, $to, empty } = current.state.selection;
|
|
817
|
+
const query =
|
|
818
|
+
!empty && $from.sameParent($to) ? current.state.doc.textBetween($from.pos, $to.pos) : "";
|
|
819
|
+
setSearchPanel((previous) => ({ token: (previous?.token ?? 0) + 1, replace, query }));
|
|
820
|
+
return true;
|
|
821
|
+
};
|
|
822
|
+
const openSearchRef = useRef(openSearch);
|
|
823
|
+
openSearchRef.current = openSearch;
|
|
824
|
+
/*
|
|
825
|
+
Закрыть панель поиска: Escape, «Закрыть», повторная кнопка «Поиск».
|
|
826
|
+
Каретка — на текущем совпадении, фокус — в Документе: автор продолжает с
|
|
827
|
+
того места, где искал. При входе в HTML-режим — без фокуса: он уходит в
|
|
828
|
+
поле HTML.
|
|
829
|
+
*/
|
|
830
|
+
const closeSearch = (focusDocument: boolean) => {
|
|
831
|
+
const current = editorRef.current;
|
|
832
|
+
if (current && !current.isDestroyed) {
|
|
833
|
+
const state = searchState(current.state);
|
|
834
|
+
const match = state?.matches[state.current];
|
|
835
|
+
const chain = current.chain();
|
|
836
|
+
if (focusDocument) chain.focus();
|
|
837
|
+
if (focusDocument && match) chain.setTextSelection({ from: match.from, to: match.to });
|
|
838
|
+
chain.clearSearch().run();
|
|
839
|
+
}
|
|
840
|
+
setSearchPanel(null);
|
|
841
|
+
};
|
|
842
|
+
|
|
843
|
+
// Пункты Меню вставки — из того же замороженного набора, что и Схема.
|
|
844
|
+
const insertItems = useMemo(() => insertItemsFor(enabledTools), [enabledTools]);
|
|
845
|
+
const textCardEntries = useMemo(() => textCardsOf(enabledTools), [enabledTools]);
|
|
846
|
+
const slash = useSlashMenu(insertItems, editorRef);
|
|
847
|
+
const slashBridge = slash.bridge;
|
|
848
|
+
const triggerRecords = useMemo(() => triggersOf(enabledTools), [enabledTools]);
|
|
849
|
+
const triggerMenu = useTriggerMenu(triggerRecords, editorRef);
|
|
850
|
+
const triggerBindings = triggerMenu.bindings;
|
|
851
|
+
|
|
852
|
+
const extensions = useMemo(
|
|
853
|
+
() =>
|
|
854
|
+
ready &&
|
|
855
|
+
createEditorExtensions({
|
|
856
|
+
tools: enabledTools,
|
|
857
|
+
placeholder: () => placeholderRef.current,
|
|
858
|
+
limit: () => limitRef.current,
|
|
859
|
+
taskCheckbox: (text) => taskCheckboxRef.current({ text }),
|
|
860
|
+
slash: slashBridge,
|
|
861
|
+
triggers: triggerBindings,
|
|
862
|
+
openPopover: (request) => setToolPopover({ request, open: true }),
|
|
863
|
+
focusToolbar: () => focusToolbarRef.current(),
|
|
864
|
+
openBlockMenu: () => openBlockMenuRef.current(),
|
|
865
|
+
onNotice: setNotice,
|
|
866
|
+
openSearch: (replace) => openSearchRef.current(replace),
|
|
867
|
+
image: {
|
|
868
|
+
/*
|
|
869
|
+
Поповер открывается кадром позже. Пункт Меню вставки зовёт
|
|
870
|
+
команду в цепочке после `focus()`, а Tiptap возвращает фокус в
|
|
871
|
+
документ в следующем кадре: открытый сразу поповер получил бы
|
|
872
|
+
фокус в поле адреса и тут же потерял его — и закрылся как
|
|
873
|
+
«фокус ушёл наружу».
|
|
874
|
+
*/
|
|
875
|
+
onOpenEditor: () => requestAnimationFrame(() => setImageOpen(true)),
|
|
876
|
+
captionPlaceholder: () => imageMessagesRef.current.imageCaption,
|
|
877
|
+
uploadingLabel: (name) => imageMessagesRef.current.imageUploading({ name }),
|
|
878
|
+
upload: () => uploadRef.current,
|
|
879
|
+
describeNotice: (event) => describeImageNotice(event, imageMessagesRef.current),
|
|
880
|
+
},
|
|
881
|
+
}),
|
|
882
|
+
[enabledTools, slashBridge, triggerBindings, ready]
|
|
883
|
+
);
|
|
884
|
+
/*
|
|
885
|
+
Ошибка сборки набора своих Инструментов (ADR-0058, п. 1.5, 2.4) — ошибка
|
|
886
|
+
поля: Схема с таким набором потеряла бы чужие Блоки уже при разборе
|
|
887
|
+
`value`. Движок тогда собирается из запасного набора и пустым, а наружу
|
|
888
|
+
не выходит (`editor` ниже — `null`, как до монтажа): Хэндл тихий,
|
|
889
|
+
скрытое поле несёт входящее значение, `onChange` молчит. Набор с
|
|
890
|
+
загрузчиками проверяется, когда они отработали: Часть для движка — их итог.
|
|
891
|
+
*/
|
|
892
|
+
const toolsError = useMemo(
|
|
893
|
+
() => extensions && customToolsError(enabledTools, extensions),
|
|
894
|
+
[enabledTools, extensions]
|
|
895
|
+
);
|
|
896
|
+
useEffect(() => {
|
|
897
|
+
if (toolsError) devError(`RichTextEditor: ${toolsError.message}`, toolsError.cause);
|
|
898
|
+
}, [toolsError]);
|
|
899
|
+
|
|
900
|
+
/*
|
|
901
|
+
Имя подписи `FormField`. `<label for>` браузер связывает только с
|
|
902
|
+
«labelable»-элементами — `input`, `textarea`, `select`, — а
|
|
903
|
+
`contenteditable` к ним не относится: подпись была бы видна, но поле
|
|
904
|
+
оставалось бы безымянным.
|
|
905
|
+
|
|
906
|
+
Поэтому имя идёт ссылкой: `FormField` публикует `id` своей подписи
|
|
907
|
+
контекстом, и поле ставит его в `aria-labelledby`. Явные `aria-label` и
|
|
908
|
+
`aria-labelledby` сильнее: потребитель знает про своё поле больше.
|
|
909
|
+
|
|
910
|
+
Щелчок по подписи нативно сюда не доходит по той же причине, поэтому
|
|
911
|
+
слушатель вешается на сам узел подписи — только на чтение: `FormField`
|
|
912
|
+
остаётся как есть, а правило «подпись фокусирует поле» живёт у поля.
|
|
913
|
+
Подпись, у которой `for` указывает на настоящий нативный control, не
|
|
914
|
+
трогаем: её фокус уже решён браузером.
|
|
915
|
+
*/
|
|
916
|
+
const fieldLabelId = useFieldLabelId();
|
|
917
|
+
useEffect(() => {
|
|
918
|
+
const label = fieldLabelId
|
|
919
|
+
? rootRef.current?.ownerDocument.getElementById(fieldLabelId)
|
|
920
|
+
: null;
|
|
921
|
+
if (!(label instanceof HTMLLabelElement) || label.control) return;
|
|
922
|
+
const focus = () => focusFieldRef.current();
|
|
923
|
+
label.addEventListener("click", focus);
|
|
924
|
+
return () => label.removeEventListener("click", focus);
|
|
925
|
+
}, [fieldLabelId]);
|
|
926
|
+
|
|
927
|
+
/*
|
|
928
|
+
Счётчик появляется у 80 % предела и до того не занимает места. Пока он
|
|
929
|
+
виден, он входит в описание поля: скринридер называет остаток при входе
|
|
930
|
+
в поле, но не объявляет каждую букву — живой регион на счётчике говорил
|
|
931
|
+
бы поверх набора.
|
|
932
|
+
*/
|
|
933
|
+
const counterId = useId();
|
|
934
|
+
const counter =
|
|
935
|
+
maxLength !== undefined && count >= maxLength * 0.8
|
|
936
|
+
? count > maxLength
|
|
937
|
+
? messages.editor.overLimit({ count: count - maxLength })
|
|
938
|
+
: messages.editor.remaining({ count: maxLength - count })
|
|
939
|
+
: null;
|
|
940
|
+
|
|
941
|
+
const describedBy = useDescribedBy(
|
|
942
|
+
[ariaDescribedBy, counter != null ? counterId : undefined].filter(Boolean).join(" ") ||
|
|
943
|
+
undefined
|
|
944
|
+
);
|
|
945
|
+
// Явный проп сильнее раскладки формы — тот же порядок, что у `TextControl`.
|
|
946
|
+
const fieldInvalid = useFieldInvalid();
|
|
947
|
+
const invalid = ariaInvalid ?? fieldInvalid;
|
|
948
|
+
const labelledBy = ariaLabelledBy ?? (ariaLabel ? undefined : fieldLabelId);
|
|
949
|
+
const editable = !readOnly && !disabled;
|
|
950
|
+
/*
|
|
951
|
+
Плавающая Панель и меню выделения на сенсорном экране спорят с системным
|
|
952
|
+
меню выделения («Копировать / Вставить») за одно место над текстом и
|
|
953
|
+
проигрывают ему: там вместо них фиксированная Панель (спека, «Панель и
|
|
954
|
+
Меню вставки»; то же для плашки).
|
|
955
|
+
*/
|
|
956
|
+
const coarsePointer = useCoarsePointer();
|
|
957
|
+
const toolbarMode =
|
|
958
|
+
(toolbar === "floating" || toolbar === "bubble") && coarsePointer ? "fixed" : toolbar;
|
|
959
|
+
// Плашка выделения: своим режимом или поверх фиксированной Панели (но не
|
|
960
|
+
// поверх той, что заменила плавающую на сенсорном экране).
|
|
961
|
+
const bubbleShown =
|
|
962
|
+
toolbarMode === "bubble" || (toolbar === "fixed" && selectionMenu && !coarsePointer);
|
|
963
|
+
/*
|
|
964
|
+
HTML-режим — только у фиксированной Панели: у плавающей и меню
|
|
965
|
+
выделения кнопки нет (они живут над выделением в Документе), при `none` и
|
|
966
|
+
в `readOnly` Панели нет. Пропала кнопка при открытом режиме — режим
|
|
967
|
+
закрывается с применением: входа без выхода не бывает.
|
|
968
|
+
*/
|
|
969
|
+
const sourceAvailable = enabledTools.has("source") && toolbarMode === "fixed" && !readOnly;
|
|
970
|
+
|
|
971
|
+
/*
|
|
972
|
+
Область Документа (ADR-0059): Документ, его Скелет, поле HTML-режима и
|
|
973
|
+
ручка Блока. С `maxHeight` или `resizable` она прокручивает их сама —
|
|
974
|
+
Панель над ней и Строка статуса под ней остаются на месте. `relative`
|
|
975
|
+
делает её началом координат ручки Блока, и ручка едет вместе с текстом;
|
|
976
|
+
плашки над выделением слушают её прокрутку (`scrollTarget`). Без пропов
|
|
977
|
+
это простой блок без стилей: поле растёт с Документом, как раньше.
|
|
978
|
+
|
|
979
|
+
Поля `-mx-3 px-3` — под горизонтальный отступ оболочки, как у Панели:
|
|
980
|
+
полоса прокрутки встаёт у рамки, а ручка Блока слева не срезается.
|
|
981
|
+
*/
|
|
982
|
+
const scrolls = maxHeight != null || resizable;
|
|
983
|
+
const [scrollArea, setScrollArea] = useState<HTMLDivElement | null>(null);
|
|
984
|
+
const scrollTarget = scrolls ? (scrollArea ?? undefined) : undefined;
|
|
985
|
+
const areaLength = maxHeight == null ? undefined : cssLength(maxHeight);
|
|
986
|
+
/** Высота, натянутая ручкой (`FieldResizer`); `null` — стартовая. */
|
|
987
|
+
const [areaHeight, setAreaHeight] = useState<number | null>(null);
|
|
988
|
+
const areaStyle: CSSProperties | undefined = !scrolls
|
|
989
|
+
? undefined
|
|
990
|
+
: resizable
|
|
991
|
+
? {
|
|
992
|
+
height: areaHeight != null ? `${areaHeight}px` : areaLength,
|
|
993
|
+
minHeight: FIELD_MIN_HEIGHT,
|
|
994
|
+
}
|
|
995
|
+
: { maxHeight: areaLength };
|
|
996
|
+
|
|
997
|
+
/*
|
|
998
|
+
`Alt+F10` — фокус на первое доступное действие Панели. Плавающую Панель
|
|
999
|
+
клавиша показывает сама, не дожидаясь задержки показа: человек с
|
|
1000
|
+
клавиатуры выделил текст и сразу просит Панель. На пустом выделении
|
|
1001
|
+
плавающей Панели нет — клавиша уходит дальше, как без Панели вовсе. Меню
|
|
1002
|
+
выделения (`bubble`) — ровно так же, своим ключом плагина.
|
|
1003
|
+
*/
|
|
1004
|
+
focusToolbarRef.current = () => {
|
|
1005
|
+
const current = editorRef.current;
|
|
1006
|
+
const root = rootRef.current;
|
|
1007
|
+
if (!current || !root) return false;
|
|
1008
|
+
// Открытая Карточка у текста ближе Панели; спрятанная клавишу не берёт.
|
|
1009
|
+
if (textCardRef.current?.focus()) return true;
|
|
1010
|
+
if (readOnly) return false;
|
|
1011
|
+
/*
|
|
1012
|
+
HTML-режим (из поля HTML, `onKeyDown` ниже): Документа нет, остальные
|
|
1013
|
+
действия Панели — `aria-disabled`. Фокус — на первое, которое
|
|
1014
|
+
сработает, то есть на саму «HTML»: Enter на ней возвращает визуальный
|
|
1015
|
+
режим, а стрелки ведут по Панели дальше, как обычно.
|
|
1016
|
+
*/
|
|
1017
|
+
if (sourceTextRef.current !== null) {
|
|
1018
|
+
const action = root
|
|
1019
|
+
.querySelector('[role="toolbar"]')
|
|
1020
|
+
?.querySelector<HTMLElement>('button:not([disabled]):not([aria-disabled="true"])');
|
|
1021
|
+
if (!action) return false;
|
|
1022
|
+
action.focus();
|
|
1023
|
+
return true;
|
|
1024
|
+
}
|
|
1025
|
+
// Выделена картинка — `Alt+F10` ведёт в её панель: действия над
|
|
1026
|
+
// выделенным ближе, чем Панель форматирования, которой картинке нечего дать.
|
|
1027
|
+
if (isImageSelection(current.state.selection)) {
|
|
1028
|
+
const action = root.querySelector<HTMLElement>(
|
|
1029
|
+
'[data-image-toolbar] [role="toolbar"] button:not([disabled])'
|
|
1030
|
+
);
|
|
1031
|
+
if (action) {
|
|
1032
|
+
action.focus();
|
|
1033
|
+
return true;
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
if (toolbarMode === "floating" || toolbarMode === "bubble") {
|
|
1037
|
+
if (current.state.selection.empty) return false;
|
|
1038
|
+
const key = toolbarMode === "floating" ? FLOATING_TOOLBAR_KEY : SELECTION_BUBBLE_KEY;
|
|
1039
|
+
current.view.dispatch(current.state.tr.setMeta(key, "show"));
|
|
1040
|
+
/*
|
|
1041
|
+
Плагин на `show` сначала считает позицию, потом показывает, а счёт
|
|
1042
|
+
у спрятанного меню — пустой ход. Без второй команды меню, спрятанное
|
|
1043
|
+
до нажатия, встало бы без координат под полем, куда плагин кладёт
|
|
1044
|
+
свой узел, и доехало бы до выделения только с его таймером (250 мс).
|
|
1045
|
+
*/
|
|
1046
|
+
current.view.dispatch(current.state.tr.setMeta(key, "updatePosition"));
|
|
1047
|
+
}
|
|
1048
|
+
const action = root
|
|
1049
|
+
.querySelector('[role="toolbar"]')
|
|
1050
|
+
?.querySelector<HTMLElement>("button:not([disabled])");
|
|
1051
|
+
if (!action) return false;
|
|
1052
|
+
action.focus();
|
|
1053
|
+
return true;
|
|
1054
|
+
};
|
|
1055
|
+
// Нативный `required` не проверяется у `readonly` и выключенных полей —
|
|
1056
|
+
// здесь то же правило.
|
|
1057
|
+
const validatable = required && editable;
|
|
1058
|
+
validatableRef.current = validatable;
|
|
1059
|
+
const requiredMessage = messages.editor.required;
|
|
1060
|
+
|
|
1061
|
+
/*
|
|
1062
|
+
Атрибуты редактируемой области. Объект пересобирается только при смене
|
|
1063
|
+
значений: `useEditor` сверяет опции по ссылке и иначе переустанавливал бы
|
|
1064
|
+
их движку на каждом рендере.
|
|
1065
|
+
*/
|
|
1066
|
+
const slashAttributes = slash.attributes;
|
|
1067
|
+
const triggerAttributes = triggerMenu.attributes;
|
|
1068
|
+
// Класс Документа — общий у движка и Скелета: ритм и отступы одни, и высота не прыгает.
|
|
1069
|
+
const documentClass = cn(
|
|
1070
|
+
proseClass(surface),
|
|
1071
|
+
PLACEHOLDER_CLASS,
|
|
1072
|
+
IMAGE_EDITING_CLASS,
|
|
1073
|
+
SEARCH_HIGHLIGHT_CLASS,
|
|
1074
|
+
// Лист отступает от рамки поля: край листа виден на подложке поля.
|
|
1075
|
+
surface === "paper" ? "my-3 min-h-24 outline-none" : "min-h-24 py-2.5 outline-none",
|
|
1076
|
+
// Левое поле под ручку Блока (`BlockHandle`): ручка стоит в нём и
|
|
1077
|
+
// текст не перекрывает. Только там, где ручка бывает, — не в
|
|
1078
|
+
// `readOnly`; у выключенного поля остаётся, чтобы текст не прыгал.
|
|
1079
|
+
!readOnly && (surface === "paper" ? "pl-10" : "pl-6")
|
|
1080
|
+
);
|
|
1081
|
+
const editorProps = useMemo(() => {
|
|
1082
|
+
const attributes: Record<string, string> = {
|
|
1083
|
+
role: "textbox",
|
|
1084
|
+
"aria-multiline": "true",
|
|
1085
|
+
"aria-placeholder": placeholderText,
|
|
1086
|
+
// Глобальный контур `:focus-visible` здесь лишний — фокус показывает
|
|
1087
|
+
// рамка поля, как у `TextControl`.
|
|
1088
|
+
"data-disable-focus-ring": "true",
|
|
1089
|
+
class: documentClass,
|
|
1090
|
+
...surfaceAttributes(surface),
|
|
1091
|
+
};
|
|
1092
|
+
if (id) attributes.id = id;
|
|
1093
|
+
if (labelledBy) attributes["aria-labelledby"] = labelledBy;
|
|
1094
|
+
else attributes["aria-label"] = ariaLabel ?? messages.editor.label;
|
|
1095
|
+
if (describedBy) attributes["aria-describedby"] = describedBy;
|
|
1096
|
+
if (invalid) attributes["aria-invalid"] = "true";
|
|
1097
|
+
if (required) attributes["aria-required"] = "true";
|
|
1098
|
+
if (readOnly) attributes["aria-readonly"] = "true";
|
|
1099
|
+
if (disabled) attributes["aria-disabled"] = "true";
|
|
1100
|
+
// Меню вставки открывается только в правке: полю только для чтения
|
|
1101
|
+
// обещать список нечего.
|
|
1102
|
+
if (editable) Object.assign(attributes, slashAttributes, triggerAttributes);
|
|
1103
|
+
return { attributes };
|
|
1104
|
+
}, [
|
|
1105
|
+
editable,
|
|
1106
|
+
slashAttributes,
|
|
1107
|
+
triggerAttributes,
|
|
1108
|
+
id,
|
|
1109
|
+
labelledBy,
|
|
1110
|
+
ariaLabel,
|
|
1111
|
+
messages.editor.label,
|
|
1112
|
+
describedBy,
|
|
1113
|
+
invalid,
|
|
1114
|
+
required,
|
|
1115
|
+
readOnly,
|
|
1116
|
+
disabled,
|
|
1117
|
+
placeholderText,
|
|
1118
|
+
surface,
|
|
1119
|
+
documentClass,
|
|
1120
|
+
]);
|
|
1121
|
+
|
|
1122
|
+
/*
|
|
1123
|
+
Пока загрузчики работают или набор с ошибкой, движок `useEditor` собран
|
|
1124
|
+
из запасного набора и наружу не выходит. Набор сменился — запасной
|
|
1125
|
+
уничтожается: живому движку Tiptap только переставляет опции, Схему не
|
|
1126
|
+
пересобирает, а уничтоженный создаёт заново с новым набором. Эффект стоит
|
|
1127
|
+
РАНЬШЕ `useEditor`: эффекты идут в порядке объявления, и его — первым.
|
|
1128
|
+
*/
|
|
1129
|
+
const engineSet = extensions && !toolsError ? extensions : FALLBACK_EXTENSIONS;
|
|
1130
|
+
const engineRef = useRef<Editor | null>(null);
|
|
1131
|
+
useEffect(() => {
|
|
1132
|
+
if (engineRef.current?.options.extensions !== engineSet) engineRef.current?.destroy();
|
|
1133
|
+
}, [engineSet]);
|
|
1134
|
+
const engine = useEditor({
|
|
1135
|
+
immediatelyRender: false,
|
|
1136
|
+
extensions: engineSet,
|
|
1137
|
+
content: engineSet === extensions ? initial : "",
|
|
1138
|
+
editable,
|
|
1139
|
+
editorProps,
|
|
1140
|
+
onUpdate: ({ editor: updated }) => {
|
|
1141
|
+
// Правка снимает ошибку: она про прошлое действие.
|
|
1142
|
+
setNotice((current) => (current?.tone === "error" ? null : current));
|
|
1143
|
+
recount(updated);
|
|
1144
|
+
syncValidity(updated);
|
|
1145
|
+
throttle.schedule();
|
|
1146
|
+
},
|
|
1147
|
+
onBlur: () => throttle.flush(),
|
|
1148
|
+
});
|
|
1149
|
+
engineRef.current = engine;
|
|
1150
|
+
const loadFailed = !!engine && !loading && !ready;
|
|
1151
|
+
const editor = engine?.options.extensions === extensions ? engine : null;
|
|
1152
|
+
editorRef.current = editor;
|
|
1153
|
+
/*
|
|
1154
|
+
Документ Скелета — только в браузере после монтирования: разбор Схемой
|
|
1155
|
+
идёт в DOM браузера, а сервер и гидратация видят пустой Скелет, иначе
|
|
1156
|
+
разметка разошлась бы. Клиентский рендер без SSR получает Документ с
|
|
1157
|
+
первого кадра (`useSyncExternalStore` отдаёт серверный снимок только при
|
|
1158
|
+
гидратации). Пересчёт — на новый `value` и на каждый отработавший
|
|
1159
|
+
загрузчик: их число только растёт (повтор зовёт лишь упавшие).
|
|
1160
|
+
*/
|
|
1161
|
+
const mounted = useSyncExternalStore(subscribeNever, isBrowser, isServer);
|
|
1162
|
+
const settledLoads = loads.filter((load) => load.done).length;
|
|
1163
|
+
const skeleton = useMemo(
|
|
1164
|
+
() =>
|
|
1165
|
+
mounted && !editor
|
|
1166
|
+
? skeletonHtml(
|
|
1167
|
+
initial,
|
|
1168
|
+
enabledTools,
|
|
1169
|
+
loaders.filter((_, index) => !loads[index]?.done)
|
|
1170
|
+
)
|
|
1171
|
+
: "",
|
|
1172
|
+
[mounted, !editor, initial, enabledTools, settledLoads]
|
|
1173
|
+
);
|
|
1174
|
+
|
|
1175
|
+
/*
|
|
1176
|
+
Начальный конверт встаёт сразу при появлении движка — в фазе компоновки,
|
|
1177
|
+
до первой отрисовки: пустой Документ на экране не мелькает. Это начальное
|
|
1178
|
+
значение, а не правка: ни `onChange`, ни шага истории; предел символов его
|
|
1179
|
+
не режет. Скрытое поле и счётчик сверяются ниже, как для HTML.
|
|
1180
|
+
*/
|
|
1181
|
+
useLayoutEffect(() => {
|
|
1182
|
+
const envelope = initialDocumentRef.current;
|
|
1183
|
+
if (!editor || !envelope) return;
|
|
1184
|
+
const next = documentFromJSON(editor, envelope);
|
|
1185
|
+
if (!next) {
|
|
1186
|
+
devError("RichTextEditor: defaultValue is not a rich text document; it is ignored");
|
|
1187
|
+
return;
|
|
1188
|
+
}
|
|
1189
|
+
editor
|
|
1190
|
+
.chain()
|
|
1191
|
+
.setMeta(EXTERNAL_CHANGE, true)
|
|
1192
|
+
.setMeta("addToHistory", false)
|
|
1193
|
+
.setContent(next, { emitUpdate: false })
|
|
1194
|
+
.run();
|
|
1195
|
+
knownRef.current = serialize(editor);
|
|
1196
|
+
}, [editor]);
|
|
1197
|
+
|
|
1198
|
+
/*
|
|
1199
|
+
Движок появился — скрытое поле и счётчик сверяются с разобранным
|
|
1200
|
+
документом. Не в `onCreate`: Tiptap шлёт его таймером уже после монтажа, и
|
|
1201
|
+
до того счётчик показывал бы ноль при длинном `value`. Скрытое поле до
|
|
1202
|
+
этого момента несёт входящую строку как есть — так её получает и
|
|
1203
|
+
серверный рендер, где движка нет вовсе.
|
|
1204
|
+
*/
|
|
1205
|
+
useEffect(() => {
|
|
1206
|
+
if (!editor) return;
|
|
1207
|
+
if (hiddenRef.current) hiddenRef.current.value = serialize(editor);
|
|
1208
|
+
// Предел мог появиться позже движка — счётчику нужен свежий пересчёт.
|
|
1209
|
+
if (maxLength !== undefined) setCount(countCharacters(editor.state.doc));
|
|
1210
|
+
}, [editor, maxLength]);
|
|
1211
|
+
|
|
1212
|
+
// Прокси появляется и пропадает вместе с `required`, а текст сообщения —
|
|
1213
|
+
// с локалью: валидность сверяется с документом и при этом, не только на
|
|
1214
|
+
// правке.
|
|
1215
|
+
useEffect(() => {
|
|
1216
|
+
if (editor) syncValidity(editor);
|
|
1217
|
+
}, [editor, validatable, requiredMessage]);
|
|
1218
|
+
|
|
1219
|
+
// Плейсхолдер расширение перерисовывает только на транзакции: смена
|
|
1220
|
+
// локали без правки документа оставила бы на экране прежнюю строку.
|
|
1221
|
+
useEffect(() => {
|
|
1222
|
+
if (editor && !editor.isDestroyed) editor.view.dispatch(editor.state.tr);
|
|
1223
|
+
}, [editor, placeholderText]);
|
|
1224
|
+
|
|
1225
|
+
useEffect(() => {
|
|
1226
|
+
if (!editor || value === undefined || value === knownRef.current) return;
|
|
1227
|
+
// Документ заменён снаружи — ожидающая правка относится к прежнему и
|
|
1228
|
+
// отдавать её нечего. Замена не правка автора: `onChange` молчит, а
|
|
1229
|
+
// предел символов её не режет (`EXTERNAL_CHANGE`).
|
|
1230
|
+
throttle.cancel();
|
|
1231
|
+
knownRef.current = value;
|
|
1232
|
+
editor.chain().setMeta(EXTERNAL_CHANGE, true).setContent(value, { emitUpdate: false }).run();
|
|
1233
|
+
recount(editor);
|
|
1234
|
+
syncValidity(editor);
|
|
1235
|
+
if (hiddenRef.current) hiddenRef.current.value = serialize(editor);
|
|
1236
|
+
rewriteSource(editor);
|
|
1237
|
+
}, [editor, value, throttle]);
|
|
1238
|
+
|
|
1239
|
+
// `useEditor` переносит в движок все опции, кроме `editable`: её он
|
|
1240
|
+
// намеренно сохраняет у живого движка. Поэтому режим — отдельным вызовом,
|
|
1241
|
+
// и без события `update`: смена режима не правка.
|
|
1242
|
+
useEffect(() => {
|
|
1243
|
+
if (editor && editor.isEditable !== editable) editor.setEditable(editable, false);
|
|
1244
|
+
}, [editor, editable]);
|
|
1245
|
+
|
|
1246
|
+
// Кнопка «HTML» пропала (`readOnly`, смена `toolbar`, сенсорный экран
|
|
1247
|
+
// стал плавающим режимом) — режим закрывается с применением правки.
|
|
1248
|
+
useEffect(() => {
|
|
1249
|
+
if (!sourceAvailable && sourceTextRef.current !== null) closeSource(false);
|
|
1250
|
+
}, [sourceAvailable]);
|
|
1251
|
+
|
|
1252
|
+
/*
|
|
1253
|
+
Фокус при смене режима — после рендера: на входе поля ещё нет, на выходе
|
|
1254
|
+
Документ ещё скрыт. Вход — в поле HTML, каретка в начале; выход кнопкой
|
|
1255
|
+
— в Документ, каретка в конце, как `ref.focus()`.
|
|
1256
|
+
*/
|
|
1257
|
+
useEffect(() => {
|
|
1258
|
+
const target = switchFocusRef.current;
|
|
1259
|
+
switchFocusRef.current = null;
|
|
1260
|
+
if (target === "source") {
|
|
1261
|
+
const field = sourceFieldRef.current;
|
|
1262
|
+
field?.focus();
|
|
1263
|
+
field?.setSelectionRange(0, 0);
|
|
1264
|
+
} else if (target === "document") {
|
|
1265
|
+
editorRef.current?.commands.focus("end");
|
|
1266
|
+
}
|
|
1267
|
+
}, [sourceOpen]);
|
|
1268
|
+
|
|
1269
|
+
useEffect(() => {
|
|
1270
|
+
const form = rootRef.current?.closest("form");
|
|
1271
|
+
if (!form) return;
|
|
1272
|
+
// Захват на самой форме срабатывает раньше `onSubmit` потребителя:
|
|
1273
|
+
// React слушает всплытие у корня приложения.
|
|
1274
|
+
// Правка HTML-режима применяется первой: форма не теряет её и не
|
|
1275
|
+
// получает несанитизированный HTML.
|
|
1276
|
+
const flush = () => {
|
|
1277
|
+
applySourceRef.current();
|
|
1278
|
+
throttle.flush();
|
|
1279
|
+
};
|
|
1280
|
+
// `formdata` приходит на любой `new FormData(form)` — и на отправке, и
|
|
1281
|
+
// при автосохранении по таймеру, — но ПОСЛЕ сбора записей. Поэтому
|
|
1282
|
+
// свежее значение кладётся прямо в собранный набор.
|
|
1283
|
+
const fill = (event: FormDataEvent) => {
|
|
1284
|
+
flush();
|
|
1285
|
+
if (name != null && hiddenRef.current && !hiddenRef.current.disabled) {
|
|
1286
|
+
event.formData.set(name, hiddenRef.current.value);
|
|
1287
|
+
}
|
|
1288
|
+
};
|
|
1289
|
+
form.addEventListener("submit", flush, { capture: true });
|
|
1290
|
+
form.addEventListener("formdata", fill);
|
|
1291
|
+
return () => {
|
|
1292
|
+
form.removeEventListener("submit", flush, { capture: true });
|
|
1293
|
+
form.removeEventListener("formdata", fill);
|
|
1294
|
+
};
|
|
1295
|
+
}, [throttle, name]);
|
|
1296
|
+
|
|
1297
|
+
useImperativeHandle(
|
|
1298
|
+
ref,
|
|
1299
|
+
() => ({
|
|
1300
|
+
editor,
|
|
1301
|
+
...createHandleMethods({
|
|
1302
|
+
editor,
|
|
1303
|
+
editable,
|
|
1304
|
+
known: () => knownRef.current,
|
|
1305
|
+
initialDocument: () => initialDocumentRef.current,
|
|
1306
|
+
tables: enabledTools.has("table"),
|
|
1307
|
+
sourceOpen: () => sourceTextRef.current !== null,
|
|
1308
|
+
sourceField: () => sourceFieldRef.current,
|
|
1309
|
+
applySource: () => applySourceRef.current(),
|
|
1310
|
+
rewriteSource,
|
|
1311
|
+
fieldEmpty,
|
|
1312
|
+
}),
|
|
1313
|
+
getHTML: () => {
|
|
1314
|
+
applySourceRef.current();
|
|
1315
|
+
return editor ? serialize(editor) : knownRef.current;
|
|
1316
|
+
},
|
|
1317
|
+
getMarkdown: () => {
|
|
1318
|
+
applySourceRef.current();
|
|
1319
|
+
return editor && !isDocumentEmpty(editor.state.doc) ? markdownOf(editor) : "";
|
|
1320
|
+
},
|
|
1321
|
+
setMarkdown: (markdown) => {
|
|
1322
|
+
if (!editor) return;
|
|
1323
|
+
// Та же замена снаружи, что у `clear()`, и предел символов её не режет.
|
|
1324
|
+
// Таймер снимается ПОСЛЕ замены: её транзакция сама ставит `update`,
|
|
1325
|
+
// и отложенный `onChange` отдал бы уже отданное значение вторично.
|
|
1326
|
+
replaceWithMarkdown(editor, markdown);
|
|
1327
|
+
throttle.cancel();
|
|
1328
|
+
recount(editor);
|
|
1329
|
+
emit(serialize(editor));
|
|
1330
|
+
rewriteSource(editor);
|
|
1331
|
+
},
|
|
1332
|
+
getJSON: () => {
|
|
1333
|
+
if (!editor) return null;
|
|
1334
|
+
applySourceRef.current();
|
|
1335
|
+
return documentToJSON(editor);
|
|
1336
|
+
},
|
|
1337
|
+
setJSON: (document) => {
|
|
1338
|
+
// Та же Замена снаружи, что у `setMarkdown`, и в том же порядке.
|
|
1339
|
+
if (!editor || !replaceWithJSON(editor, document)) return false;
|
|
1340
|
+
throttle.cancel();
|
|
1341
|
+
recount(editor);
|
|
1342
|
+
emit(serialize(editor));
|
|
1343
|
+
rewriteSource(editor);
|
|
1344
|
+
return true;
|
|
1345
|
+
},
|
|
1346
|
+
openSearch: (options) => void openSearchRef.current(options?.replace ?? false),
|
|
1347
|
+
clear: () => {
|
|
1348
|
+
if (!editor) return;
|
|
1349
|
+
throttle.cancel();
|
|
1350
|
+
editor.chain().setMeta(EXTERNAL_CHANGE, true).clearContent(false).run();
|
|
1351
|
+
recount(editor);
|
|
1352
|
+
syncValidity(editor);
|
|
1353
|
+
// Очистку зовёт потребитель, но значение держит владелец: без
|
|
1354
|
+
// `onChange` управляемый режим вернул бы прежний текст следующим
|
|
1355
|
+
// рендером.
|
|
1356
|
+
emit("");
|
|
1357
|
+
rewriteSource(editor);
|
|
1358
|
+
},
|
|
1359
|
+
}),
|
|
1360
|
+
[editor, editable, throttle]
|
|
1361
|
+
);
|
|
1362
|
+
// Хук `useRichTextEditorState` не видит смену движка у `ref` сам — сообщаем.
|
|
1363
|
+
useEffect(() => notifyHandleEditor(ref), [ref, editor]);
|
|
1364
|
+
|
|
1365
|
+
/*
|
|
1366
|
+
Готовность (спека, словарь): один раз за монтаж, когда движок создан.
|
|
1367
|
+
Эффект идёт после `useImperativeHandle` (он — в фазе компоновки), поэтому
|
|
1368
|
+
`ref` в `onReady` уже действует. Флаг в ref, а не в эффекте: в строгом
|
|
1369
|
+
режиме React гоняет эффекты дважды, а событие одно. Загрузчики уже в
|
|
1370
|
+
условии: `editor` выходит наружу только после них, а ошибка набора и
|
|
1371
|
+
упавший загрузчик (`editor === null`) готовности не дают.
|
|
1372
|
+
*/
|
|
1373
|
+
const readySentRef = useRef(false);
|
|
1374
|
+
useEffect(() => {
|
|
1375
|
+
if (!editor || readySentRef.current) return;
|
|
1376
|
+
readySentRef.current = true;
|
|
1377
|
+
onReadyRef.current?.();
|
|
1378
|
+
}, [editor]);
|
|
1379
|
+
|
|
1380
|
+
/*
|
|
1381
|
+
Фокус поля — Документ, Панель, поповеры кита и поле HTML разом
|
|
1382
|
+
(`onFocus` и `onBlur` — о нём; Фокус Документа, `focus` и `blur` движка,
|
|
1383
|
+
клик в Панель снимает). Слушают корень поля через React: фокусные события
|
|
1384
|
+
React всплывают по дереву компонентов, в том числе из порталов, куда
|
|
1385
|
+
уходят поповеры и окна кита, — DOM-вложенность корня им не нужна.
|
|
1386
|
+
|
|
1387
|
+
`focusout` приходит раньше `focusin` следующей цели, поэтому уход
|
|
1388
|
+
подтверждается на такт позже: за это время фокус мог вернуться в поле
|
|
1389
|
+
(Документ → Панель → поповер → Документ). Цель в самом корне отсеивается
|
|
1390
|
+
сразу. `onBlur` идёт ПОСЛЕ вытолкнутого `onChange`: автосохранение по
|
|
1391
|
+
`blur` получает свежий Документ, откуда бы фокус ни ушёл — не только из
|
|
1392
|
+
Документа, где `blur` движка выталкивает сам.
|
|
1393
|
+
*/
|
|
1394
|
+
const fieldFocusedRef = useRef(false);
|
|
1395
|
+
const leaveTimerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
|
|
1396
|
+
useEffect(() => () => clearTimeout(leaveTimerRef.current), []);
|
|
1397
|
+
|
|
1398
|
+
const searchPanelElement = (className: string) =>
|
|
1399
|
+
editor &&
|
|
1400
|
+
searchPanel && (
|
|
1401
|
+
<Suspense fallback={null}>
|
|
1402
|
+
<SearchPanel
|
|
1403
|
+
editor={editor}
|
|
1404
|
+
focus={searchPanel}
|
|
1405
|
+
onClose={() => closeSearch(true)}
|
|
1406
|
+
className={className}
|
|
1407
|
+
/>
|
|
1408
|
+
</Suspense>
|
|
1409
|
+
);
|
|
1410
|
+
|
|
1411
|
+
return (
|
|
1412
|
+
<div
|
|
1413
|
+
ref={rootRef}
|
|
1414
|
+
className={cn("relative", className)}
|
|
1415
|
+
onFocus={() => {
|
|
1416
|
+
clearTimeout(leaveTimerRef.current);
|
|
1417
|
+
if (fieldFocusedRef.current) return;
|
|
1418
|
+
fieldFocusedRef.current = true;
|
|
1419
|
+
onFocusRef.current?.();
|
|
1420
|
+
}}
|
|
1421
|
+
onBlur={(event) => {
|
|
1422
|
+
const next = event.relatedTarget;
|
|
1423
|
+
if (next instanceof Node && event.currentTarget.contains(next)) return;
|
|
1424
|
+
clearTimeout(leaveTimerRef.current);
|
|
1425
|
+
leaveTimerRef.current = setTimeout(() => {
|
|
1426
|
+
if (!fieldFocusedRef.current) return;
|
|
1427
|
+
fieldFocusedRef.current = false;
|
|
1428
|
+
throttle.flush();
|
|
1429
|
+
onBlurRef.current?.();
|
|
1430
|
+
}, 0);
|
|
1431
|
+
}}
|
|
1432
|
+
>
|
|
1433
|
+
<div
|
|
1434
|
+
data-disabled={disabled || undefined}
|
|
1435
|
+
className={cn(
|
|
1436
|
+
FIELD_SHELL_CLASS,
|
|
1437
|
+
"has-[[contenteditable][aria-invalid=true]]:border-danger-strong",
|
|
1438
|
+
"data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50"
|
|
1439
|
+
)}
|
|
1440
|
+
>
|
|
1441
|
+
{editor && toolbarMode === "fixed" && !readOnly && (
|
|
1442
|
+
/*
|
|
1443
|
+
Липнет под шапкой приложения: отступ — `--topbar-h`, которую
|
|
1444
|
+
публикует `TopBar` (ADR-0016, ADR-0019); без шапки переменной нет,
|
|
1445
|
+
и Панель липнет к краю окна. Липкость — внутри рамки поля: Панель
|
|
1446
|
+
уходит вместе с полем, когда оно прокручено целиком.
|
|
1447
|
+
|
|
1448
|
+
Отрицательные поля — под горизонтальный отступ оболочки: фон
|
|
1449
|
+
Панели закрывает текст, уезжающий под неё, от рамки до рамки.
|
|
1450
|
+
`z-[1]` — внутри поля, а не ступень стека слоёв: Панель не
|
|
1451
|
+
оверлей и должна оставаться ниже любого из них.
|
|
1452
|
+
*/
|
|
1453
|
+
<div className={TOOLBAR_SHELL_CLASS}>
|
|
1454
|
+
<EditorToolbar
|
|
1455
|
+
editor={editor}
|
|
1456
|
+
tools={enabledTools}
|
|
1457
|
+
disabled={disabled}
|
|
1458
|
+
onInsertTable={() => setTableDialogOpen(true)}
|
|
1459
|
+
shortcutsReference
|
|
1460
|
+
search={
|
|
1461
|
+
enabledTools.has("search")
|
|
1462
|
+
? {
|
|
1463
|
+
open: searchPanel !== null,
|
|
1464
|
+
onToggle: () => (searchPanel ? closeSearch(true) : openSearch(false)),
|
|
1465
|
+
}
|
|
1466
|
+
: undefined
|
|
1467
|
+
}
|
|
1468
|
+
source={
|
|
1469
|
+
sourceAvailable
|
|
1470
|
+
? {
|
|
1471
|
+
active: sourceOpen,
|
|
1472
|
+
onToggle: () => (sourceOpen ? closeSource(true) : openSource()),
|
|
1473
|
+
}
|
|
1474
|
+
: undefined
|
|
1475
|
+
}
|
|
1476
|
+
/>
|
|
1477
|
+
{searchPanelElement(SEARCH_PANEL_PLACE_CLASS)}
|
|
1478
|
+
</div>
|
|
1479
|
+
)}
|
|
1480
|
+
{editor && !(toolbarMode === "fixed" && !readOnly) && searchPanel && (
|
|
1481
|
+
/*
|
|
1482
|
+
Без фиксированной Панели панель поиска — в верхнем углу поля:
|
|
1483
|
+
липкая обёртка нулевой высоты держит её на виду при прокрутке
|
|
1484
|
+
Документа и не сдвигает его.
|
|
1485
|
+
*/
|
|
1486
|
+
<div className="sticky top-[var(--topbar-h,0px)] z-[2] h-0">
|
|
1487
|
+
{searchPanelElement(SEARCH_PANEL_CORNER_CLASS)}
|
|
1488
|
+
</div>
|
|
1489
|
+
)}
|
|
1490
|
+
{!editor && toolbarMode === "fixed" && !readOnly && (
|
|
1491
|
+
// Скелет Панели — её рамка и невидимая копия раскладки: строк
|
|
1492
|
+
// столько же, сколько будет у Панели, и поле не прыгает.
|
|
1493
|
+
<div className={TOOLBAR_SHELL_CLASS}>
|
|
1494
|
+
<ToolbarSkeleton
|
|
1495
|
+
tools={enabledTools}
|
|
1496
|
+
source={sourceAvailable}
|
|
1497
|
+
search={enabledTools.has("search")}
|
|
1498
|
+
shortcutsReference
|
|
1499
|
+
/>
|
|
1500
|
+
</div>
|
|
1501
|
+
)}
|
|
1502
|
+
<div
|
|
1503
|
+
/*
|
|
1504
|
+
Реф — только у прокручиваемой области: колбэк ставит состояние и
|
|
1505
|
+
даёт лишний рендер на монтаже, а у обычного поля он сдвигал
|
|
1506
|
+
первый расчёт позиции плавающей Панели (опорой на миг становился
|
|
1507
|
+
весь Документ, и Панель вставала под полем).
|
|
1508
|
+
*/
|
|
1509
|
+
ref={scrolls ? setScrollArea : undefined}
|
|
1510
|
+
className={cn(scrolls && "relative -mx-3 overflow-y-auto px-3")}
|
|
1511
|
+
style={areaStyle}
|
|
1512
|
+
>
|
|
1513
|
+
{/* В HTML-режиме Документ скрыт, но смонтирован: движок и история живы. */}
|
|
1514
|
+
<EditorContent editor={editor} hidden={sourceOpen} />
|
|
1515
|
+
{!editor && (
|
|
1516
|
+
/*
|
|
1517
|
+
Скелет (ADR-0058, п. 11.4): до Готовности и при сбое загрузчика —
|
|
1518
|
+
Документ статичным HTML с классом Документа движка, без ввода.
|
|
1519
|
+
HTML — `value`, очищенный Схемой (`skeleton.ts`), а не как есть:
|
|
1520
|
+
до эпика `value` шёл в страницу только через разбор Схемой, и
|
|
1521
|
+
Скелет этого не ломает. На сервере и до гидратации — пусто.
|
|
1522
|
+
*/
|
|
1523
|
+
<div
|
|
1524
|
+
{...surfaceAttributes(surface)}
|
|
1525
|
+
className={documentClass}
|
|
1526
|
+
dangerouslySetInnerHTML={{ __html: skeleton }}
|
|
1527
|
+
/>
|
|
1528
|
+
)}
|
|
1529
|
+
{source && (
|
|
1530
|
+
/*
|
|
1531
|
+
Поле HTML-режима на месте Документа. Отступы — как у области
|
|
1532
|
+
Документа, роли `--rte-*` и вложенная тема листа — те же, что у
|
|
1533
|
+
него, а поле на листе остаётся тёмным, как везде. Высота — не
|
|
1534
|
+
ниже Документа при входе, дальше растёт по содержимому (зеркало),
|
|
1535
|
+
растягивается по вертикали рукой.
|
|
1536
|
+
|
|
1537
|
+
Имя — из каталога, описание и невалидность — те же, что у
|
|
1538
|
+
Документа: подсказка и ошибка `FormField` не теряются при смене
|
|
1539
|
+
режима. Автоисправления выключены — код ими портится. Tab
|
|
1540
|
+
нативный: табуляцию поле не вставляет, ловушки клавиатуры нет.
|
|
1541
|
+
*/
|
|
1542
|
+
<div
|
|
1543
|
+
{...surfaceAttributes(surface)}
|
|
1544
|
+
className={cn(
|
|
1545
|
+
"grid",
|
|
1546
|
+
surface === "paper" ? EDITOR_PAPER_TOKENS_CLASS : EDITOR_TOKENS_CLASS,
|
|
1547
|
+
surface === "paper" ? "my-3" : "py-2.5"
|
|
1548
|
+
)}
|
|
1549
|
+
style={{ minHeight: source.minHeight }}
|
|
1550
|
+
>
|
|
1551
|
+
<textarea
|
|
1552
|
+
ref={sourceFieldRef}
|
|
1553
|
+
value={source.text}
|
|
1554
|
+
aria-label={messages.editor.sourceField}
|
|
1555
|
+
aria-describedby={describedBy}
|
|
1556
|
+
aria-invalid={invalid || undefined}
|
|
1557
|
+
aria-required={required || undefined}
|
|
1558
|
+
spellCheck={false}
|
|
1559
|
+
autoCapitalize="off"
|
|
1560
|
+
autoCorrect="off"
|
|
1561
|
+
autoComplete="off"
|
|
1562
|
+
dir="ltr"
|
|
1563
|
+
disabled={disabled}
|
|
1564
|
+
data-disable-focus-ring="true"
|
|
1565
|
+
onChange={(event) => {
|
|
1566
|
+
const text = event.target.value;
|
|
1567
|
+
sourceTextRef.current = text;
|
|
1568
|
+
setSource((previous) => previous && { ...previous, text });
|
|
1569
|
+
if (editor) syncValidity(editor);
|
|
1570
|
+
}}
|
|
1571
|
+
onBlur={applySource}
|
|
1572
|
+
/*
|
|
1573
|
+
`Alt+F10` живёт в keymap движка, а фокус здесь — в
|
|
1574
|
+
`textarea`, мимо ProseMirror. Панель же объявляет сочетание
|
|
1575
|
+
(`aria-keyshortcuts`): из поля HTML оно обязано работать так
|
|
1576
|
+
же, как из Документа.
|
|
1577
|
+
*/
|
|
1578
|
+
onKeyDown={(event) => {
|
|
1579
|
+
if (
|
|
1580
|
+
event.key === "F10" &&
|
|
1581
|
+
event.altKey &&
|
|
1582
|
+
!event.ctrlKey &&
|
|
1583
|
+
!event.metaKey &&
|
|
1584
|
+
!event.shiftKey &&
|
|
1585
|
+
focusToolbarRef.current()
|
|
1586
|
+
) {
|
|
1587
|
+
event.preventDefault();
|
|
1588
|
+
}
|
|
1589
|
+
}}
|
|
1590
|
+
className={cn(SOURCE_BOX_CLASS, SOURCE_FIELD_CLASS)}
|
|
1591
|
+
/>
|
|
1592
|
+
<div aria-hidden className={cn(SOURCE_BOX_CLASS, "invisible border-transparent")}>
|
|
1593
|
+
{source.text + "\n"}
|
|
1594
|
+
</div>
|
|
1595
|
+
</div>
|
|
1596
|
+
)}
|
|
1597
|
+
{editor && !readOnly && !sourceOpen && (
|
|
1598
|
+
<BlockHandle editor={editor} tools={enabledTools} openRef={openBlockMenuRef} />
|
|
1599
|
+
)}
|
|
1600
|
+
</div>
|
|
1601
|
+
{editor && !sourceOpen && slash.element}
|
|
1602
|
+
{editor && !sourceOpen && triggerMenu.element}
|
|
1603
|
+
{editor && bubbleShown && !readOnly && !sourceOpen && (
|
|
1604
|
+
<SelectionBubble
|
|
1605
|
+
editor={editor}
|
|
1606
|
+
tools={enabledTools}
|
|
1607
|
+
disabled={disabled}
|
|
1608
|
+
onCustomColor={openCustomColor}
|
|
1609
|
+
keyboardTarget={toolbarMode === "bubble"}
|
|
1610
|
+
scrollTarget={scrollTarget}
|
|
1611
|
+
/>
|
|
1612
|
+
)}
|
|
1613
|
+
{editor && toolbarMode === "floating" && !readOnly && (
|
|
1614
|
+
<FloatingToolbar
|
|
1615
|
+
editor={editor}
|
|
1616
|
+
tools={enabledTools}
|
|
1617
|
+
disabled={disabled}
|
|
1618
|
+
onInsertTable={() => setTableDialogOpen(true)}
|
|
1619
|
+
scrollTarget={scrollTarget}
|
|
1620
|
+
/>
|
|
1621
|
+
)}
|
|
1622
|
+
{editor && TableInsertDialog && enabledTools.has("table") && !readOnly && (
|
|
1623
|
+
<TableInsertDialog
|
|
1624
|
+
editor={editor}
|
|
1625
|
+
open={tableDialogOpen}
|
|
1626
|
+
onClose={() => setTableDialogOpen(false)}
|
|
1627
|
+
/>
|
|
1628
|
+
)}
|
|
1629
|
+
{editor && toolPopover && (
|
|
1630
|
+
<SelectionPopover
|
|
1631
|
+
editor={editor}
|
|
1632
|
+
request={toolPopover.request}
|
|
1633
|
+
open={toolPopover.open}
|
|
1634
|
+
onOpenChange={(open) => setToolPopover((prev) => prev && { ...prev, open })}
|
|
1635
|
+
/>
|
|
1636
|
+
)}
|
|
1637
|
+
{editor && textCardEntries.length > 0 && (
|
|
1638
|
+
<Suspense fallback={null}>
|
|
1639
|
+
<TextCard
|
|
1640
|
+
editor={editor}
|
|
1641
|
+
entries={textCardEntries}
|
|
1642
|
+
enabled={!disabled && !sourceOpen}
|
|
1643
|
+
readOnly={readOnly}
|
|
1644
|
+
rootRef={rootRef}
|
|
1645
|
+
controlRef={textCardRef}
|
|
1646
|
+
/>
|
|
1647
|
+
</Suspense>
|
|
1648
|
+
)}
|
|
1649
|
+
{editor && customColor && (
|
|
1650
|
+
<Suspense fallback={null}>
|
|
1651
|
+
<CustomColorPopover
|
|
1652
|
+
editor={editor}
|
|
1653
|
+
kind={customColor.kind}
|
|
1654
|
+
open={customColor.open}
|
|
1655
|
+
onOpenChange={(open) => setCustomColor((prev) => prev && { ...prev, open })}
|
|
1656
|
+
/>
|
|
1657
|
+
</Suspense>
|
|
1658
|
+
)}
|
|
1659
|
+
{editor && enabledTools.has("image") && !readOnly && !sourceOpen && (
|
|
1660
|
+
<ImageToolbar
|
|
1661
|
+
editor={editor}
|
|
1662
|
+
disabled={disabled}
|
|
1663
|
+
onEdit={() => setImageOpen(true)}
|
|
1664
|
+
scrollTarget={scrollTarget}
|
|
1665
|
+
/>
|
|
1666
|
+
)}
|
|
1667
|
+
{editor && enabledTools.has("image") && (
|
|
1668
|
+
<ImagePopover
|
|
1669
|
+
editor={editor}
|
|
1670
|
+
open={imageOpen}
|
|
1671
|
+
onOpenChange={setImageOpen}
|
|
1672
|
+
canUpload={onUploadImage != null}
|
|
1673
|
+
/>
|
|
1674
|
+
)}
|
|
1675
|
+
{resizable && (
|
|
1676
|
+
<FieldResizer
|
|
1677
|
+
area={scrollArea}
|
|
1678
|
+
height={areaHeight}
|
|
1679
|
+
onHeight={setAreaHeight}
|
|
1680
|
+
disabled={disabled}
|
|
1681
|
+
/>
|
|
1682
|
+
)}
|
|
1683
|
+
<FieldNoticeView
|
|
1684
|
+
notice={
|
|
1685
|
+
toolsError || loadFailed
|
|
1686
|
+
? { tone: "error", text: messages.editor.toolsFailed }
|
|
1687
|
+
: notice
|
|
1688
|
+
}
|
|
1689
|
+
action={
|
|
1690
|
+
loadFailed && (
|
|
1691
|
+
<Button size="sm" variant="outline" onClick={retryLoads}>
|
|
1692
|
+
{messages.editor.retry}
|
|
1693
|
+
</Button>
|
|
1694
|
+
)
|
|
1695
|
+
}
|
|
1696
|
+
/>
|
|
1697
|
+
<StatusLine status={status} counter={counter} counterId={counterId} />
|
|
1698
|
+
</div>
|
|
1699
|
+
{validatable && (
|
|
1700
|
+
/*
|
|
1701
|
+
Прокси для проверки ограничений браузера. `<input type="hidden">`
|
|
1702
|
+
из неё ИСКЛЮЧЁН по спецификации (barred from constraint
|
|
1703
|
+
validation: `willValidate === false`, `setCustomValidity` на нём
|
|
1704
|
+
ничего не блокирует), а `contenteditable` — не form-associated
|
|
1705
|
+
элемент вовсе. Поэтому `required` держит отдельное поле: оно
|
|
1706
|
+
обычное текстовое, без `name`, поэтому в `FormData` не попадает —
|
|
1707
|
+
значение по-прежнему несёт скрытое поле ниже.
|
|
1708
|
+
|
|
1709
|
+
Валидность задаёт `setCustomValidity` (`syncValidity`), а не атрибут
|
|
1710
|
+
`required`: сообщение берётся из каталога кита, а не из языка
|
|
1711
|
+
браузера. Невидимое поле остаётся фокусируемым (`tabIndex=-1`,
|
|
1712
|
+
не `display:none`) — иначе браузер не покажет пузырь и напишет в
|
|
1713
|
+
консоль «An invalid form control is not focusable». Пузырь встаёт у
|
|
1714
|
+
рамки поля.
|
|
1715
|
+
|
|
1716
|
+
Когда браузер отклоняет отправку, он ставит фокус на первое
|
|
1717
|
+
невалидное поле — здесь на прокси; оттуда фокус пересылается в
|
|
1718
|
+
документ. `invalid` ловит то же ещё до этого: так фокус попадёт в
|
|
1719
|
+
редактор и там, где браузер сам фокус не двигает.
|
|
1720
|
+
*/
|
|
1721
|
+
<input
|
|
1722
|
+
ref={proxyRef}
|
|
1723
|
+
type="text"
|
|
1724
|
+
tabIndex={-1}
|
|
1725
|
+
aria-hidden="true"
|
|
1726
|
+
autoComplete="off"
|
|
1727
|
+
className="pointer-events-none absolute right-0 bottom-0 left-0 h-px opacity-0"
|
|
1728
|
+
onInvalid={focusField}
|
|
1729
|
+
onFocus={focusField}
|
|
1730
|
+
/>
|
|
1731
|
+
)}
|
|
1732
|
+
{name != null && (
|
|
1733
|
+
<input
|
|
1734
|
+
ref={hiddenRef}
|
|
1735
|
+
type="hidden"
|
|
1736
|
+
name={name}
|
|
1737
|
+
defaultValue={initial}
|
|
1738
|
+
// Выключенное поле не уходит в форму — как нативное. Поле только
|
|
1739
|
+
// для чтения уходит: это показанное значение, а не недоступный
|
|
1740
|
+
// контрол.
|
|
1741
|
+
disabled={disabled}
|
|
1742
|
+
/>
|
|
1743
|
+
)}
|
|
1744
|
+
</div>
|
|
1745
|
+
);
|
|
1746
|
+
}
|
|
1747
|
+
);
|