@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.
Files changed (213) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/editor/RichTextEditor.d.ts +2 -2
  3. package/dist/editor/RichTextEditor.d.ts.map +1 -1
  4. package/dist/editor/RichTextEditor.js +3 -0
  5. package/dist/editor/RichTextEditor.js.map +1 -1
  6. package/dist/editor/core/blockTypes.d.ts +2 -8
  7. package/dist/editor/core/blockTypes.d.ts.map +1 -1
  8. package/dist/editor/core/blockTypes.js +11 -54
  9. package/dist/editor/core/blockTypes.js.map +1 -1
  10. package/dist/editor/core/containers.d.ts.map +1 -1
  11. package/dist/editor/core/containers.js +1 -0
  12. package/dist/editor/core/containers.js.map +1 -1
  13. package/dist/editor/core/customMarkdown.js +1 -1
  14. package/dist/editor/core/customMarkdown.js.map +1 -1
  15. package/dist/editor/core/customTool.d.ts +6 -6
  16. package/dist/editor/core/customTool.d.ts.map +1 -1
  17. package/dist/editor/core/customToolEngine.d.ts +2 -2
  18. package/dist/editor/core/extensions.d.ts +7 -2
  19. package/dist/editor/core/extensions.d.ts.map +1 -1
  20. package/dist/editor/core/extensions.js +96 -64
  21. package/dist/editor/core/extensions.js.map +1 -1
  22. package/dist/editor/core/fieldNotice.d.ts +1 -1
  23. package/dist/editor/core/insertItems.d.ts +5 -28
  24. package/dist/editor/core/insertItems.d.ts.map +1 -1
  25. package/dist/editor/core/insertItems.js +3 -94
  26. package/dist/editor/core/insertItems.js.map +1 -1
  27. package/dist/editor/core/insertMenuTool.d.ts +13 -0
  28. package/dist/editor/core/insertMenuTool.d.ts.map +1 -0
  29. package/dist/editor/core/insertMenuTool.js +20 -0
  30. package/dist/editor/core/insertMenuTool.js.map +1 -0
  31. package/dist/editor/core/schema.d.ts +20 -5
  32. package/dist/editor/core/schema.d.ts.map +1 -1
  33. package/dist/editor/core/schema.js +18 -3
  34. package/dist/editor/core/schema.js.map +1 -1
  35. package/dist/editor/core/shortcuts.d.ts +56 -5
  36. package/dist/editor/core/shortcuts.d.ts.map +1 -1
  37. package/dist/editor/core/shortcuts.js +91 -156
  38. package/dist/editor/core/shortcuts.js.map +1 -1
  39. package/dist/editor/core/skeleton.d.ts +1 -1
  40. package/dist/editor/core/skeleton.d.ts.map +1 -1
  41. package/dist/editor/core/skeleton.js +1 -0
  42. package/dist/editor/core/skeleton.js.map +1 -1
  43. package/dist/editor/core/toolButtons.d.ts +3 -3
  44. package/dist/editor/core/toolDefinition.d.ts +3 -3
  45. package/dist/editor/core/toolDescriptor.d.ts +49 -30
  46. package/dist/editor/core/toolDescriptor.d.ts.map +1 -1
  47. package/dist/editor/core/toolDescriptor.js +2 -5
  48. package/dist/editor/core/toolDescriptor.js.map +1 -1
  49. package/dist/editor/core/toolLoader.d.ts +1 -1
  50. package/dist/editor/core/toolLoader.d.ts.map +1 -1
  51. package/dist/editor/core/toolOptions.d.ts +19 -2
  52. package/dist/editor/core/toolOptions.d.ts.map +1 -1
  53. package/dist/editor/core/toolOptions.js.map +1 -1
  54. package/dist/editor/core/tools.d.ts +10 -2
  55. package/dist/editor/core/tools.d.ts.map +1 -1
  56. package/dist/editor/core/tools.js +1 -0
  57. package/dist/editor/core/tools.js.map +1 -1
  58. package/dist/editor/features/builtins.d.ts +6 -8
  59. package/dist/editor/features/builtins.d.ts.map +1 -1
  60. package/dist/editor/features/builtins.js +48 -21
  61. package/dist/editor/features/builtins.js.map +1 -1
  62. package/dist/editor/features/code/codeBlockTool.d.ts +5 -6
  63. package/dist/editor/features/code/codeBlockTool.d.ts.map +1 -1
  64. package/dist/editor/features/code/codeBlockTool.js +10 -1
  65. package/dist/editor/features/code/codeBlockTool.js.map +1 -1
  66. package/dist/editor/features/color/colorTools.d.ts +14 -0
  67. package/dist/editor/features/color/colorTools.d.ts.map +1 -0
  68. package/dist/editor/features/color/colorTools.js +39 -0
  69. package/dist/editor/features/color/colorTools.js.map +1 -0
  70. package/dist/editor/features/details/details.d.ts +68 -0
  71. package/dist/editor/features/details/details.d.ts.map +1 -0
  72. package/dist/editor/features/details/details.js +237 -0
  73. package/dist/editor/features/details/details.js.map +1 -0
  74. package/dist/editor/features/details/detailsMarkdown.d.ts +17 -0
  75. package/dist/editor/features/details/detailsMarkdown.d.ts.map +1 -0
  76. package/dist/editor/features/details/detailsMarkdown.js +84 -0
  77. package/dist/editor/features/details/detailsMarkdown.js.map +1 -0
  78. package/dist/editor/features/details/detailsTool.d.ts +16 -0
  79. package/dist/editor/features/details/detailsTool.d.ts.map +1 -0
  80. package/dist/editor/features/details/detailsTool.js +39 -0
  81. package/dist/editor/features/details/detailsTool.js.map +1 -0
  82. package/dist/editor/features/emoji/emojiTool.d.ts +1 -1
  83. package/dist/editor/features/heading/headingTool.d.ts +18 -0
  84. package/dist/editor/features/heading/headingTool.d.ts.map +1 -0
  85. package/dist/editor/features/heading/headingTool.js +59 -0
  86. package/dist/editor/features/heading/headingTool.js.map +1 -0
  87. package/dist/editor/features/history/historyTool.d.ts +15 -0
  88. package/dist/editor/features/history/historyTool.d.ts.map +1 -0
  89. package/dist/editor/features/history/historyTool.js +28 -0
  90. package/dist/editor/features/history/historyTool.js.map +1 -0
  91. package/dist/editor/features/image/imageTool.d.ts +19 -0
  92. package/dist/editor/features/image/imageTool.d.ts.map +1 -0
  93. package/dist/editor/features/image/imageTool.js +28 -0
  94. package/dist/editor/features/image/imageTool.js.map +1 -0
  95. package/dist/editor/features/layout/layoutTool.d.ts +11 -0
  96. package/dist/editor/features/layout/layoutTool.d.ts.map +1 -0
  97. package/dist/editor/features/layout/layoutTool.js +20 -0
  98. package/dist/editor/features/layout/layoutTool.js.map +1 -0
  99. package/dist/editor/features/lists/listTools.d.ts +15 -0
  100. package/dist/editor/features/lists/listTools.d.ts.map +1 -0
  101. package/dist/editor/features/lists/listTools.js +78 -0
  102. package/dist/editor/features/lists/listTools.js.map +1 -0
  103. package/dist/editor/features/marks/markTools.d.ts +16 -0
  104. package/dist/editor/features/marks/markTools.d.ts.map +1 -0
  105. package/dist/editor/features/marks/markTools.js +43 -0
  106. package/dist/editor/features/marks/markTools.js.map +1 -0
  107. package/dist/editor/features/search/searchTool.d.ts +1 -1
  108. package/dist/editor/features/table/tableTool.d.ts +3 -3
  109. package/dist/editor/features/toc/RichTextToc.d.ts.map +1 -1
  110. package/dist/editor/features/toc/RichTextToc.js +9 -2
  111. package/dist/editor/features/toc/RichTextToc.js.map +1 -1
  112. package/dist/editor/features/wrapper/wrapperTool.d.ts +11 -0
  113. package/dist/editor/features/wrapper/wrapperTool.d.ts.map +1 -0
  114. package/dist/editor/features/wrapper/wrapperTool.js +32 -0
  115. package/dist/editor/features/wrapper/wrapperTool.js.map +1 -0
  116. package/dist/editor/index.d.ts +1 -1
  117. package/dist/editor/index.d.ts.map +1 -1
  118. package/dist/editor/index.js.map +1 -1
  119. package/dist/editor/schema-entry.d.ts +1 -1
  120. package/dist/editor/styles/prose.d.ts.map +1 -1
  121. package/dist/editor/styles/prose.js +26 -0
  122. package/dist/editor/styles/prose.js.map +1 -1
  123. package/dist/editor/ui/EditorToolbar.d.ts.map +1 -1
  124. package/dist/editor/ui/EditorToolbar.js +5 -38
  125. package/dist/editor/ui/EditorToolbar.js.map +1 -1
  126. package/dist/editor/ui/SelectionBubble.d.ts.map +1 -1
  127. package/dist/editor/ui/SelectionBubble.js +1 -1
  128. package/dist/editor/ui/SelectionBubble.js.map +1 -1
  129. package/dist/editor/ui/ToolButtonView.d.ts.map +1 -1
  130. package/dist/editor/ui/ToolButtonView.js +1 -1
  131. package/dist/editor/ui/ToolButtonView.js.map +1 -1
  132. package/dist/i18n/defaults.d.ts.map +1 -1
  133. package/dist/i18n/defaults.js +3 -0
  134. package/dist/i18n/defaults.js.map +1 -1
  135. package/dist/i18n/messages.d.ts +16 -1
  136. package/dist/i18n/messages.d.ts.map +1 -1
  137. package/dist/icons.d.ts +8 -1
  138. package/dist/icons.d.ts.map +1 -1
  139. package/dist/icons.js +1 -1
  140. package/dist/icons.js.map +1 -1
  141. package/dist/locales/ru.d.ts.map +1 -1
  142. package/dist/locales/ru.js +3 -0
  143. package/dist/locales/ru.js.map +1 -1
  144. package/docs/api/editor-extension.en.md +56 -56
  145. package/docs/api/editor-extension.md +55 -55
  146. package/docs/api/messages.en.md +4 -1
  147. package/docs/api/messages.md +3 -0
  148. package/docs/api/migration-notes.en.md +3 -3
  149. package/docs/api/migration-notes.md +2 -2
  150. package/docs/components/content/rich-text-view.en.md +18 -12
  151. package/docs/components/content/rich-text-view.md +17 -11
  152. package/docs/components/inputs/rich-text-editor.en.md +140 -87
  153. package/docs/components/inputs/rich-text-editor.md +139 -86
  154. package/docs/conventions.en.md +2 -2
  155. package/docs/conventions.md +1 -1
  156. package/docs/getting-started.en.md +9 -9
  157. package/docs/getting-started.md +8 -8
  158. package/docs/glossary.en.md +80 -52
  159. package/docs/glossary.md +79 -51
  160. package/docs/icons.en.md +4 -1
  161. package/docs/icons.md +3 -0
  162. package/package.json +2 -1
  163. package/src/editor/RichTextEditor.tsx +9 -6
  164. package/src/editor/core/atomText.ts +2 -2
  165. package/src/editor/core/blockTypes.ts +19 -83
  166. package/src/editor/core/containers.ts +4 -2
  167. package/src/editor/core/customMarkdown.ts +2 -2
  168. package/src/editor/core/customTool.ts +6 -6
  169. package/src/editor/core/customToolEngine.ts +9 -9
  170. package/src/editor/core/extensions.ts +165 -110
  171. package/src/editor/core/fieldNotice.ts +1 -1
  172. package/src/editor/core/handle.ts +2 -2
  173. package/src/editor/core/insertItems.ts +12 -158
  174. package/src/editor/core/insertMenuTool.ts +32 -0
  175. package/src/editor/core/jsonDocument.ts +1 -1
  176. package/src/editor/core/schema.ts +42 -7
  177. package/src/editor/core/shortcuts.ts +116 -177
  178. package/src/editor/core/skeleton.ts +4 -3
  179. package/src/editor/core/toolButtons.ts +3 -3
  180. package/src/editor/core/toolDefinition.ts +4 -4
  181. package/src/editor/core/toolDescriptor.ts +65 -52
  182. package/src/editor/core/toolLoader.ts +3 -3
  183. package/src/editor/core/toolOptions.ts +21 -2
  184. package/src/editor/core/tools.ts +10 -1
  185. package/src/editor/core/viewIsland.ts +1 -1
  186. package/src/editor/features/builtins.ts +76 -41
  187. package/src/editor/features/code/codeBlockTool.ts +16 -8
  188. package/src/editor/features/color/colorTools.ts +68 -0
  189. package/src/editor/features/details/details.ts +389 -0
  190. package/src/editor/features/details/detailsMarkdown.ts +158 -0
  191. package/src/editor/features/details/detailsTool.ts +69 -0
  192. package/src/editor/features/emoji/emojiTool.tsx +1 -1
  193. package/src/editor/features/heading/headingTool.ts +96 -0
  194. package/src/editor/features/history/historyTool.ts +42 -0
  195. package/src/editor/features/image/imageTool.ts +49 -0
  196. package/src/editor/features/layout/layoutTool.ts +40 -0
  197. package/src/editor/features/lists/listTools.ts +112 -0
  198. package/src/editor/features/marks/markTools.ts +78 -0
  199. package/src/editor/features/search/searchTool.ts +1 -1
  200. package/src/editor/features/table/tableTool.ts +3 -3
  201. package/src/editor/features/toc/RichTextToc.tsx +14 -3
  202. package/src/editor/features/toc/tocTool.ts +1 -1
  203. package/src/editor/features/wrapper/wrapperTool.ts +52 -0
  204. package/src/editor/index.ts +1 -0
  205. package/src/editor/schema-entry.ts +1 -1
  206. package/src/editor/styles/prose.ts +49 -0
  207. package/src/editor/ui/EditorToolbar.tsx +7 -50
  208. package/src/editor/ui/SelectionBubble.tsx +2 -5
  209. package/src/editor/ui/ToolButtonView.tsx +2 -1
  210. package/src/i18n/defaults.ts +3 -0
  211. package/src/i18n/messages.ts +14 -1
  212. package/src/icons.ts +7 -0
  213. package/src/locales/ru.ts +3 -0
