@olddevs/ui 4.5.1 → 4.6.1
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 +26 -0
- package/dist/editor/RichTextEditor.d.ts +2 -2
- package/dist/editor/RichTextEditor.d.ts.map +1 -1
- package/dist/editor/RichTextEditor.js +3 -0
- package/dist/editor/RichTextEditor.js.map +1 -1
- package/dist/editor/core/blockTypes.d.ts +2 -8
- package/dist/editor/core/blockTypes.d.ts.map +1 -1
- package/dist/editor/core/blockTypes.js +11 -54
- package/dist/editor/core/blockTypes.js.map +1 -1
- package/dist/editor/core/containers.d.ts.map +1 -1
- package/dist/editor/core/containers.js +1 -0
- package/dist/editor/core/containers.js.map +1 -1
- package/dist/editor/core/customMarkdown.js +1 -1
- package/dist/editor/core/customMarkdown.js.map +1 -1
- package/dist/editor/core/customTool.d.ts +6 -6
- package/dist/editor/core/customTool.d.ts.map +1 -1
- package/dist/editor/core/customToolEngine.d.ts +2 -2
- package/dist/editor/core/extensions.d.ts +7 -2
- package/dist/editor/core/extensions.d.ts.map +1 -1
- package/dist/editor/core/extensions.js +96 -64
- package/dist/editor/core/extensions.js.map +1 -1
- package/dist/editor/core/fieldNotice.d.ts +1 -1
- package/dist/editor/core/insertItems.d.ts +5 -28
- package/dist/editor/core/insertItems.d.ts.map +1 -1
- package/dist/editor/core/insertItems.js +3 -94
- package/dist/editor/core/insertItems.js.map +1 -1
- package/dist/editor/core/insertMenuTool.d.ts +13 -0
- package/dist/editor/core/insertMenuTool.d.ts.map +1 -0
- package/dist/editor/core/insertMenuTool.js +20 -0
- package/dist/editor/core/insertMenuTool.js.map +1 -0
- package/dist/editor/core/schema.d.ts +20 -5
- package/dist/editor/core/schema.d.ts.map +1 -1
- package/dist/editor/core/schema.js +18 -3
- package/dist/editor/core/schema.js.map +1 -1
- package/dist/editor/core/shortcuts.d.ts +56 -5
- package/dist/editor/core/shortcuts.d.ts.map +1 -1
- package/dist/editor/core/shortcuts.js +91 -156
- package/dist/editor/core/shortcuts.js.map +1 -1
- package/dist/editor/core/skeleton.d.ts +1 -1
- package/dist/editor/core/skeleton.d.ts.map +1 -1
- package/dist/editor/core/skeleton.js +1 -0
- package/dist/editor/core/skeleton.js.map +1 -1
- package/dist/editor/core/toolButtons.d.ts +3 -3
- package/dist/editor/core/toolDefinition.d.ts +3 -3
- package/dist/editor/core/toolDescriptor.d.ts +49 -30
- package/dist/editor/core/toolDescriptor.d.ts.map +1 -1
- package/dist/editor/core/toolDescriptor.js +2 -5
- package/dist/editor/core/toolDescriptor.js.map +1 -1
- package/dist/editor/core/toolLoader.d.ts +1 -1
- package/dist/editor/core/toolLoader.d.ts.map +1 -1
- package/dist/editor/core/toolOptions.d.ts +19 -2
- package/dist/editor/core/toolOptions.d.ts.map +1 -1
- package/dist/editor/core/toolOptions.js.map +1 -1
- package/dist/editor/core/tools.d.ts +10 -2
- package/dist/editor/core/tools.d.ts.map +1 -1
- package/dist/editor/core/tools.js +1 -0
- package/dist/editor/core/tools.js.map +1 -1
- package/dist/editor/features/builtins.d.ts +6 -8
- package/dist/editor/features/builtins.d.ts.map +1 -1
- package/dist/editor/features/builtins.js +48 -21
- package/dist/editor/features/builtins.js.map +1 -1
- package/dist/editor/features/code/codeBlockTool.d.ts +5 -6
- package/dist/editor/features/code/codeBlockTool.d.ts.map +1 -1
- package/dist/editor/features/code/codeBlockTool.js +10 -1
- package/dist/editor/features/code/codeBlockTool.js.map +1 -1
- package/dist/editor/features/color/colorTools.d.ts +14 -0
- package/dist/editor/features/color/colorTools.d.ts.map +1 -0
- package/dist/editor/features/color/colorTools.js +39 -0
- package/dist/editor/features/color/colorTools.js.map +1 -0
- package/dist/editor/features/details/details.d.ts +68 -0
- package/dist/editor/features/details/details.d.ts.map +1 -0
- package/dist/editor/features/details/details.js +237 -0
- package/dist/editor/features/details/details.js.map +1 -0
- package/dist/editor/features/details/detailsMarkdown.d.ts +17 -0
- package/dist/editor/features/details/detailsMarkdown.d.ts.map +1 -0
- package/dist/editor/features/details/detailsMarkdown.js +84 -0
- package/dist/editor/features/details/detailsMarkdown.js.map +1 -0
- package/dist/editor/features/details/detailsTool.d.ts +16 -0
- package/dist/editor/features/details/detailsTool.d.ts.map +1 -0
- package/dist/editor/features/details/detailsTool.js +39 -0
- package/dist/editor/features/details/detailsTool.js.map +1 -0
- package/dist/editor/features/emoji/emojiTool.d.ts +1 -1
- package/dist/editor/features/heading/headingTool.d.ts +18 -0
- package/dist/editor/features/heading/headingTool.d.ts.map +1 -0
- package/dist/editor/features/heading/headingTool.js +59 -0
- package/dist/editor/features/heading/headingTool.js.map +1 -0
- package/dist/editor/features/history/historyTool.d.ts +15 -0
- package/dist/editor/features/history/historyTool.d.ts.map +1 -0
- package/dist/editor/features/history/historyTool.js +28 -0
- package/dist/editor/features/history/historyTool.js.map +1 -0
- package/dist/editor/features/image/imageTool.d.ts +19 -0
- package/dist/editor/features/image/imageTool.d.ts.map +1 -0
- package/dist/editor/features/image/imageTool.js +28 -0
- package/dist/editor/features/image/imageTool.js.map +1 -0
- package/dist/editor/features/layout/layoutTool.d.ts +11 -0
- package/dist/editor/features/layout/layoutTool.d.ts.map +1 -0
- package/dist/editor/features/layout/layoutTool.js +20 -0
- package/dist/editor/features/layout/layoutTool.js.map +1 -0
- package/dist/editor/features/lists/listTools.d.ts +15 -0
- package/dist/editor/features/lists/listTools.d.ts.map +1 -0
- package/dist/editor/features/lists/listTools.js +78 -0
- package/dist/editor/features/lists/listTools.js.map +1 -0
- package/dist/editor/features/marks/markTools.d.ts +16 -0
- package/dist/editor/features/marks/markTools.d.ts.map +1 -0
- package/dist/editor/features/marks/markTools.js +43 -0
- package/dist/editor/features/marks/markTools.js.map +1 -0
- package/dist/editor/features/search/searchTool.d.ts +1 -1
- package/dist/editor/features/table/tableTool.d.ts +3 -3
- package/dist/editor/features/wrapper/wrapperTool.d.ts +11 -0
- package/dist/editor/features/wrapper/wrapperTool.d.ts.map +1 -0
- package/dist/editor/features/wrapper/wrapperTool.js +32 -0
- package/dist/editor/features/wrapper/wrapperTool.js.map +1 -0
- package/dist/editor/index.d.ts +1 -1
- package/dist/editor/index.d.ts.map +1 -1
- package/dist/editor/index.js.map +1 -1
- package/dist/editor/schema-entry.d.ts +1 -1
- package/dist/editor/styles/prose.d.ts.map +1 -1
- package/dist/editor/styles/prose.js +26 -0
- package/dist/editor/styles/prose.js.map +1 -1
- package/dist/editor/ui/EditorToolbar.d.ts.map +1 -1
- package/dist/editor/ui/EditorToolbar.js +5 -38
- package/dist/editor/ui/EditorToolbar.js.map +1 -1
- package/dist/editor/ui/SelectionBubble.d.ts.map +1 -1
- package/dist/editor/ui/SelectionBubble.js +1 -1
- package/dist/editor/ui/SelectionBubble.js.map +1 -1
- package/dist/editor/ui/ToolButtonView.d.ts.map +1 -1
- package/dist/editor/ui/ToolButtonView.js +1 -1
- package/dist/editor/ui/ToolButtonView.js.map +1 -1
- package/dist/i18n/defaults.d.ts.map +1 -1
- package/dist/i18n/defaults.js +3 -0
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/messages.d.ts +16 -1
- package/dist/i18n/messages.d.ts.map +1 -1
- package/dist/icons.d.ts +8 -1
- package/dist/icons.d.ts.map +1 -1
- package/dist/icons.js +1 -1
- package/dist/icons.js.map +1 -1
- package/dist/locales/ru.d.ts.map +1 -1
- package/dist/locales/ru.js +3 -0
- package/dist/locales/ru.js.map +1 -1
- package/docs/api/editor-extension.en.md +68 -68
- package/docs/api/editor-extension.md +55 -55
- package/docs/api/messages.en.md +4 -1
- package/docs/api/messages.md +3 -0
- package/docs/api/migration-notes.en.md +11 -11
- package/docs/api/migration-notes.md +2 -2
- package/docs/api/utilities.en.md +6 -6
- package/docs/components/actions/split-button.en.md +9 -9
- package/docs/components/content/data-display.en.md +1 -1
- package/docs/components/content/layout-primitives.en.md +3 -3
- package/docs/components/content/rich-text-toc.en.md +1 -1
- package/docs/components/content/rich-text-view.en.md +23 -17
- package/docs/components/content/rich-text-view.md +17 -11
- package/docs/components/content/virtual-grid.en.md +2 -2
- package/docs/components/date-time/date-picker.en.md +1 -1
- package/docs/components/inputs/rich-text-editor.en.md +283 -230
- package/docs/components/inputs/rich-text-editor.md +139 -86
- package/docs/components/navigation/mega-menu.en.md +10 -10
- package/docs/components/overlays/menu.en.md +2 -2
- package/docs/components/overlays/shortcuts-help.en.md +1 -1
- package/docs/components/table/data-table.en.md +3 -3
- package/docs/components/table/filter-bar.en.md +1 -1
- package/docs/components/table/toolbar.en.md +1 -1
- package/docs/conventions.en.md +2 -2
- package/docs/conventions.md +1 -1
- package/docs/getting-started.en.md +9 -9
- package/docs/getting-started.md +8 -8
- package/docs/glossary.en.md +193 -133
- package/docs/glossary.md +191 -132
- package/docs/icons.en.md +12 -9
- package/docs/icons.md +3 -0
- package/docs/palette.en.md +3 -3
- package/docs/theming.en.md +6 -6
- package/package.json +2 -1
- package/src/editor/RichTextEditor.tsx +9 -6
- package/src/editor/core/atomText.ts +2 -2
- package/src/editor/core/blockTypes.ts +19 -83
- package/src/editor/core/containers.ts +4 -2
- package/src/editor/core/customMarkdown.ts +2 -2
- package/src/editor/core/customTool.ts +6 -6
- package/src/editor/core/customToolEngine.ts +9 -9
- package/src/editor/core/extensions.ts +165 -110
- package/src/editor/core/fieldNotice.ts +1 -1
- package/src/editor/core/handle.ts +2 -2
- package/src/editor/core/insertItems.ts +12 -158
- package/src/editor/core/insertMenuTool.ts +32 -0
- package/src/editor/core/jsonDocument.ts +1 -1
- package/src/editor/core/schema.ts +42 -7
- package/src/editor/core/shortcuts.ts +116 -177
- package/src/editor/core/skeleton.ts +4 -3
- package/src/editor/core/toolButtons.ts +3 -3
- package/src/editor/core/toolDefinition.ts +4 -4
- package/src/editor/core/toolDescriptor.ts +65 -52
- package/src/editor/core/toolLoader.ts +3 -3
- package/src/editor/core/toolOptions.ts +21 -2
- package/src/editor/core/tools.ts +10 -1
- package/src/editor/core/viewIsland.ts +1 -1
- package/src/editor/features/builtins.ts +76 -41
- package/src/editor/features/code/codeBlockTool.ts +16 -8
- package/src/editor/features/color/colorTools.ts +68 -0
- package/src/editor/features/details/details.ts +389 -0
- package/src/editor/features/details/detailsMarkdown.ts +158 -0
- package/src/editor/features/details/detailsTool.ts +69 -0
- package/src/editor/features/emoji/emojiTool.tsx +1 -1
- package/src/editor/features/heading/headingTool.ts +96 -0
- package/src/editor/features/history/historyTool.ts +42 -0
- package/src/editor/features/image/imageTool.ts +49 -0
- package/src/editor/features/layout/layoutTool.ts +40 -0
- package/src/editor/features/lists/listTools.ts +112 -0
- package/src/editor/features/marks/markTools.ts +78 -0
- package/src/editor/features/search/searchTool.ts +1 -1
- package/src/editor/features/table/tableTool.ts +3 -3
- package/src/editor/features/toc/tocTool.ts +1 -1
- package/src/editor/features/wrapper/wrapperTool.ts +52 -0
- package/src/editor/index.ts +1 -0
- package/src/editor/schema-entry.ts +1 -1
- package/src/editor/styles/prose.ts +49 -0
- package/src/editor/ui/EditorToolbar.tsx +7 -50
- package/src/editor/ui/SelectionBubble.tsx +2 -5
- package/src/editor/ui/ToolButtonView.tsx +2 -1
- package/src/i18n/defaults.ts +3 -0
- package/src/i18n/messages.ts +14 -1
- package/src/icons.ts +7 -0
- package/src/locales/ru.ts +3 -0
|
@@ -8,7 +8,7 @@ source: src/editor/index.ts
|
|
|
8
8
|
|
|
9
9
|
## Кратко для AI
|
|
10
10
|
|
|
11
|
-
Карта того, чем продукт расширяет `RichTextEditor` из `@olddevs/ui/editor`, и граница стабильности этого API. Единица расширения — **свой Инструмент** (`CustomTool`): описание одной возможности Редактора, которое передаётся в `tools` вперемешку с именами кита. Он несёт Блоки и Метки с правилами Схемы (это данные),
|
|
11
|
+
Карта того, чем продукт расширяет `RichTextEditor` из `@olddevs/ui/editor`, и граница стабильности этого API. Единица расширения — **свой Инструмент** (`CustomTool`): описание одной возможности Редактора, которое передаётся в `tools` вперемешку с именами кита. Он несёт Блоки и Метки с правилами Схемы (это данные), Extensions (расширения Tiptap, сразу или Загрузчиком) и UI-записи: кнопки, Пункты вставки, Действия над Блоком, Карточки у текста. Есть и свой Символ-триггер (`trigger`): `@` для упоминаний открывает тот же список, что `/`. Код экрана управляет полем через Хэндл (`ref`) и хук `useRichTextEditorState`, узнаёт о Готовности и Фокусе поля колбэками `onReady`, `onFocus` и `onBlur`, кладёт своё в Строку статуса (`status`) и сообщает об ошибке командой `showNotice`. У Инструмента три типизированные части, как `options`, `storage` и `commands` у расширения Tiptap: **Опции** (`tool(name, options)` у встроенных `search` и `toc`, `defineTool` у своего), **Состояние** (хук `useRichTextToolState`) и **Команды** (`handle.tool(name)`); их типы собраны в расширяемой карте `RichTextTools`, куда свой Инструмент дописывается через `declare module "@olddevs/ui/editor"`. Тот же массив `tools` понимают серверная очистка (`sanitizeRichText`, `richTextSchema`) и `RichTextView` с Островами. Всё перечисленное подчиняется semver кита с первого выпуска, HTML-соглашение заморожено, мажор Tiptap — мажор кита (раздел «Стабильность»). Подробности каждого пункта живут на странице [RichTextEditor](../components/inputs/rich-text-editor.md); здесь — карта, граница контракта и рецепты.
|
|
12
12
|
|
|
13
13
|
```tsx
|
|
14
14
|
import {
|
|
@@ -39,39 +39,39 @@ import { sanitizeRichText } from "@olddevs/ui/editor/schema";
|
|
|
39
39
|
|
|
40
40
|
- Нужное уже есть среди Инструментов кита ([«Инструменты и Пресеты»](../components/inputs/rich-text-editor.md#инструменты-и-пресеты)): передайте имя в `tools`, своё не пишите.
|
|
41
41
|
- Чтобы спрятать встроенную кнопку или пункт, сузьте `tools`. Подменить встроенный Инструмент по имени нельзя: выключите его и поставьте свой под своим именем.
|
|
42
|
-
- Опции есть только у `search` и `
|
|
42
|
+
- Опции есть только у `search`, `toc` и `details`; `tool("bold", …)` не компилируется. Опции остальных встроенных добавляются по одному, когда о них попросят. Поменять поведение встроенного Инструмента подменой нельзя (`extend()` как у Tiptap нет): описания встроенных наружу не выходят.
|
|
43
43
|
- Сменить Опции у смонтированного поля нельзя: они читаются один раз, при создании движка, вместе с `tools`. Перемонтируйте поле ключом.
|
|
44
44
|
- Произвольный React в строке Панели и в меню нельзя: кит рисует записи сам, React допускается только в содержимом поповера (кнопки, Пункта вставки, Действия над Блоком) и в Карточке у текста.
|
|
45
|
-
- Во вставку и drop пропом вмешаться нельзя: это
|
|
45
|
+
- Во вставку и drop пропом вмешаться нельзя: это делают Extensions своего Инструмента ([«Порядок вставки и drop»](../components/inputs/rich-text-editor.md#порядок-вставки-и-drop)).
|
|
46
46
|
- Чего нет, пока потребители об этом не попросили (ADR-0058, раздел 13): `insertImage` и HTML выделения в Хэндле, `onSelectionChange`, `onPaste`, `onDrop`, `onEmpty`, `onDestroy`, события истории, сигнал об удалённых картинках, запертые Блоки шаблона, вид записи «меню», Карточки и Строка статуса в `RichTextView`. До тех пор у экрана есть `ref.current.editor` и его события.
|
|
47
47
|
- Свои символы-триггеры вроде `@` в этот перечень больше не входят: они поддержаны полем `trigger` Инструмента (ADR-0064, раздел «Символ-триггер» ниже).
|
|
48
48
|
|
|
49
49
|
## Карта API
|
|
50
50
|
|
|
51
|
-
| Что | Где в API
|
|
52
|
-
| ------------------------------------------------ |
|
|
53
|
-
| Свой Инструмент | `CustomTool` в `tools`; Пресеты — `RICH_TEXT_PRESETS`
|
|
54
|
-
| Правила Схемы и HTML-соглашение | `blocks` (`CustomBlock`), `marks` (`CustomMark`), `CustomAttribute`, `PrefixedName`
|
|
55
|
-
| Кнопка | `buttons` (`CustomToolButton`, `CustomToolPopover`, `CustomToolLabel`)
|
|
56
|
-
| Пункт вставки, Действие над Блоком | `insertItems` (`CustomInsertItem`), `blockActions` (`CustomBlockAction`)
|
|
57
|
-
| Символ-триггер | `trigger` (`CustomTrigger`, `TriggerItem`, `TriggerContext`)
|
|
58
|
-
| Карточка у текста | `textCards` (`CustomTextCard`), помощник `markRange`
|
|
59
|
-
| Хэндл и своя панель | `RichTextEditorHandle`, `useRichTextEditorState(ref, selector)`
|
|
60
|
-
| Опции встроенного Инструмента | `tool(name, options)` → `ConfiguredTool` для `search` и `
|
|
61
|
-
| Свой Инструмент с Опциями, Состоянием, Командами | `defineTool({ name, defaults, create, state, commands })` → `ToolDefinition`, `tool(definition, options)`
|
|
62
|
-
| Типы Опций, Состояния и Команд | расширяемый интерфейс `RichTextTools`
|
|
63
|
-
| Состояние Инструмента | `useRichTextToolState(ref, name, selector?)`, `SearchToolState`, `TocToolState`, `TocToolHeading`
|
|
64
|
-
| Команды Инструмента | `handle.tool(name)`, `SearchToolCommands`, `TocToolCommands`
|
|
65
|
-
| События | `onReady`, `onFocus`, `onBlur`; вставка и drop —
|
|
66
|
-
| Строка статуса и Сообщение поля | проп `status`; команда движка `showNotice`, тип `FieldNotice`
|
|
67
|
-
| Загрузчик, Готовность и Скелет | `engine: () => import(…)`
|
|
68
|
-
| Текст атома: `getText`, `maxLength`, пустота | `renderText`
|
|
69
|
-
| Сервер, Markdown, Просмотр | `sanitizeRichText(html, DOMPurify, tools)`, `richTextSchema(tools)`, `RichTextView`
|
|
70
|
-
| Остров своего Блока | `CustomBlock.island`, `CustomIslandProps`, проп `tools` у `RichTextView`
|
|
51
|
+
| Что | Где в API | Подробно |
|
|
52
|
+
| ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
53
|
+
| Свой Инструмент | `CustomTool` в `tools`; Пресеты — `RICH_TEXT_PRESETS` | [«Свой Инструмент»](../components/inputs/rich-text-editor.md#свой-инструмент) |
|
|
54
|
+
| Правила Схемы и HTML-соглашение | `blocks` (`CustomBlock`), `marks` (`CustomMark`), `CustomAttribute`, `PrefixedName` | [«Свой Инструмент»](../components/inputs/rich-text-editor.md#свой-инструмент) |
|
|
55
|
+
| Кнопка | `buttons` (`CustomToolButton`, `CustomToolPopover`, `CustomToolLabel`) | [«Кнопка своего Инструмента»](../components/inputs/rich-text-editor.md#кнопка-своего-инструмента) |
|
|
56
|
+
| Пункт вставки, Действие над Блоком | `insertItems` (`CustomInsertItem`), `blockActions` (`CustomBlockAction`) | [«Пункты вставки и Действия над Блоком»](../components/inputs/rich-text-editor.md#пункты-вставки-и-действия-над-блоком) |
|
|
57
|
+
| Символ-триггер | `trigger` (`CustomTrigger`, `TriggerItem`, `TriggerContext`) | [«Свой символ-триггер»](../components/inputs/rich-text-editor.md#свой-символ-триггер) |
|
|
58
|
+
| Карточка у текста | `textCards` (`CustomTextCard`), помощник `markRange` | [«Карточка у текста»](../components/inputs/rich-text-editor.md#карточка-у-текста) |
|
|
59
|
+
| Хэндл и своя панель | `RichTextEditorHandle`, `useRichTextEditorState(ref, selector)` | [«Хэндл (`ref`) и своя панель вне поля»](../components/inputs/rich-text-editor.md#хэндл-ref-и-своя-панель-вне-поля) |
|
|
60
|
+
| Опции встроенного Инструмента | `tool(name, options)` → `ConfiguredTool` для `search`, `toc` и `details`; `SearchToolOptions`, `TocToolOptions`, `TocLevel`, `DetailsToolOptions` | [«Опции встроенного Инструмента: `tool()`»](../components/inputs/rich-text-editor.md#опции-встроенного-инструмента-tool) |
|
|
61
|
+
| Свой Инструмент с Опциями, Состоянием, Командами | `defineTool({ name, defaults, create, state, commands })` → `ToolDefinition`, `tool(definition, options)` | [«Опции, Состояние и Команды»](editor-extension.md#опции-состояние-и-команды) |
|
|
62
|
+
| Типы Опций, Состояния и Команд | расширяемый интерфейс `RichTextTools` | [«Карта `RichTextTools` и declaration merging»](editor-extension.md#карта-richtexttools-и-declaration-merging) |
|
|
63
|
+
| Состояние Инструмента | `useRichTextToolState(ref, name, selector?)`, `SearchToolState`, `TocToolState`, `TocToolHeading` | [«Состояние Инструмента: `useRichTextToolState`»](../components/inputs/rich-text-editor.md#состояние-инструмента-userichtexttoolstate) |
|
|
64
|
+
| Команды Инструмента | `handle.tool(name)`, `SearchToolCommands`, `TocToolCommands` | [«Команды Инструмента: `handle.tool()`»](../components/inputs/rich-text-editor.md#команды-инструмента-handletool) |
|
|
65
|
+
| События | `onReady`, `onFocus`, `onBlur`; вставка и drop — через Extensions | [«События»](../components/inputs/rich-text-editor.md#события) |
|
|
66
|
+
| Строка статуса и Сообщение поля | проп `status`; команда движка `showNotice`, тип `FieldNotice` | [«Строка статуса и Сообщение поля»](../components/inputs/rich-text-editor.md#строка-статуса-и-сообщение-поля) |
|
|
67
|
+
| Загрузчик, Готовность и Скелет | `engine: () => import(…)` | [«Загрузчик Extensions»](../components/inputs/rich-text-editor.md#загрузчик-extensions), [«Скелет»](../components/inputs/rich-text-editor.md#скелет) |
|
|
68
|
+
| Текст атома: `getText`, `maxLength`, пустота | `renderText` из Extensions | [«Текст атома»](../components/inputs/rich-text-editor.md#текст-атома) |
|
|
69
|
+
| Сервер, Markdown, Просмотр | `sanitizeRichText(html, DOMPurify, tools)`, `richTextSchema(tools)`, `RichTextView` | [«Вне Редактора»](../components/inputs/rich-text-editor.md#вне-редактора-сервер-markdown-и-просмотр), [RichTextView, «Свои Инструменты: третий аргумент»](../components/content/rich-text-view.md#свои-инструменты-третий-аргумент) |
|
|
70
|
+
| Остров своего Блока | `CustomBlock.island`, `CustomIslandProps`, проп `tools` у `RichTextView` | [RichTextView, «Остров своего Блока»](../components/content/rich-text-view.md#остров-своего-блока) |
|
|
71
71
|
|
|
72
72
|
## Свой Инструмент и HTML-соглашение
|
|
73
73
|
|
|
74
|
-
Описание одно, внутри две части. **Правила Схемы** — обычные данные без Tiptap: их читают Редактор, серверная очистка и Просмотр.
|
|
74
|
+
Описание одно, внутри две части. **Правила Схемы** — обычные данные без Tiptap: их читают Редактор, серверная очистка и Просмотр. **Extensions** — расширения Tiptap целиком (Node, Mark, Extension, плагины ProseMirror, React-вид узла): только поведение, а разбор и вывод HTML ставит кит. Обязательны имя, Extensions и правило Схемы для каждого их Node и Mark; остальное — по умолчанию: обычный Блок без Признаков, выгрузка в Markdown его содержимым, ритм абзаца в Просмотре, без UI-записей. Инструмент может не нести Блока вовсе — например, только фильтр вставки.
|
|
75
75
|
|
|
76
76
|
Всё своё называется с Префиксом потребителя через подчёркивание: Инструмент `acme_mergeTag`, атрибут `acme_size`. В именах кита подчёркивания нет, поэтому своё и встроенное не пересекаются ни в массиве `tools`, ни в сохранённом Документе. HTML своего пишет и читает кит:
|
|
77
77
|
|
|
@@ -82,7 +82,7 @@ import { sanitizeRichText } from "@olddevs/ui/editor/schema";
|
|
|
82
82
|
| Метка | `<span data-mark="acme_comment">…</span>` |
|
|
83
83
|
| Атрибут | `data-acme_size="m"` — значение по правилу: список, шаблон или URL |
|
|
84
84
|
|
|
85
|
-
Массив `tools` проверяется один раз, при создании движка (с Загрузчиками — когда они отработали). Имя без префикса, совпадение имён, Node или Mark в
|
|
85
|
+
Массив `tools` проверяется один раз, при создании движка (с Загрузчиками — когда они отработали). Имя без префикса, совпадение имён, Node или Mark в Extensions без правила Схемы (и наоборот), запись без обязательного поля дают ошибку поля «Редактор не запустился», а не тихая потеря Блоков при первом сохранении. Неизвестная **строка** в `tools` по-прежнему отбрасывается молча.
|
|
86
86
|
|
|
87
87
|
## UI-записи
|
|
88
88
|
|
|
@@ -98,7 +98,7 @@ import { sanitizeRichText } from "@olddevs/ui/editor/schema";
|
|
|
98
98
|
- **Подпись** — строка или функция, получающая `{ locale }` (локаль `UiProvider`); каталог сообщений `UiProvider` для сторонних Инструментов не расширяется, переопределение — опциями фабрики Инструмента (рецепт ниже).
|
|
99
99
|
- **Иконка** обязательна у кнопки, пункта и Действия: компонент с контрактом `IconProps` из `@olddevs/ui/icons` или свой.
|
|
100
100
|
- **Поповер** — у кнопки, Пункта вставки и Действия над Блоком ровно одно из `run` и `popover`. Содержимое — функция, получающая `{ editor, close }` (у Действия — ещё `pos` Блока), рамку держит кит: слой оверлея, Стекло всплывающих поверхностей Редактора, стек Escape, имя (подпись записи), возврат фокуса и выделения в Документ. Карточка у текста лежит на том же Стекле, поэтому сплошной фон содержимому не нужен: он закроет подложку. При включённой в системе настройке прозрачности или контраста подложка и так станет сплошной. Поповер встаёт у кнопки (щелчок), у каретки (сочетание кнопки, пункт из «/», «+», «Добавить ›», «Формат ›» и его сочетание) или у Блока (Действие из меню Ручки и его сочетание).
|
|
101
|
-
- **Сочетание** (`shortcut`) — единственный источник: кит вешает клавишу и пишет её в подсказку, `aria-keyshortcuts` и Справочник сочетаний.
|
|
101
|
+
- **Сочетание** (`shortcut`) — единственный источник: кит вешает клавишу и пишет её в подсказку, `aria-keyshortcuts` и Справочник сочетаний. Клавиши, которые вешают Extensions, в справочник не попадают.
|
|
102
102
|
- **Выключенный Инструмент** уносит свои записи отовсюду.
|
|
103
103
|
|
|
104
104
|
## Символ-триггер
|
|
@@ -124,11 +124,11 @@ import { sanitizeRichText } from "@olddevs/ui/editor/schema";
|
|
|
124
124
|
| Состояние | Снимок, который экран читает | Кит у встроенных; поле `state` у `defineTool` | `useRichTextToolState(ref, name, selector?)` |
|
|
125
125
|
| Команды | То, что экран вызывает | Кит у встроенных; поле `commands` у `defineTool` | `ref.current?.tool(name)?.команда()` |
|
|
126
126
|
|
|
127
|
-
|
|
127
|
+
Extensions по-прежнему следуют мажору Tiptap (ADR-0058, п. 12.4). Три новые части от Tiptap не зависят: их типы и поведение подчиняются semver кита.
|
|
128
128
|
|
|
129
129
|
### `tool()`: встроенный Инструмент с Опциями
|
|
130
130
|
|
|
131
|
-
`tool(name, options)` возвращает Настроенный Инструмент — непрозрачную запись для `tools` (её поля читает только кит). Опции есть у `search` (стартовые флажки)
|
|
131
|
+
`tool(name, options)` возвращает Настроенный Инструмент — непрозрачную запись для `tools` (её поля читает только кит). Опции есть у `search` (стартовые флажки), `toc` (`offsetVar`, `levels`, `listWidth`) и `details` (`persist`: пишется ли открытость сворачиваемого Блока в Документ); их значения и пример — на странице [RichTextEditor](../components/inputs/rich-text-editor.md#опции-встроенного-инструмента-tool). Запись включает Инструмент и без имени в `tools`, а имя из Пресета ей уступает. Две записи `tool()` с одним именем — ошибка набора.
|
|
132
132
|
|
|
133
133
|
`tool(definition, options)` настраивает тем же способом определение `defineTool`; Опции берутся из его `defaults`.
|
|
134
134
|
|
|
@@ -137,17 +137,17 @@ import { sanitizeRichText } from "@olddevs/ui/editor/schema";
|
|
|
137
137
|
`defineTool({ name, defaults, create, state?, commands? })` возвращает определение — элемент `tools`, который работает и без `tool()` (с умолчаниями из `defaults`), и с ним.
|
|
138
138
|
|
|
139
139
|
- **`defaults`** — полный набор Опций. Тип Опций выводится из него, второй раз его объявлять не нужно. Литерал расширяется до своего типа (`tone: "info"` станет `string`): нужен union-тип — укажите тип значения, `tone: "info" as "info" | "warning"`.
|
|
140
|
-
- **`create(options)`** отдаёт тело описания — ту же форму, что `CustomTool`, без имени (`CustomToolBody`):
|
|
140
|
+
- **`create(options)`** отдаёт тело описания — ту же форму, что `CustomTool`, без имени (`CustomToolBody`): Extensions, правила Схемы, UI-записи. Зовётся один раз на запись `tools` (определение само или объект, который вернул `tool(definition, options)`): кит запоминает результат по паре «определение и объект Опций записи». Всё, что замкнуто в теле `create` (счётчик, кэш), поэтому общее у всех Редакторов с этой записью. Запись `tool(…)`, созданная в теле компонента, на каждом рендере новая, и Остров в `RichTextView` на каждом рендере перемонтируется: выносите набор `tools` из рендера, в константу модуля или в `useMemo`. Загрузчик Extensions держите константой модуля: кэш загрузчика живёт на самой функции, и новая функция на каждый вызов `create` загружала бы Extensions заново для каждой записи.
|
|
141
141
|
- **`state({ editor, options })`** — Состояние для `useRichTextToolState`. Её зовут при каждой транзакции и при каждом чтении хука, поэтому она должна быть быстрой и без побочных эффектов, а результат — данные без DOM-узлов. Примитивы, массивы и простые объекты сравниваются по значению, поэтому экран перерисовывается, только когда снимок изменился. `Date`, `Map`, `Set` и экземпляры классов сравниваются по ссылке: `state`, который создаёт их заново на каждый вызов, перерисует экран на каждой транзакции. Отдавайте простые данные (`date.toISOString()`) или ту же ссылку, пока данные не изменились. Нет `state` — у Инструмента нет Состояния, и хук отдаёт `null`.
|
|
142
142
|
- **`commands({ editor, options })`** — Команды для `handle.tool(name)`. Их зовут при каждом обращении к Хэндлу: только обёртки над движком, без подписок. Команда возвращает `boolean`, как у встроенных. Нет `commands` — `handle.tool(name)` отдаёт `null`.
|
|
143
143
|
- **Слияние Опций.** Вложенные простые объекты сливаются с умолчаниями, массивы и функции заменяются целиком — как `configure` у Tiptap v3. Значение `undefined` не в счёт: остаётся то, что было. Объект `defaults` не меняется, объект Опций общий для `create`, `state` и `commands`: читайте его, но не меняйте.
|
|
144
144
|
- **Опции читаются один раз**, при создании движка, вместе с набором. Чтобы сменить их, перемонтируйте Редактор ключом (`key`). Значения Опций своего Инструмента проверяет его автор: кит этого не делает.
|
|
145
|
-
- **Все правила своего Инструмента действуют** (ADR-0058): Префикс потребителя в имени, уникальность имени в `tools` (определение дважды, с `tool()` и без, — тоже ошибка набора), проверки набора, Загрузчик
|
|
145
|
+
- **Все правила своего Инструмента действуют** (ADR-0058): Префикс потребителя в имени, уникальность имени в `tools` (определение дважды, с `tool()` и без, — тоже ошибка набора), проверки набора, Загрузчик Extensions. `defineTool` — сахар над той же формой `CustomTool`: отдельного пути сборки у него нет. Обычный объект `CustomTool` в `tools` работает как раньше, без Опций, Состояния и Команд.
|
|
146
146
|
- **Сервер.** `defineTool` и `tool()` живут в модуле без Tiptap и React в рантайме (Tiptap там — только типы), поэтому набор `tools` собирается в серверном модуле, рядом с остальной конфигурацией экрана. Определение содержит функции, как и `CustomTool`, поэтому клиентскому компоненту оно отдаётся вместе с модулем (импортом), а не пропом через границу RSC. Настроенный встроенный Инструмент состоит из данных: при данных в опциях его можно передать и пропом.
|
|
147
147
|
|
|
148
148
|
### Карта `RichTextTools` и declaration merging
|
|
149
149
|
|
|
150
|
-
Типы всех трёх частей собраны в интерфейсе `RichTextTools`, как `Storage` и `Commands` у Tiptap: ключ — имя Инструмента, значение — `{ options; state; commands }`. Кит объявляет в нём `search` и `
|
|
150
|
+
Типы всех трёх частей собраны в интерфейсе `RichTextTools`, как `Storage` и `Commands` у Tiptap: ключ — имя Инструмента, значение — `{ options; state; commands }`. Кит объявляет в нём `search`, `toc` и `details` (у последнего только `options`), свой Инструмент потребитель дописывает сам:
|
|
151
151
|
|
|
152
152
|
```ts
|
|
153
153
|
declare module "@olddevs/ui/editor" {
|
|
@@ -164,7 +164,7 @@ declare module "@olddevs/ui/editor" {
|
|
|
164
164
|
- Из карты выводятся тип снимка в `useRichTextToolState`, тип Команд в `handle.tool()` и Опции `tool()` встроенного. Опции своего Инструмента `tool()` берёт из `defaults` его определения, поэтому поле `options` в карте описывает Опции для читателей карты (`RichTextTools["acme_note"]["options"]`), а `tool()` его не использует.
|
|
165
165
|
- **Типизация добровольна.** Инструмент, не дописанный в карту, работает: его Состояние и Команды имеют тип `unknown`.
|
|
166
166
|
- Файл с `declare module` должен быть модулем (в нём есть `import` или `export`); иначе объявление не дополняет карту, а заводит свой модуль. Положите его рядом с определением Инструмента.
|
|
167
|
-
- Карту не стоит путать с типизацией движка. Кто типизирует
|
|
167
|
+
- Карту не стоит путать с типизацией движка. Кто типизирует Extensions через `declare module "@tiptap/core"` (`Commands`, `Storage`), продолжает так делать: это слой движка и его мажор, а `RichTextTools` — слой кита.
|
|
168
168
|
|
|
169
169
|
### Сквозной пример
|
|
170
170
|
|
|
@@ -300,12 +300,12 @@ export function ArticleBody({ html }: { html: string }) {
|
|
|
300
300
|
|
|
301
301
|
## Загрузчики, Готовность и Скелет
|
|
302
302
|
|
|
303
|
-
|
|
303
|
+
Extensions можно отдать Загрузчиком — `engine: () => import("./engine.js").then((m) => m.engine)`: модуль с описанием тогда импортирует и сервер, а Tiptap уходит в отдельный чанк. Загрузка стартует с первого рендера в браузере, промис кэшируется на функции Загрузчика (поэтому Загрузчик — одна функция на модуль). **Готовность** — движок создан и Загрузчики всех включённых Инструментов, своих и тяжёлых встроенных (`codeBlock`, `table`), отработали. До неё поле — **Скелет**: рамка, место Панели и Документ, очищенный Схемой, без ввода и без прыжка высоты; на сервере — рамка без Документа. Сбой Загрузчика — ошибка поля с «Повторить», Документ остаётся виден. Подробно — [«Загрузчик Extensions»](../components/inputs/rich-text-editor.md#загрузчик-extensions) и [«Скелет»](../components/inputs/rich-text-editor.md#скелет).
|
|
304
304
|
|
|
305
305
|
## Сервер, Markdown, Просмотр и Остров
|
|
306
306
|
|
|
307
307
|
- **Сервер** чистит Документ тем же массивом `tools`: `sanitizeRichText(html, DOMPurify, tools)`, правила данными — `richTextSchema(tools)`. Оба есть и в лёгком `@olddevs/ui/editor/schema` без Tiptap и React — вместе с `markRange`: описание своего Инструмента с Карточкой у текста собирается и в модуле сервера. Имена Инструментов кита в `tools` белый список не сужают: очистка пропускает всё, что пропускает кит. Без третьего аргумента очистка прежняя, и свои Блоки срезаются.
|
|
308
|
-
- **Markdown** — правила в
|
|
308
|
+
- **Markdown** — правила в Extensions (`renderMarkdown`, `markdownTokenizer`, `parseMarkdown`). Без них Блок выгружается содержимым, Атом — Текстом атома, и текст не теряется.
|
|
309
309
|
- **`RichTextView`** показывает свой Блок очищенным HTML с ритмом абзаца; вид — ваш CSS по `data-block`. **Остров** — клиентский компонент в поле `island` Блока: оживает после монтирования и только если такой Блок есть в Документе; `RichTextView` для этого получает тот же `tools`.
|
|
310
310
|
|
|
311
311
|
## Стабильность
|
|
@@ -317,34 +317,34 @@ export function ArticleBody({ html }: { html: string }) {
|
|
|
317
317
|
- описание своего Инструмента (`CustomTool` и его поля, в том числе `trigger`), UI-записи и их Отведённые места, правила Схемы (`CustomBlock`, `CustomMark`, `CustomAttribute`), Признаки Блока;
|
|
318
318
|
- HTML-соглашение (`data-block`, `data-mark`, `data-<префикс>_<имя>`);
|
|
319
319
|
- методы Хэндла, `useRichTextEditorState`, колбэки `onReady`, `onFocus`, `onBlur`, проп `status`, команда `showNotice` и тип `FieldNotice`;
|
|
320
|
-
- Опции, Состояние и Команды (ADR-0069): карта `RichTextTools`, `tool()`, `defineTool()` и его типы (`ToolDefinition`, `ConfiguredTool`), `useRichTextToolState`, `handle.tool()`, а также поля Опций, Состояния и Команд `search` и `toc`;
|
|
320
|
+
- Опции, Состояние и Команды (ADR-0069): карта `RichTextTools`, `tool()`, `defineTool()` и его типы (`ToolDefinition`, `ConfiguredTool`), `useRichTextToolState`, `handle.tool()`, а также поля Опций, Состояния и Команд `search` и `toc` и Опции `details`;
|
|
321
321
|
- третий аргумент `sanitizeRichText` и `richTextSchema`, проп `tools` и Остров у `RichTextView`, `markRange`;
|
|
322
322
|
- имена встроенных Инструментов (`ToolName`) и сам факт Пресетов-массивов `RICH_TEXT_PRESETS` — но не их состав (ниже).
|
|
323
323
|
|
|
324
|
-
**Не входят:** DOM и классы кита вокруг Отведённого места; id встроенных кнопок и пунктов; внутреннее описание встроенных Инструментов (надмножество публичной формы) — наружу оно не экспортируется; точное место записи внутри поверхности; вид Скелета; форма Настроенного Инструмента изнутри (запись непрозрачна, её поля читает кит); момент прокрутки после Команд Поиска (она происходит чуть позже вызова); имена файлов и чанков в `dist`, как любой путь внутри пакета ([«Публичный контракт»](../conventions.md#публичный-контракт)). API сырого `editor` и
|
|
324
|
+
**Не входят:** DOM и классы кита вокруг Отведённого места; id встроенных кнопок и пунктов; внутреннее описание встроенных Инструментов (надмножество публичной формы) — наружу оно не экспортируется; точное место записи внутри поверхности; вид Скелета; форма Настроенного Инструмента изнутри (запись непрозрачна, её поля читает кит); момент прокрутки после Команд Поиска (она происходит чуть позже вызова); имена файлов и чанков в `dist`, как любой путь внутри пакета ([«Публичный контракт»](../conventions.md#публичный-контракт)). API сырого `editor` и Extensions — это API Tiptap, он следует мажору движка.
|
|
325
325
|
|
|
326
326
|
**Сохранённый Документ не ломают ни minor, ни patch.** HTML-соглашение заморожено: `data-block` и `data-mark` расширяются только добавлением. Если форму придётся сменить, это мажор, и до следующего мажора кит читает обе формы — и разбором движка, и санитайзером.
|
|
327
327
|
|
|
328
328
|
**Ломающим считается нарушение контракта, а не сдвиг пикселей:**
|
|
329
329
|
|
|
330
|
-
| Изменение
|
|
331
|
-
|
|
|
332
|
-
| Новое обязательное поле описания
|
|
333
|
-
| Новый Признак Блока или значение по умолчанию, меняющее поведение уже описанных Блоков
|
|
334
|
-
| Отказ от «одно Отведённое место на поверхность» или «свои записи в порядке `tools`»
|
|
335
|
-
| Перенос вида записи на другую поверхность
|
|
336
|
-
| Смена формы HTML-соглашения
|
|
337
|
-
| Новый мажор Tiptap — даже без правок в коде кита: ломаются
|
|
338
|
-
| Удаление Инструмента из Пресета, переименование Инструмента
|
|
339
|
-
| Удаление публичного имени
|
|
340
|
-
| Новое необязательное поле, новый вид записи, метод Хэндла или колбэк
|
|
341
|
-
| Новое поле Опций или Состояния, новая Команда, опция у другого встроенного Инструмента
|
|
342
|
-
| Удаление поля Опций, Состояния или Команды, смена его смысла
|
|
343
|
-
| Новый встроенный Инструмент в Пресете
|
|
344
|
-
| Сдвиг Отведённого места внутри поверхности
|
|
345
|
-
| Подъём нижней границы Tiptap внутри мажора
|
|
346
|
-
| Ужесточение очистки ради безопасности
|
|
347
|
-
| Вид Скелета, DOM и классы вокруг Отведённого места
|
|
330
|
+
| Изменение | Версия |
|
|
331
|
+
| -------------------------------------------------------------------------------------- | -------------------------------------------- |
|
|
332
|
+
| Новое обязательное поле описания | major |
|
|
333
|
+
| Новый Признак Блока или значение по умолчанию, меняющее поведение уже описанных Блоков | major |
|
|
334
|
+
| Отказ от «одно Отведённое место на поверхность» или «свои записи в порядке `tools`» | major |
|
|
335
|
+
| Перенос вида записи на другую поверхность | major |
|
|
336
|
+
| Смена формы HTML-соглашения | major, и до следующего мажора читаются обе |
|
|
337
|
+
| Новый мажор Tiptap — даже без правок в коде кита: ломаются Extensions у потребителя | major |
|
|
338
|
+
| Удаление Инструмента из Пресета, переименование Инструмента | major |
|
|
339
|
+
| Удаление публичного имени | major, после `@deprecated` в minor (ниже) |
|
|
340
|
+
| Новое необязательное поле, новый вид записи, метод Хэндла или колбэк | minor |
|
|
341
|
+
| Новое поле Опций или Состояния, новая Команда, опция у другого встроенного Инструмента | minor |
|
|
342
|
+
| Удаление поля Опций, Состояния или Команды, смена его смысла | major |
|
|
343
|
+
| Новый встроенный Инструмент в Пресете | minor, строка changeset выделена жирным |
|
|
344
|
+
| Сдвиг Отведённого места внутри поверхности | minor со строкой changeset |
|
|
345
|
+
| Подъём нижней границы Tiptap внутри мажора | minor |
|
|
346
|
+
| Ужесточение очистки ради безопасности | patch или minor с заметкой в migration-notes |
|
|
347
|
+
| Вид Скелета, DOM и классы вокруг Отведённого места | вне контракта |
|
|
348
348
|
|
|
349
349
|
- **Мажор Tiptap — мажор кита.** Кит поддерживает один мажор Tiptap за раз; движка нет в манифесте кита, и диапазон версий (`^3.31.4`) держит потребитель по странице [RichTextEditor](../components/inputs/rich-text-editor.md#установка).
|
|
350
350
|
- **Пресет** — «то, что кит считает полным набором», а не замороженный список. Кому нужен стабильный состав, передаёт точный список имён.
|
|
@@ -500,7 +500,7 @@ export const EDITOR_TOOLS = [
|
|
|
500
500
|
|
|
501
501
|
### `modulepreload` для ленивых чанков
|
|
502
502
|
|
|
503
|
-
Предзагрузки кит не публикует. Чанки
|
|
503
|
+
Предзагрузки кит не публикует. Чанки Extensions (своих Загрузчиков и встроенных `codeBlock` и `table` в `full`) начинают грузиться с первого рендера Редактора, и это время закрывает Скелет. Чтобы чанк пришёл вместе со страницей, поставьте на него `<link rel="modulepreload">` (в React 19 — `preloadModule(url)` из `react-dom`); URL с хешем берите из манифеста своего сборщика: имена чанков кита в контракт не входят. Пример — [RichTextEditor, «Загрузчик Extensions»](../components/inputs/rich-text-editor.md#загрузчик-extensions); цена сценариев «старт» и «полный» — [«Размер импорта»](../getting-started.md#размер-импорта).
|
|
504
504
|
|
|
505
505
|
## Ссылки
|
|
506
506
|
|
package/docs/api/messages.en.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
sourceHash:
|
|
2
|
+
sourceHash: 9e3157586a55
|
|
3
3
|
---
|
|
4
4
|
|
|
5
5
|
# Message catalog `UiMessages`
|
|
@@ -276,6 +276,9 @@ The Editor's strings ([rich-text-editor.md](../components/inputs/rich-text-edito
|
|
|
276
276
|
| `wrapperToneName.neutral` | string | Important | Важно |
|
|
277
277
|
| `wrapperToneName.warning` | string | Warning | Внимание |
|
|
278
278
|
| `wrapperToneName.danger` | string | Caution | Осторожно |
|
|
279
|
+
| `details` | string | Collapsible block | Сворачиваемый блок |
|
|
280
|
+
| `unwrapDetails` | string | Remove collapsing | Снять сворачивание |
|
|
281
|
+
| `detailsToggle` | function | — | — |
|
|
279
282
|
| `emoji` | string | Emoji | Эмодзи |
|
|
280
283
|
| `emojiGrid` | string | Choose an emoji | Выберите эмодзи |
|
|
281
284
|
| `emojiCategory.favorites` | string | Favorites | Избранное |
|
package/docs/api/messages.md
CHANGED
|
@@ -278,6 +278,9 @@
|
|
|
278
278
|
| `wrapperToneName.neutral` | строка | Important | Важно |
|
|
279
279
|
| `wrapperToneName.warning` | строка | Warning | Внимание |
|
|
280
280
|
| `wrapperToneName.danger` | строка | Caution | Осторожно |
|
|
281
|
+
| `details` | строка | Collapsible block | Сворачиваемый блок |
|
|
282
|
+
| `unwrapDetails` | строка | Remove collapsing | Снять сворачивание |
|
|
283
|
+
| `detailsToggle` | функция | — | — |
|
|
281
284
|
| `emoji` | строка | Emoji | Эмодзи |
|
|
282
285
|
| `emojiGrid` | строка | Choose an emoji | Выберите эмодзи |
|
|
283
286
|
| `emojiCategory.favorites` | строка | Favorites | Избранное |
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
category: api
|
|
3
3
|
status: stable
|
|
4
4
|
source: src/index.ts
|
|
5
|
-
sourceHash:
|
|
5
|
+
sourceHash: 19d3eaf4181f
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Compatibility and migration notes
|
|
@@ -22,7 +22,7 @@ became relevant.
|
|
|
22
22
|
- When changing a default, accessibility, keyboard behavior or the shape of a
|
|
23
23
|
controlled value: TypeScript may not detect such a migration.
|
|
24
24
|
- When replacing one component with another, for example, when the old API goes away in favor of
|
|
25
|
-
an existing family.
|
|
25
|
+
an existing component family.
|
|
26
26
|
|
|
27
27
|
## When not to use
|
|
28
28
|
|
|
@@ -110,7 +110,7 @@ ref.current?.tool("search")?.open({ replace: true });
|
|
|
110
110
|
|
|
111
111
|
Unchanged: the same panel, the same focus, the same shortcuts. The differences are small: `tool("search")` is `null`
|
|
112
112
|
without the `search` Tool in `tools` and before the engine exists, so a call through `?.` does nothing, just as
|
|
113
|
-
`openSearch` did; `open` returns a `boolean` (`false` in
|
|
113
|
+
`openSearch` did; `open` returns a `boolean` (`false` in Source mode) instead of `void`.
|
|
114
114
|
|
|
115
115
|
### Action before updating
|
|
116
116
|
|
|
@@ -282,12 +282,12 @@ the same page.
|
|
|
282
282
|
`onChange`, `onUploadImage` and `focus()` do not change, and the previous code builds.
|
|
283
283
|
The note is needed because five changes are visible to current consumers
|
|
284
284
|
of `@olddevs/ui/editor`, and one requires installing packages with pnpm. The new API
|
|
285
|
-
(a custom Tool, the Handle, events, the Status
|
|
285
|
+
(a custom Tool, the Handle, events, the Status bar) requires no action — it is on the
|
|
286
286
|
[extension API page](editor-extension.md).
|
|
287
287
|
|
|
288
288
|
### 1. Two new peer packages
|
|
289
289
|
|
|
290
|
-
The blockquote and the divider take their
|
|
290
|
+
The blockquote and the divider take their Extensions from `@tiptap/extension-blockquote` and
|
|
291
291
|
`@tiptap/extension-horizontal-rule` — optional peer dependencies of the
|
|
292
292
|
`@olddevs/ui/editor` entry point with the same `^3.31.4` range (since 3.46.0 the engine
|
|
293
293
|
packages are no longer in the kit manifest; see the entry above).
|
|
@@ -329,7 +329,7 @@ did not fit goes away whole, together with everything after it.
|
|
|
329
329
|
|
|
330
330
|
**Action before updating.** Check the server-side length validation against the kit's rule:
|
|
331
331
|
the Document's text without markup and Block separators, an Atom by the length of its text.
|
|
332
|
-
The kit has no server-side counter: the weight of a custom Atom depends on its
|
|
332
|
+
The kit has no server-side counter: the weight of a custom Atom depends on its Extensions.
|
|
333
333
|
|
|
334
334
|
### 3. Skeleton before Readiness
|
|
335
335
|
|
|
@@ -381,7 +381,7 @@ arrive with the page, add `modulepreload` for them
|
|
|
381
381
|
**What changed.** "Uploading…", "uploaded", an upload refusal, "not an image" and
|
|
382
382
|
"files are not accepted" go through the same channel as the new engine command
|
|
383
383
|
`showNotice`: one place under the field, a new message replaces the previous one, and an error
|
|
384
|
-
(`role="alert"`) stays until the next
|
|
384
|
+
(`role="alert"`) stays until the next User edit. The texts and roles are the same, but the
|
|
385
385
|
live region `role="status"` is now present in **every** Editor, not only with the
|
|
386
386
|
`image` Tool.
|
|
387
387
|
|
|
@@ -578,7 +578,7 @@ is parameterized by your state (`SavedView<T>`) and is not tied to
|
|
|
578
578
|
`TableState`; storage, sharing and the URL stay entirely with you. For details, see the
|
|
579
579
|
[component page](../components/table/saved-views.md).
|
|
580
580
|
|
|
581
|
-
**The `FormField` hint and error reach the react-aria families.** For
|
|
581
|
+
**The `FormField` hint and error reach the react-aria component families.** For
|
|
582
582
|
`Select`, `Combobox`, `DatePicker` and `TagInput`, the description from `FormField` is now tied to
|
|
583
583
|
the field through `aria-describedby`. **This is an accessibility fix, and it changes
|
|
584
584
|
what is announced:** where a hint was visible on screen but did not reach a screen reader, a
|
|
@@ -646,7 +646,7 @@ above came from: `npm run check:dist`, `npm run check:consumer`,
|
|
|
646
646
|
with changesets.
|
|
647
647
|
|
|
648
648
|
**Deliberately postponed:** Figma Code Connect (priority P2 in the specification, only after
|
|
649
|
-
the names and axes stabilize); binding the description for the react-aria families (`Select`,
|
|
649
|
+
the names and axes stabilize); binding the description for the react-aria component families (`Select`,
|
|
650
650
|
`Combobox`, `DatePicker`, `TagInput`) — they have their own description slots; merging
|
|
651
651
|
`UploadState` and `TimelineStatus` — it breaks a public type and waits for a major;
|
|
652
652
|
widening the peer to React 18 — it doubles the consumer's CI build.
|
|
@@ -735,7 +735,7 @@ the description is **supplemented, not replaced**: the attribute holds a list.
|
|
|
735
735
|
|
|
736
736
|
`TextControl` and everything built on it (`MaskedInput`,
|
|
737
737
|
`PhoneInput`, `PasswordInput`, `SearchControl`), plus `NumberInput`, pick up the description. The react-aria
|
|
738
|
-
families (`Select`, `Combobox`, `DatePicker`, `TagInput`) carry their own description slots
|
|
738
|
+
component families (`Select`, `Combobox`, `DatePicker`, `TagInput`) carry their own description slots
|
|
739
739
|
and do not pick up the `FormField` hint yet.
|
|
740
740
|
|
|
741
741
|
**3. A character that does not fit the mask is announced.** A character that did not fit the mask token
|
|
@@ -817,7 +817,7 @@ something read it; `DataTable` became that reader.
|
|
|
817
817
|
`tableStateToParams`, `tableStateFromParams`, `DEFAULT_TABLE_STATE`.
|
|
818
818
|
|
|
819
819
|
**5. Selection is within a page.** "Select all" marks the `items` that arrived;
|
|
820
|
-
the kit does not support selecting the
|
|
820
|
+
the kit does not support selecting all the filtered rows, and the labels about it do not lie.
|
|
821
821
|
If you need selection beyond the page, that is your code, not the kit's.
|
|
822
822
|
|
|
823
823
|
**6. State is carried into the URL without selection and expansion.** The list of keys
|
|
@@ -287,7 +287,7 @@ Shift+F10 — меню ячейки. Новое: кнопки внутри яч
|
|
|
287
287
|
|
|
288
288
|
### 1. Два новых peer-пакета
|
|
289
289
|
|
|
290
|
-
Цитата и разделитель берут
|
|
290
|
+
Цитата и разделитель берут Extensions из `@tiptap/extension-blockquote` и
|
|
291
291
|
`@tiptap/extension-horizontal-rule` — опциональных peer-зависимостей входа
|
|
292
292
|
`@olddevs/ui/editor` с тем же диапазоном `^3.31.4` (с 3.46.0 пакеты движка из
|
|
293
293
|
манифеста кита убраны, см. запись выше).
|
|
@@ -329,7 +329,7 @@ pnpm add @tiptap/extension-blockquote @tiptap/extension-horizontal-rule
|
|
|
329
329
|
|
|
330
330
|
**Действие до обновления.** Серверную проверку длины сверьте с правилом кита:
|
|
331
331
|
текст Документа без разметки и разделителей Блоков, Атом — длиной своего текста.
|
|
332
|
-
Серверного счётчика у кита нет: вес своего Атома зависит от его
|
|
332
|
+
Серверного счётчика у кита нет: вес своего Атома зависит от его Extensions.
|
|
333
333
|
|
|
334
334
|
### 3. Скелет до Готовности
|
|
335
335
|
|
package/docs/api/utilities.en.md
CHANGED
|
@@ -156,10 +156,10 @@ nothing outside React** and subscribes to nothing. The kit provides the shape, a
|
|
|
156
156
|
### Invariants the hook exists to keep
|
|
157
157
|
|
|
158
158
|
- changing **filters, sorting or the page size resets the page** to the first one. Otherwise the user looks at
|
|
159
|
-
page four of
|
|
159
|
+
page four of ten filtered rows, and reads the empty space as "nothing found";
|
|
160
160
|
- **selection is not reset.** The reverse looks tidier, but it breaks a bulk action exactly when that action is
|
|
161
161
|
needed most;
|
|
162
|
-
- density and column visibility do **not** touch the page. A filter narrows the
|
|
162
|
+
- density and column visibility do **not** touch the page. A filter narrows the rows, not the look;
|
|
163
163
|
- an explicit `page` in the same call cancels the reset. This is how the state is restored from the address,
|
|
164
164
|
in full and in one go.
|
|
165
165
|
|
|
@@ -190,7 +190,7 @@ router.replace(`?${tableStateToParams(state)}`);
|
|
|
190
190
|
state. There are two reasons. The list of keys has no length limit. And a link with a selection, opened the next
|
|
191
191
|
day, marks records that no longer exist. Selection is session state, not URL state.
|
|
192
192
|
|
|
193
|
-
The restored state is passed to the hook as a whole, in one `set` call. The invariant "narrowing the
|
|
193
|
+
The restored state is passed to the hook as a whole, in one `set` call. The invariant "narrowing the filtered rows
|
|
194
194
|
resets the page" is cancelled by an explicit page in the same call. Otherwise a link would always open the first
|
|
195
195
|
page.
|
|
196
196
|
|
|
@@ -207,7 +207,7 @@ For how to build a range in the UI, see [FilterBar](../components/table/filter-b
|
|
|
207
207
|
|
|
208
208
|
## Constants, classes and public types: where they are documented
|
|
209
209
|
|
|
210
|
-
These are public exports, but not standalone components. The page of the family they belong to describes them,
|
|
210
|
+
These are public exports, but not standalone components. The page of the component family they belong to describes them,
|
|
211
211
|
so that AI does not treat a class as a general-purpose API:
|
|
212
212
|
|
|
213
213
|
| Exports | Documentation |
|
|
@@ -221,8 +221,8 @@ so that AI does not treat a class as a general-purpose API:
|
|
|
221
221
|
|
|
222
222
|
Each `*Props` type and each component-specific type exported with a component (for example `TableProps`,
|
|
223
223
|
`CommandItem`, `SelectItem`, `KeyboardSelection` or `DrawerSide`) stays part of that component's public API. It
|
|
224
|
-
is described on the page of its family. The [component catalog](../components/index.md) links the public exports
|
|
225
|
-
to the family pages. `src/index.ts` is the final source for all exports.
|
|
224
|
+
is described on the page of its component family. The [component catalog](../components/index.md) links the public exports
|
|
225
|
+
to the component family pages. `src/index.ts` is the final source for all exports.
|
|
226
226
|
|
|
227
227
|
## Related sources and checks
|
|
228
228
|
|
|
@@ -12,7 +12,7 @@ sourceHash: 982b0da00a2f
|
|
|
12
12
|
|
|
13
13
|
## Summary for AI
|
|
14
14
|
|
|
15
|
-
`SplitButton` is a primary action with a menu
|
|
15
|
+
`SplitButton` is a primary action with a menu button for its variants next to it, as **two separate buttons**. The accessible name of the menu button is built from `label`, so `label` is a string, not a node. Menu items go in `children`.
|
|
16
16
|
|
|
17
17
|
## When to use
|
|
18
18
|
|
|
@@ -38,9 +38,9 @@ sourceHash: 982b0da00a2f
|
|
|
38
38
|
|
|
39
39
|
## Public API
|
|
40
40
|
|
|
41
|
-
- `label` is a **string**: the label of the primary action and the source of the name of the menu
|
|
41
|
+
- `label` is a **string**: the label of the primary action and the source of the name of the menu button.
|
|
42
42
|
- `icon` is the icon on the left of the primary action. If a button can enter `loading`, give it an icon from the start: otherwise the loading indicator adds a slot, and the label shifts.
|
|
43
|
-
- `onClick` is called only by the primary action; the menu
|
|
43
|
+
- `onClick` is called only by the primary action; the menu button does not call it.
|
|
44
44
|
- `variant`, `tone`, `size` are the same axes as on `Button` and mean the same thing.
|
|
45
45
|
- `disabled` and `loading` disable **both** buttons and close a menu that is already open — and **do not bring it back** when `disabled` or `loading` is lifted: otherwise the menu would open by itself once a submission ended.
|
|
46
46
|
- `placement` is the side the panel opens to, `bottom end` by default. The side values of `Menu` are narrowed here: a panel that slides sideways lands on top of the primary action.
|
|
@@ -57,20 +57,20 @@ two. These are two separate controls.
|
|
|
57
57
|
|
|
58
58
|
## Why `label` is a string
|
|
59
59
|
|
|
60
|
-
The name of the menu
|
|
60
|
+
The name of the menu button is built from the label. A node would give a name
|
|
61
61
|
that does not exist — or would require a second prop with the same label as a
|
|
62
62
|
string. One label would live in two places and drift apart at the first edit.
|
|
63
63
|
|
|
64
64
|
## Keyboard
|
|
65
65
|
|
|
66
|
-
- **Two tab stops, not one.** Tab goes to the primary action, the next Tab to the menu
|
|
67
|
-
- The menu opens from the menu
|
|
68
|
-
- Escape closes the menu and **returns focus to the menu
|
|
66
|
+
- **Two tab stops, not one.** Tab goes to the primary action, the next Tab to the menu button. The whole rationale of the component rests on this: a single button whose right part opens a menu would leave the second outcome unreachable from the keyboard.
|
|
67
|
+
- The menu opens from the menu button with Enter, Space and Down Arrow — `MenuTrigger` does this.
|
|
68
|
+
- Escape closes the menu and **returns focus to the menu button** instead of sending it to `<body>`.
|
|
69
69
|
- Disabling the component while the menu is open closes the panel: otherwise it would look disabled while the items kept working.
|
|
70
70
|
|
|
71
71
|
## Accessibility and semantics
|
|
72
72
|
|
|
73
|
-
- The menu
|
|
74
|
-
- The menu
|
|
73
|
+
- The menu button's name comes from the message catalog: `splitButton.more({ action })` → "Другие действия: Экспорт" with `@olddevs/ui/locales/ru`, "More actions: Export" without a provider. Without the action's label, several menu buttons on a page are indistinguishable when read aloud by a screen reader.
|
|
74
|
+
- The menu button carries `aria-haspopup` and `aria-expanded` — `MenuTrigger` sets them.
|
|
75
75
|
- The group does not get `role="group"`: an unnamed group is an extra screen reader announcement, and a name would duplicate the button's label.
|
|
76
76
|
- See `src/components/actions/SplitButton.tsx`, `src/components/actions/SplitButton.stories.tsx`, `tests/split-button.test.tsx`, [Menu](../overlays/menu.md).
|
|
@@ -117,7 +117,7 @@ the row: a manual `stopPropagation` is not needed. A detail row and the expander
|
|
|
117
117
|
button do not call the action. A row with an action gets a pointer cursor.
|
|
118
118
|
|
|
119
119
|
**Expansion is the only axis that could not be added as a layer on top.**
|
|
120
|
-
`DataTable` adds column visibility, order, density and the table
|
|
120
|
+
`DataTable` adds column visibility, order, density and the table toolbar (`toolbar`)
|
|
121
121
|
from the outside: they change what goes into `Table` through props. A detail row
|
|
122
122
|
lives **inside** `<tbody>`, between the rows of the react-aria collection, and
|
|
123
123
|
cannot be inserted from the outside. The analysis is in
|
|
@@ -77,9 +77,9 @@ import { AspectRatio, Kbd, ScrollArea, Separator } from "@olddevs/ui";
|
|
|
77
77
|
|
|
78
78
|
### `Kbd`
|
|
79
79
|
|
|
80
|
-
| Prop | Default | Meaning
|
|
81
|
-
| ------ | ------- |
|
|
82
|
-
| `size` | `sm` | `sm` — inside a menu, `md` — in a standalone shortcuts
|
|
80
|
+
| Prop | Default | Meaning |
|
|
81
|
+
| ------ | ------- | ----------------------------------------------------------------------- |
|
|
82
|
+
| `size` | `sm` | `sm` — inside a menu, `md` — in a standalone keyboard shortcuts dialog. |
|
|
83
83
|
|
|
84
84
|
`Kbd` renders the Apple modifier symbols (`⌘ ⌥ ⇧ ⌃`) in a string label in a
|
|
85
85
|
proportional font and everything else in a monospace one. The kit's monospace
|
|
@@ -67,7 +67,7 @@ export function Article({ html }: { html: string }) {
|
|
|
67
67
|
### Which headings are included
|
|
68
68
|
|
|
69
69
|
- `h1`–`h4` at the top level of the Document and inside a Wrapper.
|
|
70
|
-
- Headings in the columns of a
|
|
70
|
+
- Headings in the columns of a Column layout are not included: two headings at the same height in neighboring columns confuse the highlight of the current section. Headings inside custom Blocks and their Islands are not included either: their content is part of the Block, not of the Document's structure.
|
|
71
71
|
- The `levels` prop narrows the set: `levels={[2, 3]}` keeps only `h2` and `h3`. Other levels are in neither the strip nor the list; an empty array leaves no headings at all.
|
|
72
72
|
- With fewer than two headings (after `levels`) the component renders nothing, and the screen's column stays empty.
|
|
73
73
|
|