@olddevs/ui 4.5.0 → 4.6.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 +24 -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/toc/RichTextToc.d.ts.map +1 -1
- package/dist/editor/features/toc/RichTextToc.js +9 -2
- package/dist/editor/features/toc/RichTextToc.js.map +1 -1
- 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 +56 -56
- 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 +3 -3
- package/docs/api/migration-notes.md +2 -2
- package/docs/components/content/rich-text-view.en.md +18 -12
- package/docs/components/content/rich-text-view.md +17 -11
- package/docs/components/inputs/rich-text-editor.en.md +140 -87
- package/docs/components/inputs/rich-text-editor.md +139 -86
- 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 +80 -52
- package/docs/glossary.md +79 -51
- package/docs/icons.en.md +4 -1
- package/docs/icons.md +3 -0
- 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/RichTextToc.tsx +14 -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
|
@@ -92,17 +92,17 @@ export default async function ArticlePage({ id }: { id: string }) {
|
|
|
92
92
|
|
|
93
93
|
<!-- allow-list -->
|
|
94
94
|
|
|
95
|
-
| Что | Разрешено
|
|
96
|
-
| -------- |
|
|
97
|
-
| Блоки | `p`, `h1`, `h2`, `h3`, `h4`, `ul`, `ol`, `li`, `blockquote`, `hr`, `pre`, `table`, `tbody`, `tr`, `th`, `td`; `label`, `input`, `span` — только внутри пункта чек-листа; `div` — там же, а ещё Раскладка и её колонки (Раскладка — только на верхнем уровне, колонка — только прямо в ней) и Обёртка (на верхнем уровне и прямо в колонке, не в другой Обёртке); `figure` — картинка, внутри неё `img` и необязательная `figcaption` (вне `figure` их нет)
|
|
98
|
-
| Метки | `strong`, `em`, `u`, `s`, `code`, `sup`, `sub`, `mark` (только с цветом), `br`, `a`
|
|
99
|
-
| Атрибуты | `ol[start]` — только когда нумерация не с 1; `ul[data-type]`, `li[data-type]`, `li[data-checked]` — чек-лист; `input[type]`, `input[checked]` — его флажок; `code[class]` — язык блока кода, только «language-python», «language-typescript», «language-javascript», «language-go», «language-html», «language-json», «language-yaml» или «language-markdown» (без языка класса нет); `span[data-color]`, `mark[data-color]` — цвет текста и маркер, только имена палитры этого тега: на `span` цвета текста, на `mark` маркера; `span[style]`, `mark[style]` — произвольный цвет автора, только «color:#rrggbb» и «background-color:#rrggbb», и не вместе с «data-color»; `p[data-align]`, `h1[data-align]`, `h2[data-align]`, `h3[data-align]`, `h4[data-align]` — выравнивание Блока, по центру или справа; `th[colspan]`, `td[colspan]` — слияние по горизонтали, целое от 2 до 20; `th[rowspan]`, `td[rowspan]` — по вертикали, от 2 до 50; `th[data-align]`, `td[data-align]` — выравнивание столбца, по центру или справа, на каждой его ячейке; `a[href]` — только «http», «https» или «mailto»; `a[rel]` — всегда «noopener noreferrer»; `img[src]` — только абсолютный «http» или «https», без «data:» и «blob:»; `img[alt]` — всегда, пустой у картинки без описания; `img[data-width]` — 50, 75 или 100; `div[data-block]` — Раскладка («layout»), её колонка («column») и Обёртка («wrapper»); `div[data-layout]` — вариант Раскладки, доли колонок в процентах: «100», «50-50», «33-33-33», «25-25-25-25», «60-40» или «40-60»; `div[data-tone]` — тон Обёртки, только на ней: «neutral», «accent», «success», «warning» или «danger» (без тона атрибута нет) |
|
|
95
|
+
| Что | Разрешено |
|
|
96
|
+
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
97
|
+
| Блоки | `p`, `h1`, `h2`, `h3`, `h4`, `ul`, `ol`, `li`, `blockquote`, `hr`, `pre`, `table`, `tbody`, `tr`, `th`, `td`; `label`, `input`, `span` — только внутри пункта чек-листа; `div` — там же, а ещё Раскладка и её колонки (Раскладка — только на верхнем уровне, колонка — только прямо в ней) и Обёртка (на верхнем уровне и прямо в колонке, не в другой Обёртке); `details` — сворачиваемый Блок, внутри него `summary` и `div` содержимого (оба — только прямо в `details`; вне него теги снимаются); `figure` — картинка, внутри неё `img` и необязательная `figcaption` (вне `figure` их нет) |
|
|
98
|
+
| Метки | `strong`, `em`, `u`, `s`, `code`, `sup`, `sub`, `mark` (только с цветом), `br`, `a` |
|
|
99
|
+
| Атрибуты | `ol[start]` — только когда нумерация не с 1; `ul[data-type]`, `li[data-type]`, `li[data-checked]` — чек-лист; `input[type]`, `input[checked]` — его флажок; `code[class]` — язык блока кода, только «language-python», «language-typescript», «language-javascript», «language-go», «language-html», «language-json», «language-yaml» или «language-markdown» (без языка класса нет); `span[data-color]`, `mark[data-color]` — цвет текста и маркер, только имена палитры этого тега: на `span` цвета текста, на `mark` маркера; `span[style]`, `mark[style]` — произвольный цвет автора, только «color:#rrggbb» и «background-color:#rrggbb», и не вместе с «data-color»; `p[data-align]`, `h1[data-align]`, `h2[data-align]`, `h3[data-align]`, `h4[data-align]` — выравнивание Блока, по центру или справа; `th[colspan]`, `td[colspan]` — слияние по горизонтали, целое от 2 до 20; `th[rowspan]`, `td[rowspan]` — по вертикали, от 2 до 50; `th[data-align]`, `td[data-align]` — выравнивание столбца, по центру или справа, на каждой его ячейке; `a[href]` — только «http», «https» или «mailto»; `a[rel]` — всегда «noopener noreferrer»; `img[src]` — только абсолютный «http» или «https», без «data:» и «blob:»; `img[alt]` — всегда, пустой у картинки без описания; `img[data-width]` — 50, 75 или 100; `div[data-block]` — Раскладка («layout»), её колонка («column») и Обёртка («wrapper»); `div[data-layout]` — вариант Раскладки, доли колонок в процентах: «100», «50-50», «33-33-33», «25-25-25-25», «60-40» или «40-60»; `div[data-tone]` — тон Обёртки, только на ней: «neutral», «accent», «success», «warning» или «danger» (без тона атрибута нет); `div[data-type]` — обёртка содержимого сворачиваемого Блока, только значение «detailsContent» и только прямо в `details`; `details[open]` — открытый Блок, только пустой «open» |
|
|
100
100
|
|
|
101
101
|
Пункт чек-листа Tiptap пишет так: `<li data-type="taskItem" data-checked="true"><label><input type="checkbox" checked><span></span></label><div><p>…</p></div></li>`. `sanitizeRichText` пускает `input`, `label`, `span` и `div` только внутри такого пункта, а `input` — только с `type="checkbox"`.
|
|
102
102
|
|
|
103
103
|
Таблицу Редактор пишет так: `<table><tbody><tr><th><p>…</p></th></tr><tr><td colspan="2" data-align="center"><p>…</p></td></tr></tbody></table>`. Строка-заголовок — первая строка из `th`, а у ячейки бывают только три атрибута: `colspan` и `rowspan` (слияние, целое от 2 до `RICH_TEXT_SCHEMA.tableSpans`: 20 по горизонтали и 50 по вертикали; 1 не пишется) и `data-align` (выравнивание столбца, `center` или `right`, на каждой ячейке столбца). Строка, целиком накрытая слиянием сверху, остаётся пустой `<tr></tr>`. `thead`, `tfoot`, `colgroup`, `caption` в Схеме нет, и **DOMPurify по умолчанию вместе с `thead` и `colgroup` убирает и их содержимое**: заголовок таблицы, пришедшей не из Редактора, записанный в `thead`, пропадёт. Редактор `thead` не пишет, так что для его HTML это не потеря. `tbody`, `tr`, `th` и `td` вне таблицы парсер HTML выбрасывает до очистки (текст остаётся), `style` и `colwidth` не проходят, а `colspan` и `rowspan` пропускает только хук `sanitizeRichText`: на `th` и `td` и только цифрами в пределах Схемы; голый конфиг их не знает вовсе. Без такой проверки `colspan="10000"` из HTML не от Редактора развернётся в 10 тыс. пустых ячеек у каждого, кто откроет Документ.
|
|
104
104
|
|
|
105
|
-
Других классов, `style` (кроме произвольного цвета, см. ниже), `aria-*` и `data-*` (кроме восьми имён Схемы: `data-type` и `data-checked` чек-листа, `data-color` цвета, `data-align` выравнивания, `data-width` ширины картинки, `data-block` и `data-layout` Раскладки и `data-tone` Обёртки) в отдаваемом HTML нет. `h1` в Документе бывает только у Редактора с Инструментом `heading1` (по умолчанию в `full`); экран, у которого H1 стоит над Редактором, этот Инструмент выключает.
|
|
105
|
+
Других классов, `style` (кроме произвольного цвета, см. ниже), `aria-*` и `data-*` (кроме восьми имён Схемы: `data-type` чек-листа и обёртки содержимого сворачиваемого Блока, `data-checked` чек-листа, `data-color` цвета, `data-align` выравнивания, `data-width` ширины картинки, `data-block` и `data-layout` Раскладки и `data-tone` Обёртки) в отдаваемом HTML нет. `h1` в Документе бывает только у Редактора с Инструментом `heading1` (по умолчанию в `full`); экран, у которого H1 стоит над Редактором, этот Инструмент выключает.
|
|
106
106
|
|
|
107
107
|
**Картинку** Редактор пишет так: `<figure><img src="https://…" alt="…" data-width="50"><figcaption>…</figcaption></figure>`. `figcaption` есть, только когда подпись не пуста, `data-width` есть только у картинки с заданной шириной (`50`, `75` или `100` процентов ширины Документа, `RICH_TEXT_SCHEMA.imageWidths`; без него размер у картинки свой, не шире Документа), `alt` есть всегда и пуст у картинки без описания. Адрес может быть только абсолютным `http` или `https` (`RICH_TEXT_SCHEMA.imageProtocols`): `data:` (base64) и `blob:` Редактор не пишет никогда, а `style`, `width`, `height` и `class` у картинки не бывает ни у `img`, ни у `figure`. Голый `<img>` вне `figure` Редактор не отдаёт; `sanitizeRichText` его удаляет.
|
|
108
108
|
|
|
@@ -152,7 +152,7 @@ export function sanitizeDocument(html: string): string {
|
|
|
152
152
|
|
|
153
153
|
#### Свои Инструменты: третий аргумент
|
|
154
154
|
|
|
155
|
-
Если Редактор работает со своими Инструментами ([RichTextEditor, «Свой Инструмент»](../inputs/rich-text-editor.md#свой-инструмент)), сервер передаёт очистке **тот же массив `tools`**. Описание своего Инструмента — данные, и модуль с ним импортируется на сервере: очистка читает только правила Схемы (`blocks`, `marks`),
|
|
155
|
+
Если Редактор работает со своими Инструментами ([RichTextEditor, «Свой Инструмент»](../inputs/rich-text-editor.md#свой-инструмент)), сервер передаёт очистке **тот же массив `tools`**. Описание своего Инструмента — данные, и модуль с ним импортируется на сервере: очистка читает только правила Схемы (`blocks`, `marks`), Extensions не трогает. Чтобы в графе сервера не оказался и Tiptap, держите описание в модуле без импорта расширений — Extensions тогда подаются Загрузчиком ([RichTextEditor, «Загрузчик Extensions»](../inputs/rich-text-editor.md#загрузчик-extensions)) или собираются рядом с Редактором.
|
|
156
156
|
|
|
157
157
|
```ts
|
|
158
158
|
import { sanitizeRichText } from "@olddevs/ui/editor/schema";
|
|
@@ -244,6 +244,12 @@ export default async function ArticlePage({ id }: { id: string }) {
|
|
|
244
244
|
|
|
245
245
|
`sanitizeRichText` держит Обёртку там, где её пишет Редактор: на верхнем уровне и прямо в колонке Раскладки, не в другой Обёртке, списке, цитате и таблице; иначе Обёртка снимается, Блоки остаются подряд. Раскладка внутри Обёртки разворачивается в Блоки.
|
|
246
246
|
|
|
247
|
+
## Сворачиваемый Блок
|
|
248
|
+
|
|
249
|
+
Сворачиваемый Блок Редактора (Инструмент `details`, раздел «Сворачиваемый Блок» страницы [RichTextEditor](../inputs/rich-text-editor.md#сворачиваемый-блок)) в показе — **родные `details` и `summary`**: движка и JavaScript для него не нужно, раскрывает и сворачивает сам браузер, с мыши и с клавиатуры (Tab, Enter, пробел), а скринридер читает его как раскрывающийся элемент — ни ролей, ни `aria-*` кит в разметку не добавляет. Блок приходит закрытым; открытым — только тот, что сохранён с `open` (Опция `persist` Редактора). Рамка, отступ и полужирный заголовок — те же, что в Редакторе, маркер `summary` — родной маркер браузера, а Блоки содержимого идут с тем же ритмом, что в Документе. Обёртка содержимого `div[data-type="detailsContent"]` вида не имеет.
|
|
250
|
+
|
|
251
|
+
`sanitizeRichText` держит Блок в форме, которую пишет Редактор: `summary` и обёртка содержимого — только прямо в `details` (иначе тег снимается, Блоки остаются подряд), `open` — только пустой и только на `details`; `iframe` так не открывается. Раскладка или Обёртка внутри содержимого разворачивается в Блоки.
|
|
252
|
+
|
|
247
253
|
## Свой Блок
|
|
248
254
|
|
|
249
255
|
Свой Блок потребителя (`div[data-block="acme_card"]`, раздел «Свой Инструмент» страницы [RichTextEditor](../inputs/rich-text-editor.md#свой-инструмент)) `RichTextView` показывает очищенным HTML и даёт ему **тот же вертикальный ритм, что у абзаца, и больше ничего**: отступ до следующего Блока такой же, как у абзаца на том же месте (в Документе, цитате, ячейке, колонке). Блоки внутри своего Блока-контейнера стоят с ритмом Документа, как в Обёртке; строчное содержимое (текст, Атомы, Метки) отступов не получает. На Листе `surface="paper"` — то же.
|
|
@@ -258,7 +264,7 @@ export default async function ArticlePage({ id }: { id: string }) {
|
|
|
258
264
|
}
|
|
259
265
|
```
|
|
260
266
|
|
|
261
|
-
Вид узла из
|
|
267
|
+
Вид узла из Extensions (React-вид) в `RichTextView` не используется: движка здесь нет. Строчный Атом показывается тем, что лежит в HTML: пустой `span` без текста не виден; оживить Блок в показе можно Островом (раздел ниже). Ритм сверяет `tests/rich-text-paper-css.test.tsx` на настоящем каскаде.
|
|
262
268
|
|
|
263
269
|
## Остров своего Блока
|
|
264
270
|
|
|
@@ -294,18 +300,18 @@ export const acmePlayer: CustomTool = {
|
|
|
294
300
|
|
|
295
301
|
**Как это устроено и почему `RichTextView` остаётся серверным.** Так же, как у «Копировать» (раздел выше): сам компонент без состояния, клиентский кусок — отдельный файл со своей директивой.
|
|
296
302
|
|
|
297
|
-
1. Описание Инструмента целиком (
|
|
303
|
+
1. Описание Инструмента целиком (Extensions, функции) через границу RSC не пройдёт, поэтому `RichTextView` выбирает из `tools` только Острова, причём только тех Блоков, чей `data-block="<имя>"` есть в Документе (`islandsFor`, `src/editor/core/viewIsland.ts`), и отдаёт Острову ссылки на клиентские компоненты и имена атрибутов. Если нет `tools`, нет `island` у Блока или самого Блока в Документе, Острова нет вовсе: ни опорного `<template>` в разметке, ни эффекта, ни загрузки кода Острова потребителя (сервер сериализует ссылку на клиентский компонент, только когда Блок есть). `island` обязан быть компонентом из модуля с `"use client"`: серверный компонент или функция с динамическим импортом в клиентский Остров не передаются.
|
|
298
304
|
2. Серверный HTML Блока приходит всегда. До гидрации, до загрузки Острова и без JS читатель видит его — то есть содержимое Блока как оно сохранено.
|
|
299
305
|
3. После монтирования Остров (`src/editor/ui/BlockIsland.tsx` и тело `BlockIslandSlots.tsx`, свой `"use client"`) находит Блоки **своего** Просмотра так же, как «Копировать» находит гнёзда: от своего опорного `<template>` влево, а не по глобальному `document` — Просмотр в теневом корне или `iframe` работает. В каждом вхождении Блока содержимое заменяется Островом; при смене `tools` (Остров пропал) или уходе Блока содержимое возвращается. Если Блок с Островом стоит внутри другого Блока с Островом, оживает внешний: компонент получает его текст целиком, а внутренний остаётся его содержимым.
|
|
300
306
|
4. Состояние Острова не сбрасывается перерисовкой родителя: Остров ищет Блоки заново только когда сменился Документ, а не `tools` (инлайновый литерал массива у родителя не перемонтирует Остров). Для этого `RichTextView` держит объект `dangerouslySetInnerHTML` стабильным (`useMemo` по Документу): новый объект на каждой перерисовке заставил бы React переписать разметку вместе со вставленными Островами и кнопками «Копировать».
|
|
301
307
|
|
|
302
|
-
**Остров — отдельный компонент**, а не React-вид
|
|
308
|
+
**Остров — отдельный компонент**, а не React-вид из Extensions; Редактор поле `island` не читает.
|
|
303
309
|
|
|
304
310
|
**Цена.** Тело Острова (`BlockIslandSlots.tsx`) подключается лениво (`React.lazy`) и в первую загрузку Просмотра не входит: пока чанк идёт, виден серверный HTML Блока. В статический замер `editorView` попадает только оболочка и выбор Островов — около 0,2 кБ gzip; Tiptap в графе Просмотра по-прежнему нет, это проверяет `tests/rich-text-view.test.tsx`.
|
|
305
311
|
|
|
306
312
|
## Доступность
|
|
307
313
|
|
|
308
|
-
Компонент не добавляет ролей: это обычный `div` с семантическим HTML внутри — заголовки, списки, цитата. Заголовки Документа начинаются с H2, если Редактор работал без `heading1`: страница сама держит H1. Документ с `heading1` содержит собственный `h1`, и тогда страница своего второго не ставит. H1 в `RichTextView` рисуется той же типографикой, что в Редакторе. Если Документ — отдельная область страницы, дайте контейнеру имя через `aria-label` и `role="region"`.
|
|
314
|
+
Компонент не добавляет ролей: это обычный `div` с семантическим HTML внутри — заголовки, списки, цитата. Сворачиваемый Блок — родные `details` и `summary`: раскрытие с клавиатуры (Tab, Enter, пробел) и озвучивание состояния даёт браузер. Заголовки Документа начинаются с H2, если Редактор работал без `heading1`: страница сама держит H1. Документ с `heading1` содержит собственный `h1`, и тогда страница своего второго не ставит. H1 в `RichTextView` рисуется той же типографикой, что в Редакторе. Если Документ — отдельная область страницы, дайте контейнеру имя через `aria-label` и `role="region"`.
|
|
309
315
|
|
|
310
316
|
## Антипаттерны
|
|
311
317
|
|