package/docs/glossary.md CHANGED
@@ -131,54 +131,82 @@
131
131
  Термины `RichTextEditor` и `RichTextView` (вход `@olddevs/ui/editor`). Здесь особенно легко
132
132
  взять слово из соседнего редактора (плагин, сервис, нода) — оно заводит второй смысл.
133
133
 
134
- | Термин | Значение | Не путать с |
135
- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
136
- | **Редактор** | `RichTextEditor` — поле ввода форматированного текста | Редактором кода: его в ките нет, показ кода — `CodeView` |
137
- | **Просмотр** | `RichTextView` — только чтение сохранённого Документа | `readOnly`-режимом Редактора: тот держит движок, Просмотр — нет |
138
- | **Оглавление** | `RichTextToc`: список заголовков Документа рядом с Просмотром или Редактором. Свёрнуто — полоса штрихов, раскрыто — список, клик по пункту ведёт к заголовку | `Heading` кита и навигацией сайта документации |
139
- | **Документ** | Значение Редактора: HTML-строка, ограниченная Схемой | JSON-деревом ProseMirror в движке — оно внутреннее; наружу оно выходит только JSON-конвертом |
140
- | **JSON-конверт** | Документ как JSON для файла и шаблона: `{ format: "olddevs-rich-text", version, doc }` (`getJSON()`, `setJSON()`, `defaultValue`), без потерь и через Схему | Значением Редактора — значение остаётся HTML; голым деревом `editor.getJSON()` без конверта |
141
- | **Схема** | Белый список Блоков, Меток и атрибутов, которые Редактор принимает и отдаёт | Санитизацией на сервере — её делает потребитель (`sanitizeRichText`) |
142
- | **Блок** | Структурный элемент Документа: абзац, заголовок, список, таблица, картинка… | Меткой |
143
- | **Метка** | Строчное форматирование внутри Блока: жирный, ссылка, цвет… | Блоком |
144
- | **Атом** | Блок или строчный элемент, который выделяется, переносится и удаляется целиком: картинка (подпись внутри неё правится), разделитель, мягкий перенос, упоминание. Всегда делает поле непустым | Пустым Блоком: абзац без текста — не Атом и содержимым не считается |
145
- | **Текст атома** | Строка, которой Атом представлен в тексте Документа: её отдают `getText` и `getSelectedText`, её длина — вес Атома в `maxLength`, ею Атом выгружается в Markdown без своих правил. У картинки — текст подписи, у разделителя — пустая строка | Атрибутом Блока |
146
- | **Раскладка** | Блок из колонок (Инструмент `layout`): шесть вариантов — от одной до четырёх равных колонок, 60/40 и 40/60. Только верхнего уровня, в себя не вкладывается; колонка для своих Блоков — то же, что Документ | Таблицей: у той строки и ячейки данных, а колонки Раскладки — вёрстка Документа. `Grid` кита — сеткой экрана, а не Блоком |
147
- | **Обёртка** | Блок, который собирает группу Блоков (Инструмент `wrapper`, `div` с `data-block="wrapper"`): их двигают, дублируют и удаляют одним Блоком. Без Тона Обёртки своего вида нет — пунктир только в Редакторе. Обёртка и Раскладка в Обёртку не вкладываются | Цитатой: у той свой вид и смысл в Документе, а Обёртка без тона — только группировка |
148
- | **Тон Обёртки** | Оформление Обёртки заметкой (`data-tone`): фон и полоса слева одного из пяти тонов словаря `Tone` — «Заметка», «Совет», «Важно», «Внимание», «Осторожно». Выбирается в «Тон ›» Ручки Блока, одинаков в Редакторе и Просмотре, в Markdown выгружается GitHub alert (то, что GitHub и Notion называют callout) | Тоном Сообщения поля (`status` или `error`). Смыслом: ролей и `aria-*` тон не несёт, смысл заметки пишется словом в тексте |
149
- | **Панель** | Набор кнопок форматирования; вид задаёт `toolbar`. **Фиксированная** (`fixed`, по умолчанию) — над полем, липнет при прокрутке; **плавающая** (`floating`) — те же кнопки над непустым выделением. При `bubble` Панели нет — её место занимает Меню выделения, при `none` нет ни того, ни другого. На сенсорном экране Панель всегда фиксированная | `Toolbar` кита — Примитивом, из которого Панель собрана |
150
- | **Меню вставки** | Список «Добавить» и «Превратить в»: открывается по `/` в тексте и по кнопке «+» | Контекстным меню браузера |
151
- | **Меню выделения** | Компактная плашка на инверсной поверхности над непустым выделением: «¶», списки, жирный, курсив, подчёркнутый, цвет, «…», ссылка, эмодзи; состав задан китом. Стоит вместо Панели при `toolbar="bubble"` и поверх фиксированной Панели — там её выключает `selectionMenu={false}`. На сенсорном экране её нет | Плавающей Панелью: у той полный набор кнопок |
152
- | **Ручка Блока** | «⋮» у Блока с кареткой и её меню действий над Блоком целиком: «Добавить ›», «Формат ›», «Вверх», «Вниз», «Дублировать», «Удалить» | Панелью: та работает с выделением, а не с Блоком |
153
- | **Пункт вставки** | Строка Меню вставки: вставляет Блок или превращает текущий. Один пункт виден и по `/`, и по «+», и в Ручке Блока | Кнопкой Панели |
154
- | **Действие над Блоком** | Пункт меню Ручки Блока, который работает с Блоком целиком, например «Дублировать» | Кнопкой: та работает с выделением |
155
- | **Справочник сочетаний** | Поповер «команда — сочетание» только для чтения за последней кнопкой фиксированной Панели. Строки — команды включённых Инструментов, своих тоже; на телефоне кнопки нет | `CommandPalette` кита: строки Справочника сочетаний не нажимаются. `ShortcutsHelp` кита: тот — сочетания экрана, а не Редактора |
156
- | **HTML-режим** | Режим Инструмента `source`: кнопка «HTML» на фиксированной Панели заменяет Документ полем с его HTML. Текст поля проходит Схему и становится Документом одной правкой — при выходе из режима, `blur`, отправке формы и чтении через Хэндл | HTML-соглашением: то — форма своего в Документе, а не режим. `CodeView`: тот показывает код, а поле HTML правится |
157
- | **Стекло** | Полупрозрачная заливка с размытием фона у всего, что Редактор показывает поверх Документа: плавающая Панель, Меню выделения, меню, поповеры, Карточка у текста. Цвет — токен своей поверхности; при `prefers-reduced-transparency`, `prefers-contrast: more` и на iOS заливка сплошная | `Menu` и `Popover` кита вне Редактора: те остаются сплошными |
158
- | **UI-запись** | Элемент интерфейса своего Инструмента, описанный данными: кнопка, Пункт вставки, Действие над Блоком или Карточка у текста. Рисует её кит в Отведённом месте; выключенный Инструмент убирает и свои записи | React-узлом в интерфейсе: произвольный React допускается только в содержимом поповера кнопки и Карточки у текста |
159
- | **Отведённое место** | Одно место на поверхности, где стоят записи своих Инструментов, в порядке `tools`: группа Панели перед «Отменить», конец раздела Меню вставки, секция Ручки Блока перед «Удалить» | Позицией относительно встроенной кнопки: id встроенных публичным API не являются |
160
- | **Пресет** | Готовый набор встроенных Инструментов: `full` или `basic` (`RICH_TEXT_PRESETS`). Не замороженный список: новый встроенный приходит в него minor-версией | Точным списком `tools`: его состав меняет только экран |
161
- | **Инструмент** | Одна возможность Редактора: её Блоки и Метки, их правила в Схеме и место в интерфейсе, например `table`. Встроенный задаётся именем, свой — описанием | Кнопкой: выключенный Инструмент убирает и Блок из Схемы. Плагином Redactor: тот — класс поведения над DOM без Схемы |
162
- | **Свой Инструмент** | Инструмент, который описывает потребитель (`CustomTool`): правила Схемы данными, Часть для движка и UI-записи. Передаётся в `tools` вперемешку с именами кита | Внутренним описанием кита: то — надмножество публичной формы для встроенных, наружу не экспортируется |
163
- | **Опции Инструмента** | Что экран задаёт Инструменту до создания движка: стартовые флажки Поиска, `offsetVar`, `levels` и `listWidth` Оглавления, `defaults` своего Инструмента (`defineTool`). Экран задаёт их записью `tool(…)`, кит читает один раз, при создании движка | `options` у расширения Tiptap: те задаёт сам автор расширения и читает Часть для движка, а Опции задаёт экран и читает кит. Пропами Редактора (`preset`, `maxHeight`): те настраивают поле, а не Инструмент |
164
- | **Настроенный Инструмент** | Запись `tools`, которую возвращает `tool(name, options)` или `tool(definition, options)`: Инструмент вместе с его Опциями. Включает Инструмент без имени в `tools` и побеждает голое имя из Пресета | Определением `defineTool`: то описывает Инструмент, а Настроенный Инструмент — его включение с Опциями. Описанием встроенного: оно наружу не выходит, запись лишь называет Инструмент и несёт Опции |
165
- | **Состояние Инструмента** | Снимок данных, который экран читает хуком `useRichTextToolState(ref, name)`: у Поиска — открыта ли панель, запрос, число совпадений и текущее, у Оглавления — заголовки и текущий раздел. Перерисовка только при смене снимка | `storage` у расширения Tiptap: то — изменяемое хранилище внутри движка, а Состояние только читается. `useRichTextEditorState`: тот берёт срез живого `editor` Tiptap, а не контракт Инструмента |
166
- | **Команды Инструмента** | Что экран вызывает у Инструмента через `handle.tool(name)`: `tool("search")?.open()`, `tool("toc")?.jumpTo(2)`. Каждая возвращает `boolean`; `null` вместо объекта Команд — Инструмента нет в наборе, у него нет Команд или движок ещё не создан | Методами Хэндла (`insertHTML`, `focus`): те общие для любого `tools`, а Команды есть, только пока Инструмент включён. `editor.commands` и `commands` у Tiptap: те — команды движка, они следуют его мажору |
167
- | **Префикс потребителя** | Начало имени всего своего — Инструмента, его Блоков, Меток и атрибутов — до подчёркивания: `acme_mergeTag`, `data-acme_size`. В именах кита подчёркивания нет, поэтому своё и встроенное не совпадают ни в наборе, ни в Документе | Пресетом: тот — набор встроенных Инструментов, а не пространство имён |
168
- | **HTML-соглашение** | Форма своего в Документе: Блок — `div` или `span` с `data-block`, Метка — `span` с `data-mark`, атрибуты — `data-<префикс>_<имя>`. Заморожено: расширяется только добавлением | Тегами Схемы кита (`p`, `table`, `img`): свой Блок их занять не может |
169
- | **Признак Блока** | Свойство Блока, которое понимает только кит, а не движок: «контейнер» (детям своя Ручка), «можно превратить в», «Атом без меню форматирования» | Атрибутом Блока: тот хранится в Документе |
170
- | **Часть для движка** | То в описании Инструмента, что нужно только живому Редактору: расширения Tiptap и вид узла. Подаётся сразу или Загрузчиком | Правилами Схемы: те — данные, их читают сервер и Просмотр без движка |
171
- | **Загрузчик** | Функция с динамическим импортом вместо Части для движка: `engine: () => import(…)`. Так же грузятся тяжёлые встроенные вне `basic` — Блок кода и таблица | Предзагрузкой (`modulepreload`): её кит не публикует, ставит потребитель |
172
- | **Хэндл** | Императивный доступ кода экрана к Редактору через `ref`: вставка у каретки, чтение, фокус, история, Команды Инструментов (`tool(name)`) | Сервисами Redactor: те — внутренности движка, а не API экрана |
173
- | **Готовность** | Момент, когда движок создан и Загрузчики всех включённых Инструментов, своих и встроенных, отработали: с него методы Хэндла действуют, а не молчат. Наступает один раз за монтаж, о нём сообщает `onReady` | Гидратацией: после неё движок может ещё ждать Загрузчики |
174
- | **Фокус поля** | Фокус внутри Редактора целиком: Документ, Панель, поповеры кита, поле HTML. Переход между ними Фокус поля не теряет; `onFocus` и `onBlur` — о нём | Фокусом Документа (`focus` и `blur` движка): клик в Панель его снимает |
175
- | **Правка автора** | Изменение Документа, равное набору с клавиатуры: шаг истории, `onChange` после задержки, предел символов действует. Сюда же вставка, отмена и повтор из Хэндла | Заменой снаружи |
176
- | **Замена снаружи** | Подмена Документа целиком (`value`, `clear()`, `setMarkdown()`, `setJSON()`): предел символов не режет; `onChange` сразу у `clear()`, `setMarkdown()` и `setJSON()`, на новый `value` не вызывается | Правкой автора |
177
- | **Скелет** | Вид Редактора до Готовности: рамка поля, место Панели и Документ: очищенный Схемой, он выведен статичным HTML с тем же классом и ритмом, что Документ движка, без ввода. На сервере — рамка без Документа. Сбой Загрузчика превращает Скелет в ошибку поля с «Повторить» | Просмотром: тот — отдельный компонент только для чтения, а Скелет — состояние Редактора, которое сменяется движком. Компонентом `Skeleton` кита — заглушкой загрузки |
178
- | **Строка статуса** | Строка внутри рамки поля под Документом: слева содержимое экрана (`status`: число слов, «Сохранено», соавтор), справа счётчик символов кита | Сообщением поля: строка показывает длительное состояние экрана, а не событие |
179
- | **Сообщение поля** | Одно событие, привязанное к полю (`showNotice`): тон `status` (только озвучивается) или `error` (видимая строка под полем до следующей Правки автора). Новое заменяет прежнее | Тостом кита: тот глобален и к полю не привязан |
180
- | **Карточка у текста** | Немодальная карточка под диапазоном Документа, который объявил свой Инструмент (`textCards`): комментарий, подсказка по результатам проверки текста. Открывается кареткой или щелчком, фокус остаётся в тексте | Поповером кнопки: его открывает кнопка, а Карточку — место Документа |
181
- | **Символ-триггер** | Свой символ Инструмента (`trigger`), набор которого в начале Блока или после пробела открывает список пунктов у каретки, как `/`: `@` для упоминаний, `#` для тегов. Выбор заменяет набранное `@запрос` своим узлом | Меню вставки по `/`: то — встроенное, а свой символ задаёт Инструмент |
182
- | **Лист** | Светлая область Документа в любой теме приложения (`surface="paper"`) — для текста, который уйдёт из приложения светлым: письмо, печать, PDF. Панель, меню и рамка поля остаются в теме приложения; Просмотр с тем же `surface` показывает тот же Лист | Темой `light`: та меняет всё приложение, Лист — только Документ |
183
- | **Остров** | Клиентский кусок Просмотра, который после монтирования оживляет Блок в уже показанном HTML: кнопка «Копировать» у Блока кода, `island` своего Блока | Видом узла: тот живёт только в движке Редактора |
184
- | **Гнездо** | Место в показанном HTML, куда Остров монтирует живой элемент: шапка Блока кода, в которую встаёт кнопка «Копировать» | Отведённым местом: то — место в интерфейсе Редактора для записей Инструментов |
134
+ | Термин | Значение | Не путать с |
135
+ | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
136
+ | **Редактор** | `RichTextEditor` — поле ввода форматированного текста | Редактором кода: его в ките нет, показ кода — `CodeView` |
137
+ | **Просмотр** | `RichTextView` — только чтение сохранённого Документа | `readOnly`-режимом Редактора: тот держит движок, Просмотр — нет |
138
+ | **Оглавление** | `RichTextToc`: список заголовков Документа рядом с Просмотром или Редактором. Свёрнуто — полоса штрихов, раскрыто — список, клик по пункту ведёт к заголовку | `Heading` кита и навигацией сайта документации |
139
+ | **Документ** | Значение Редактора: HTML-строка, ограниченная Схемой | JSON-деревом ProseMirror в движке — оно внутреннее; наружу оно выходит только JSON-конвертом |
140
+ | **JSON-конверт** | Документ как JSON для файла и шаблона: `{ format: "olddevs-rich-text", version, doc }` (`getJSON()`, `setJSON()`, `defaultValue`), без потерь и через Схему | Значением Редактора — значение остаётся HTML; голым деревом `editor.getJSON()` без конверта |
141
+ | **Схема** | Белый список Блоков, Меток и атрибутов, которые Редактор принимает и отдаёт | Санитизацией на сервере — её делает потребитель (`sanitizeRichText`) |
142
+ | **Блок** | Структурный элемент Документа: абзац, заголовок, список, таблица, картинка… | Меткой |
143
+ | **Метка** | Строчное форматирование внутри Блока: жирный, ссылка, цвет… | Блоком |
144
+ | **Атом** | Блок или строчный элемент, который выделяется, переносится и удаляется целиком: картинка (подпись внутри неё правится), разделитель, мягкий перенос, упоминание. Всегда делает поле непустым | Пустым Блоком: абзац без текста — не Атом и содержимым не считается |
145
+ | **Текст атома** | Строка, которой Атом представлен в тексте Документа: её отдают `getText` и `getSelectedText`, её длина — вес Атома в `maxLength`, ею Атом выгружается в Markdown без своих правил. У картинки — текст подписи, у разделителя — пустая строка | Атрибутом Блока |
146
+ | **Раскладка** | Блок из колонок (Инструмент `layout`): шесть вариантов — от одной до четырёх равных колонок, 60/40 и 40/60. Только верхнего уровня, в себя не вкладывается; колонка для своих Блоков — то же, что Документ | Таблицей: у той строки и ячейки данных, а колонки Раскладки — вёрстка Документа. `Grid` кита — сеткой экрана, а не Блоком |
147
+ | **Обёртка** | Блок, который собирает группу Блоков (Инструмент `wrapper`, `div` с `data-block="wrapper"`): их двигают, дублируют и удаляют одним Блоком. Без Тона Обёртки своего вида нет — пунктир только в Редакторе. Обёртка и Раскладка в Обёртку не вкладываются | Цитатой: у той свой вид и смысл в Документе, а Обёртка без тона — только группировка |
148
+ | **Тон Обёртки** | Оформление Обёртки заметкой (`data-tone`): фон и полоса слева одного из пяти тонов словаря `Tone` — «Заметка», «Совет», «Важно», «Внимание», «Осторожно». Выбирается в «Тон ›» Ручки Блока, одинаков в Редакторе и Просмотре, в Markdown выгружается GitHub alert (то, что GitHub и Notion называют callout) | Тоном Сообщения поля (`status` или `error`). Смыслом: ролей и `aria-*` тон не несёт, смысл заметки пишется словом в тексте |
149
+ | **Сворачиваемый Блок** | Блок из заголовка и содержимого, которое раскрывают и сворачивают (Инструмент `details`, расширение Details из Tiptap; теги `details` и `summary`). Содержимое — Блоки, Раскладки и Обёртки в нём нет. Открытость пишет в Документ только Опция `persist` | Обёрткой: та группирует Блоки и ничего не прячет. `Accordion` кита: тот — компонент экрана, а не Блок Документа |
150
+ | **Панель** | Набор кнопок форматирования; вид задаёт `toolbar`. **Фиксированная** (`fixed`, по умолчанию) — над полем, липнет при прокрутке; **плавающая** (`floating`) — те же кнопки над непустым выделением. При `bubble` Панели нет — её место занимает Меню выделения, при `none` нет ни того, ни другого. На сенсорном экране Панель всегда фиксированная | `Toolbar` кита — Примитивом, из которого Панель собрана |
151
+ | **Меню вставки** | Список «Добавить» и «Превратить в»: открывается по `/` в тексте и по кнопке «+» | Контекстным меню браузера |
152
+ | **Меню выделения** | Компактная плашка на инверсной поверхности над непустым выделением: «¶», списки, жирный, курсив, подчёркнутый, цвет, «…», ссылка, эмодзи; состав задан китом. Стоит вместо Панели при `toolbar="bubble"` и поверх фиксированной Панели — там её выключает `selectionMenu={false}`. На сенсорном экране её нет | Плавающей Панелью: у той полный набор кнопок |
153
+ | **Ручка Блока** | «⋮» у Блока с кареткой и её меню действий над Блоком целиком: «Добавить ›», «Формат ›», «Вверх», «Вниз», «Дублировать», «Удалить» | Панелью: та работает с выделением, а не с Блоком |
154
+ | **Пункт вставки** | Строка Меню вставки: вставляет Блок или превращает текущий. Один пункт виден и по `/`, и по «+», и в Ручке Блока | Кнопкой Панели |
155
+ | **Действие над Блоком** | Пункт меню Ручки Блока, который работает с Блоком целиком, например «Дублировать» | Кнопкой: та работает с выделением |
156
+ | **Справочник сочетаний** | Поповер «команда — сочетание» только для чтения за последней кнопкой фиксированной Панели. Строки — команды включённых Инструментов, своих тоже; на телефоне кнопки нет | `CommandPalette` кита: строки Справочника сочетаний не нажимаются. `ShortcutsHelp` кита: тот — сочетания экрана, а не Редактора |
157
+ | **HTML-режим** | Режим Инструмента `source`: кнопка «HTML» на фиксированной Панели заменяет Документ полем с его HTML. Текст поля проходит Схему и становится Документом одной правкой — при выходе из режима, `blur`, отправке формы и чтении через Хэндл | HTML-соглашением: то — форма своего в Документе, а не режим. `CodeView`: тот показывает код, а поле HTML правится |
158
+ | **Стекло** | Полупрозрачная заливка с размытием фона у всего, что Редактор показывает поверх Документа: плавающая Панель, Меню выделения, меню, поповеры, Карточка у текста. Цвет — токен своей поверхности; при `prefers-reduced-transparency`, `prefers-contrast: more` и на iOS заливка сплошная | `Menu` и `Popover` кита вне Редактора: те остаются сплошными |
159
+ | **UI-запись** | Элемент интерфейса своего Инструмента, описанный данными: кнопка, Пункт вставки, Действие над Блоком или Карточка у текста. Рисует её кит в Отведённом месте; выключенный Инструмент убирает и свои записи | React-узлом в интерфейсе: произвольный React допускается только в содержимом поповера кнопки и Карточки у текста |
160
+ | **Отведённое место** | Одно место на поверхности, где стоят записи своих Инструментов, в порядке `tools`: группа Панели перед «Отменить», конец раздела Меню вставки, секция Ручки Блока перед «Удалить» | Позицией относительно встроенной кнопки: id встроенных публичным API не являются |
161
+ | **Пресет** | Готовый набор встроенных Инструментов: `full` или `basic` (`RICH_TEXT_PRESETS`). Не замороженный список: новый встроенный приходит в него minor-версией | Точным списком `tools`: его состав меняет только экран |
162
+ | **Инструмент** | Одна возможность Редактора: её Блоки и Метки, их правила в Схеме и место в интерфейсе, например `table`. Встроенный задаётся именем, свой — описанием | Кнопкой: выключенный Инструмент убирает и Блок из Схемы. Плагином Redactor: тот — класс поведения над DOM без Схемы |
163
+ | **Свой Инструмент** | Инструмент, который описывает потребитель (`CustomTool`): правила Схемы данными, Extensions и UI-записи. Его передают в `tools` вперемешку с именами кита | Внутренним описанием кита: то — надмножество публичной формы для встроенных, наружу не экспортируется |
164
+ | **Опции Инструмента** | Что экран задаёт Инструменту до создания движка: стартовые флажки Поиска, `offsetVar`, `levels` и `listWidth` Оглавления, `defaults` своего Инструмента (`defineTool`). Экран задаёт их записью `tool(…)`, кит читает один раз, при создании движка | `options` у расширения Tiptap: те задаёт сам автор расширения и читает само расширение, а Опции задаёт экран и читает кит. Пропами Редактора (`preset`, `maxHeight`): те настраивают поле, а не Инструмент |
165
+ | **Настроенный Инструмент** | Запись `tools`, которую возвращает `tool(name, options)` или `tool(definition, options)`: Инструмент вместе с его Опциями. Включает Инструмент без имени в `tools` и побеждает голое имя из Пресета | Определением `defineTool`: то описывает Инструмент, а Настроенный Инструмент — его включение с Опциями. Описанием встроенного: оно наружу не выходит, запись лишь называет Инструмент и несёт Опции |
166
+ | **Состояние Инструмента** | Снимок данных, который экран читает хуком `useRichTextToolState(ref, name)`: у Поиска — открыта ли панель, запрос, число совпадений и текущее, у Оглавления — заголовки и текущий раздел. Перерисовка только при смене снимка | `storage` у расширения Tiptap: то — изменяемое хранилище внутри движка, а Состояние только читается. `useRichTextEditorState`: тот берёт срез живого `editor` Tiptap, а не контракт Инструмента |
167
+ | **Команды Инструмента** | Что экран вызывает у Инструмента через `handle.tool(name)`: `tool("search")?.open()`, `tool("toc")?.jumpTo(2)`. Каждая возвращает `boolean`; `null` вместо объекта Команд — Инструмента нет в наборе, у него нет Команд или движок ещё не создан | Методами Хэндла (`insertHTML`, `focus`): те общие для любого `tools`, а Команды есть, только пока Инструмент включён. `editor.commands` и `commands` у Tiptap: те — команды движка, они следуют его мажору |
168
+ | **Префикс потребителя** | Начало имени всего своего — Инструмента, его Блоков, Меток и атрибутов — до подчёркивания: `acme_mergeTag`, `data-acme_size`. В именах кита подчёркивания нет, поэтому своё и встроенное не совпадают ни в наборе, ни в Документе | Пресетом: тот — набор встроенных Инструментов, а не пространство имён |
169
+ | **HTML-соглашение** | Форма своего в Документе: Блок — `div` или `span` с `data-block`, Метка — `span` с `data-mark`, атрибуты — `data-<префикс>_<имя>`. Заморожено: расширяется только добавлением | Тегами Схемы кита (`p`, `table`, `img`): свой Блок их занять не может |
170
+ | **Признак Блока** | Свойство Блока, которое понимает только кит, а не движок: «контейнер» (детям своя Ручка), «можно превратить в», «Атом без меню форматирования» | Атрибутом Блока: тот хранится в Документе |
171
+ | **Extensions** | Расширения Tiptap в описании Инструмента (поле `engine`): Node, Mark, Extension, плагины ProseMirror, NodeView. Передаются сразу или через Загрузчик | Правилами Схемы: те — данные, их читают сервер и Просмотр без движка. «Часть для движка» — прежнее название (так в ADR-0058) |
172
+ | **Загрузчик** | Функция с динамическим импортом вместо самих Extensions: `engine: () => import(…)`. Так же грузятся тяжёлые встроенные вне `basic` — Блок кода и таблица | Предзагрузкой (`modulepreload`): её кит не публикует, ставит потребитель |
173
+ | **Хэндл** | Императивный доступ кода экрана к Редактору через `ref`: вставка у каретки, чтение, фокус, история, Команды Инструментов (`tool(name)`) | Сервисами Redactor: те — внутренности движка, а не API экрана |
174
+ | **Готовность** | Момент, когда движок создан и Загрузчики всех включённых Инструментов, своих и встроенных, отработали: с него методы Хэндла действуют, а не молчат. Наступает один раз за монтаж, о нём сообщает `onReady` | Гидратацией: после неё движок может ещё ждать Загрузчики |
175
+ | **Фокус поля** | Фокус внутри Редактора целиком: Документ, Панель, поповеры кита, поле HTML. Переход между ними Фокус поля не теряет; `onFocus` и `onBlur` — о нём | Фокусом Документа (`focus` и `blur` движка): клик в Панель его снимает |
176
+ | **Правка автора** | Изменение Документа, равное набору с клавиатуры: шаг истории, `onChange` после задержки, предел символов действует. Сюда же вставка, отмена и повтор из Хэндла | Заменой снаружи |
177
+ | **Замена снаружи** | Подмена Документа целиком (`value`, `clear()`, `setMarkdown()`, `setJSON()`): предел символов не режет; `onChange` сразу у `clear()`, `setMarkdown()` и `setJSON()`, на новый `value` не вызывается | Правкой автора |
178
+ | **Скелет** | Вид Редактора до Готовности: рамка поля, место Панели и Документ: очищенный Схемой, он выведен статичным HTML с тем же классом и ритмом, что Документ движка, без ввода. На сервере — рамка без Документа. Сбой Загрузчика превращает Скелет в ошибку поля с «Повторить» | Просмотром: тот — отдельный компонент только для чтения, а Скелет — состояние Редактора, которое сменяется движком. Компонентом `Skeleton` кита — заглушкой загрузки |
179
+ | **Строка статуса** | Строка внутри рамки поля под Документом: слева содержимое экрана (`status`: число слов, «Сохранено», соавтор), справа счётчик символов кита | Сообщением поля: строка показывает длительное состояние экрана, а не событие |
180
+ | **Сообщение поля** | Одно событие, привязанное к полю (`showNotice`): тон `status` (только озвучивается) или `error` (видимая строка под полем до следующей Правки автора). Новое заменяет прежнее | Тостом кита: тот глобален и к полю не привязан |
181
+ | **Карточка у текста** | Немодальная карточка под диапазоном Документа, который объявил свой Инструмент (`textCards`): комментарий, подсказка по результатам проверки текста. Открывается кареткой или щелчком, фокус остаётся в тексте | Поповером кнопки: его открывает кнопка, а Карточку — место Документа |
182
+ | **Символ-триггер** | Свой символ Инструмента (`trigger`), набор которого в начале Блока или после пробела открывает список пунктов у каретки, как `/`: `@` для упоминаний, `#` для тегов. Выбор заменяет набранное `@запрос` своим узлом | Меню вставки по `/`: то — встроенное, а свой символ задаёт Инструмент |
183
+ | **Лист** | Светлая область Документа в любой теме приложения (`surface="paper"`) — для текста, который уйдёт из приложения светлым: письмо, печать, PDF. Панель, меню и рамка поля остаются в теме приложения; Просмотр с тем же `surface` показывает тот же Лист | Темой `light`: та меняет всё приложение, Лист — только Документ |
184
+ | **Остров** | Клиентский кусок Просмотра, который после монтирования оживляет Блок в уже показанном HTML: кнопка «Копировать» у Блока кода, `island` своего Блока | Видом узла: тот живёт только в движке Редактора |
185
+ | **Гнездо** | Место в показанном HTML, куда Остров монтирует живой элемент: шапка Блока кода, в которую встаёт кнопка «Копировать» | Отведённым местом: то — место в интерфейсе Редактора для записей Инструментов |
186
+
187
+ ## Tiptap
188
+
189
+ Слова движка [Tiptap](https://tiptap.dev), на котором стоит Редактор. Их пишут по-английски и не
190
+ переводят: русская калька («нода», «плагин») завела бы второй смысл рядом с Блоком и
191
+ Инструментом. Автор своего Инструмента пишет Extensions на Tiptap и читает документацию Tiptap —
192
+ таблица связывает слово движка со словом кита. В колонке «Значение» сначала смысл в Tiptap, затем то,
193
+ что ему соответствует у кита.
194
+
195
+ | Термин | Значение | Не путать с |
196
+ | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
197
+ | **Extension** | Единица движка Tiptap: узлы, Метки, команды, сочетания клавиш и плагины ProseMirror в одном классе (`Extension.create`; `Node` и `Mark` — её виды). У кита то же слово: Extensions Инструмента — это его расширения Tiptap, а возможность целиком — это Инструмент. Extension без Схемы — Инструмент без Блока (`search`, `toc`) | Инструментом: тот несёт ещё правила для Схемы, Markdown и Просмотра, а также UI-записи, а Extension — только движок. Расширение Tiptap в `tools` не передают: его кладут в Extensions своего Инструмента |
198
+ | **Node** | Тип узла в Схеме Tiptap: абзац, заголовок, таблица, картинка; бывает блочным и строчным. У кита блочному соответствует Блок, строчному без содержимого — строчный Атом (упоминание) | Блоком целиком: Блок — это правила Схемы данными и Признаки Блока, которые читают сервер и Просмотр, а Node — одно из его Extensions. Русского слова «нода» в ките нет |
199
+ | **Mark** | Строчное форматирование в Схеме Tiptap: жирный, ссылка, цвет. У кита — Метка: правила Схемы данными и `Mark` в Extensions | Тегом `mark`: его рисует только Метка `highlight`. Text Style Tiptap (пустой `span` под стили) — основа Метки `color`, а не отдельный Инструмент |
200
+ | **StarterKit**, **Kit** | Набор расширений Tiptap одним пакетом: StarterKit, ListKit, TableKit, TextStyleKit; каждое расширение набора настраивается или выключается ключом в `configure`. У кита StarterKit — внутренняя деталь сборки движка: описание каждого встроенного Инструмента вносит свою долю ключей (`starterKit`), доли сливаются в один `StarterKit.configure`, а ключ без доли выключен. Наружу выходит Пресет | Пресетом (`full`, `basic`): тот — набор Инструментов, а не расширений движка, и не замороженный. Китом словаря — дизайн-системой `@olddevs/ui`: слово Kit в названиях Tiptap к ней отношения не имеет. Подключить `StarterKit` через `tools` нельзя |
201
+ | **options** (`configure`) | Настройки расширения Tiptap: автор объявляет их в `addOptions`, потребитель меняет вызовом `configure({…})`. У кита — Опции Инструмента: `tool(name, options)` у `search` и `toc`, `defaults` и `tool(definition, options)` у своего Инструмента (`defineTool`). Слияние как у `configure` в Tiptap v3: вложенные объекты сливаются, массивы и функции заменяются | Опциями расширений Tiptap внутри Extensions: встроенные Extensions кит собирает сам, и экрану они не открыты. Пропами Редактора (`preset`, `maxHeight`): те настраивают поле, а не Инструмент |
202
+ | **storage** | Изменяемое хранилище расширения внутри движка (`editor.storage.<имя>`): результаты поиска, счётчик символов. У кита — Состояние Инструмента: снимок, который экран читает хуком `useRichTextToolState(ref, name)`; свой Инструмент объявляет его функцией `state` в `defineTool` | `editor.storage`: Состояние только читается, а storage меняет само расширение. Хранилище — часть движка и следует его мажору |
203
+ | **commands** | Команды расширения Tiptap (`addCommands`): `editor.commands`, цепочка `editor.chain()`, проверка `editor.can()`. У кита — Команды Инструмента: `handle.tool(name)`, каждая возвращает `boolean`; свой Инструмент объявляет их функцией `commands` в `defineTool` | `editor.commands` и `chain()`: те — команды движка и следуют его мажору. Методами Хэндла (`insertHTML`, `focus`): те общие для любого `tools`, а Команды Инструмента есть, только пока он включён |
204
+ | **`extend`** | Способ изменить существующее расширение Tiptap: `Bold.extend({…})`. У кита аналога нет: встроенный Инструмент не подменяется (ADR-0058, п. 1.5). Если нужно другое поведение, выключите встроенный и поставьте свой под именем с Префиксом потребителя | `configure`: тот меняет Опции, а не поведение; его аналог у кита есть — Опции Инструмента. Своим Инструментом «вместо» встроенного: у того собственное имя, свои Блоки и Метки |
205
+ | **`priority`** | Число у расширения Tiptap: чем оно больше, тем раньше расширение в очереди и тем раньше опрашиваются его плагины. У кита числа нет: порядок встроенных Инструментов задаёт сам кит (от него зависят ранг Меток, а с ним их вложенность в HTML, вставка и клавиши), а свои идут после встроенных в порядке `tools`, и их обработчики вставки и drop опрашиваются раньше встроенных | Порядком записей на Панели и в Меню вставки: его задаёт кит, а UI-записи своих Инструментов стоят в Отведённом месте в порядке `tools`. `priority` правила `parseHTML`: то — очередность правил разбора одного узла |
206
+ | **NodeView** | Свой вид узла в Редакторе: вместо `renderHTML` узел рисуется кодом на JavaScript или React. У кита — вид узла в Extensions; в Просмотре, где движка нет, ему соответствует Остров | Островом: тот оживляет Блок в уже показанном HTML без движка, а NodeView живёт только в Редакторе. `renderHTML`: он даёт HTML Документа, а NodeView — лишь вид на экране |
207
+ | **MarkView** | То же для Метки: свой вид Метки в Редакторе. У кита — вид Метки в Extensions; Острова у Метки нет, в Просмотре она остаётся очищенным HTML | NodeView: тот рисует узел целиком, а MarkView — отрезок текста с Меткой. Островом: Остров бывает только у Блока |
208
+ | **Decoration** | Оформление поверх Документа, которое его не меняет: подсветка, класс на узле, виджет (`Decoration` ProseMirror). У кита то же слово: Decoration живёт в Extensions и в Документ не попадает — так устроены подсветка кода, совпадения Поиска и индикатор загрузки картинки | Меткой: Метка хранится в Документе и уходит в `value`, Decoration — нет. Атрибутом Блока |
209
+ | **Input rule** | Правило ввода: набранный текст по шаблону заменяется узлом или Меткой (`# ` — заголовок, `**…**` — жирный). У кита отдельного термина нет: правило лежит в Extensions Блока или Метки, а автор текста видит его как Markdown-сокращение при наборе | Markdown-выгрузкой (`getMarkdown`, `setMarkdown`): та переводит весь Документ, а правило ввода срабатывает на набранном фрагменте. Пунктом вставки |
210
+ | **Paste rule** | Правило вставки: при вставке или drop совпавший с шаблоном текст (чаще всего ссылка) становится узлом или Меткой. У кита то же: правило в Extensions Инструмента | Разбором вставки по Схеме: тот срезает то, чего Схема не знает, а Paste rule превращает совпавший текст в узел. Правилом разбора `parseHTML`: то относится к HTML, а не к тексту |
211
+ | **Schema** | Описание допустимых узлов и Меток в ProseMirror: какие бывают и что внутри чего; Tiptap собирает его из расширений. У кита Схема — то же самое плюс белый список для санитайзера и Просмотра: правила лежат в описании Инструмента данными, их читают сервер и Просмотр без движка, а Schema движка собирается из Extensions | Санитизацией на сервере: её делает потребитель (`sanitizeRichText`). JSON-деревом ProseMirror: оно внутреннее |
212
+ | **Transaction** | Одно изменение состояния движка ProseMirror: шаги над Документом, выделение и метаданные; цепочка `chain().run()` — одна транзакция. У кита слова нет: Состояние Инструмента пересчитывается на каждой транзакции, а правка из `run` Действия над Блоком — одна транзакция, то есть одна отмена | Правкой автора: та — изменение Документа, равное набору, а транзакция бывает и без изменения Документа (выделение, метаданные). Перерисовкой: Состояние перерисовывает экран, только когда сменился снимок, а не на каждой транзакции |
package/docs/icons.en.md CHANGED
@@ -2,7 +2,7 @@
2
2
  entrypoint: "@olddevs/ui/icons"
3
3
  source: src/icons.ts
4
4
  status: stable
5
- sourceHash: d5e61db56b70
5
+ sourceHash: 8b6aa04a1c0a
6
6
  ---
7
7
 
8
8
  # Icons `@olddevs/ui/icons`
@@ -116,6 +116,7 @@ import { DeleteIcon, SearchIcon } from "@olddevs/ui/icons";
116
116
  | Document Layout in columns | `ColumnLayoutIcon` | `ColumnsIcon` |
117
117
  | Wrapper: a group of Blocks | `WrapperIcon` | `ColumnLayoutIcon` |
118
118
  | Remove the Wrapper, keep the Blocks | `UnwrapIcon` | `DeleteIcon` |
119
+ | Collapsible Block of the Editor | `DetailsIcon` | `ChevronDownIcon` |
119
120
 
120
121
  ## Subject topics
121
122
 
@@ -217,6 +218,8 @@ Layout added `ColumnLayoutIcon` — two columns, the "Layout" item of the Insert
217
218
 
218
219
  Wrapper added the pair `WrapperIcon` and `UnwrapIcon` — lucide's `Group` and `Ungroup`: a frame with dashed corners around two Blocks and the same Blocks without a frame. The icons sit at the "Wrapper" item of the Insert menu and the "Remove Wrapper" item in the Block handle menu. This is not `ColumnLayoutIcon`: columns put Blocks side by side, while a Wrapper groups them without changing their order. `DeleteIcon` does not fit removal: only the container is deleted, not the content.
219
220
 
221
+ Collapsible block added `DetailsIcon` — lucide's `ListCollapse`: a list with collapse arrows, the "Collapsible block" item of the Insert menu. The dictionary had no fitting name: `ChevronDownIcon` is a step and nesting, `CollapseIcon` is collapsing a window, while here it is a whole Block with a title and hidden content. Removing the Block uses the already taken `UnwrapIcon` (ADR-0049).
222
+
220
223
  The first iteration of the table made do with two icons for four directions
221
224
  (`AddRowIcon`, `AddColumnIcon`) and an icon for the separate "Table
222
225
  actions" button (`TableEditIcon`). With the "Table" menu the button went away, and the direction
package/docs/icons.md CHANGED
@@ -115,6 +115,7 @@ import { DeleteIcon, SearchIcon } from "@olddevs/ui/icons";
115
115
  | Раскладка Документа колонками | `ColumnLayoutIcon` | `ColumnsIcon` |
116
116
  | Обёртка: группа Блоков | `WrapperIcon` | `ColumnLayoutIcon` |
117
117
  | Снять Обёртку, Блоки остаются | `UnwrapIcon` | `DeleteIcon` |
118
+ | Сворачиваемый Блок Редактора | `DetailsIcon` | `ChevronDownIcon` |
118
119
 
119
120
  ## Предметные темы
120
121
 
@@ -216,6 +217,8 @@ HTML-режим добавил `SourceIcon` — лист с `</>` (`FileCode`),
216
217
 
217
218
  Обёртка добавила пару `WrapperIcon` и `UnwrapIcon` — `Group` и `Ungroup` у lucide: рамка пунктирными углами вокруг двух Блоков и те же Блоки без рамки. Иконки стоят у пункта «Обёртка» Меню вставки и пункта «Снять обёртку» в меню Ручки Блока. Это не `ColumnLayoutIcon`: колонки ставят Блоки рядом, а Обёртка группирует их, не меняя порядка. Для снятия не подходит `DeleteIcon`: удаляется только контейнер, а не содержимое.
218
219
 
220
+ Сворачиваемый Блок добавил `DetailsIcon` — `ListCollapse` у lucide: список со стрелками сворачивания, пункт «Сворачиваемый блок» Меню вставки. Подходящего имени в словаре не было: `ChevronDownIcon` — шаг и вложенность, `CollapseIcon` — свернуть окно, а здесь Блок целиком с заголовком и спрятанным содержимым. Снять Блок — уже занятый `UnwrapIcon` (ADR-0049).
221
+
219
222
  Первый срез таблицы обходился двумя рисунками на четыре направления
220
223
  (`AddRowIcon`, `AddColumnIcon`) и иконкой отдельной кнопки «Действия с
221
224
  таблицей» (`TableEditIcon`). С меню «Таблица» кнопка ушла, а направление
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@olddevs/ui",
3
- "version": "4.5.0",
3
+ "version": "4.6.0",
4
4
  "description": "Olddevs UI — design system: tokens, themes and accessible UI primitives",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -117,6 +117,7 @@
117
117
  "@tiptap/core": "^3.31.4",
118
118
  "@tiptap/extension-blockquote": "^3.31.4",
119
119
  "@tiptap/extension-code-block-lowlight": "^3.31.4",
120
+ "@tiptap/extension-details": "^3.31.4",
120
121
  "@tiptap/extension-highlight": "^3.31.4",
121
122
  "@tiptap/extension-horizontal-rule": "^3.31.4",
122
123
  "@tiptap/extension-link": "^3.31.4",
@@ -157,7 +157,7 @@ export interface RichTextEditorProps {
157
157
  * Редактор готов: движок создан, методы Хэндла (`ref`) уже действуют — например,
158
158
  * вставить шаблон. Без аргументов, один раз за монтаж, в том числе при
159
159
  * `readOnly` и `disabled`; перерисовка и смена колбэка повторного вызова не
160
- * дают. Ждёт загрузчики Частей для движка своих Инструментов. Серверный
160
+ * дают. Ждёт загрузчики Extensions своих Инструментов. Серверный
161
161
  * рендер, ошибка набора `tools` и упавший загрузчик (движка нет) его не вызывают.
162
162
  */
163
163
  onReady?: () => void;
@@ -261,7 +261,7 @@ export interface RichTextEditorProps {
261
261
  * включает Инструмент и без имени, а имя из пресета уступает ей; две записи
262
262
  * `tool()` с одним именем — ошибка поля. Неизвестное имя отбрасывается
263
263
  * молча; описание с ошибкой (имя без Префикса потребителя, совпадение имён,
264
- * Часть для движка мимо правил Схемы) — ошибка поля: движок не создаётся,
264
+ * Extensions мимо правил Схемы) — ошибка поля: движок не создаётся,
265
265
  * значение формы остаётся входящим, причина — в консоли разработчика.
266
266
  *
267
267
  * `preset` и `tools`, а с ними и Опции Инструментов, читаются при создании
@@ -522,17 +522,17 @@ export const RichTextEditor = forwardRef<RichTextEditorHandle, RichTextEditorPro
522
522
  Набор инструментов замораживается при монтаже: из него собрана Схема, а
523
523
  Схему у живого движка не поменять. Панель читает тот же замороженный
524
524
  набор — иначе новый `tools` показал бы кнопку, которой Схема не знает.
525
- Набор — список описаний Инструментов (`features/builtins.ts`), реестры
525
+ Набор — список описаний Инструментов (`features/builtins.ts`), поверхности
526
526
  читают его проекцию.
527
527
  */
528
528
  const [enabledTools] = useState(() => expandTools(preset, tools));
529
529
  /*
530
- Загрузчики Частей для движка (ADR-0058, п. 11.3–11.6). Загрузка стартует
530
+ Загрузчики Extensions (ADR-0058, п. 11.3–11.6). Загрузка стартует
531
531
  в рендере, а не в эффекте: с первого рендера в браузере, ещё до монтажа;
532
532
  на сервере — никогда. Промис кэширован на загрузчике (`toolLoader.ts`):
533
533
  повторный рендер и второй Редактор его не зовут. Набор движка собирается,
534
534
  только когда отработали все (`ready`): Схема фиксируется при создании, и
535
- Блоки из `value` без Части для движка потерялись бы при разборе.
535
+ Блоки из `value` без Extensions потерялись бы при разборе.
536
536
  */
537
537
  const loaders = enabledTools.descriptors.flatMap((descriptor) => descriptor.load ?? []);
538
538
  const loads = loaders.map((loader) =>
@@ -603,6 +603,8 @@ export const RichTextEditor = forwardRef<RichTextEditorHandle, RichTextEditorPro
603
603
  placeholderRef.current = placeholderText;
604
604
  const taskCheckboxRef = useRef(messages.editor.taskCheckbox);
605
605
  taskCheckboxRef.current = messages.editor.taskCheckbox;
606
+ const detailsToggleRef = useRef(messages.editor.detailsToggle);
607
+ detailsToggleRef.current = messages.editor.detailsToggle;
606
608
  // Загрузчик и строки картинки — тоже через ref: расширение их читает в
607
609
  // момент вставки файла и при перерисовке подписи, а не при создании движка.
608
610
  const uploadRef = useRef(onUploadImage);
@@ -887,6 +889,7 @@ export const RichTextEditor = forwardRef<RichTextEditorHandle, RichTextEditorPro
887
889
  placeholder: () => placeholderRef.current,
888
890
  limit: () => limitRef.current,
889
891
  taskCheckbox: (text) => taskCheckboxRef.current({ text }),
892
+ detailsToggle: (text) => detailsToggleRef.current({ text }),
890
893
  slash: slashBridge,
891
894
  triggers: triggerBindings,
892
895
  openPopover: (request) => setToolPopover({ request, open: true }),
@@ -917,7 +920,7 @@ export const RichTextEditor = forwardRef<RichTextEditorHandle, RichTextEditorPro
917
920
  `value`. Движок тогда собирается из запасного набора и пустым, а наружу
918
921
  не выходит (`editor` ниже — `null`, как до монтажа): Хэндл тихий,
919
922
  скрытое поле несёт входящее значение, `onChange` молчит. Набор с
920
- загрузчиками проверяется, когда они отработали: Часть для движка — их итог.
923
+ загрузчиками проверяется, когда они отработали: Extensions — их итог.
921
924
  */
922
925
  const toolsError = useMemo(
923
926
  () => extensions && customToolsError(enabledTools, extensions),
@@ -16,7 +16,7 @@ import { MARKDOWN_FALLBACK, warnNoMarkdown } from "./customMarkdown.js";
16
16
  Текст атома (ADR-0058, раздел 4). Одно правило для встроенных и
17
17
  своих атомов, и всё, что выдаёт текст Документа, читает его отсюда:
18
18
 
19
- - Текст атома даёт `renderText` из Части для движка. Листовой атом без него —
19
+ - Текст атома даёт `renderText` из Extensions. Листовой атом без него —
20
20
  пустая строка, атом с содержимым (картинка с подписью) — текст своих детей;
21
21
  - вес атома в `maxLength` — длина этого текста (`countCharacters`);
22
22
  - `getText`, `getSelectedText`, копирование текстом и Markdown отдают тот же
@@ -90,7 +90,7 @@ export function atomText(node: ProseMirrorNode): string {
90
90
  */
91
91
 
92
92
  /**
93
- * Узлы по выгрузке в Markdown: `true` — Часть для движка умеет сама, строка —
93
+ * Узлы по выгрузке в Markdown: `true` — Extensions умеют сами, строка —
94
94
  * атом своего Инструмента без правил (имя Инструмента — для предупреждения).
95
95
  */
96
96
  function markdownHandled(editor: Editor): Map<string, true | string> {