@rtif-sdk/web 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (215) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +67 -0
  3. package/dist/block-drag-handler.d.ts +189 -0
  4. package/dist/block-drag-handler.d.ts.map +1 -0
  5. package/dist/block-drag-handler.js +745 -0
  6. package/dist/block-drag-handler.js.map +1 -0
  7. package/dist/block-renderer.d.ts +402 -0
  8. package/dist/block-renderer.d.ts.map +1 -0
  9. package/dist/block-renderer.js +424 -0
  10. package/dist/block-renderer.js.map +1 -0
  11. package/dist/clipboard.d.ts +178 -0
  12. package/dist/clipboard.d.ts.map +1 -0
  13. package/dist/clipboard.js +432 -0
  14. package/dist/clipboard.js.map +1 -0
  15. package/dist/command-bus.d.ts +113 -0
  16. package/dist/command-bus.d.ts.map +1 -0
  17. package/dist/command-bus.js +70 -0
  18. package/dist/command-bus.js.map +1 -0
  19. package/dist/composition.d.ts +220 -0
  20. package/dist/composition.d.ts.map +1 -0
  21. package/dist/composition.js +271 -0
  22. package/dist/composition.js.map +1 -0
  23. package/dist/content-extraction.d.ts +69 -0
  24. package/dist/content-extraction.d.ts.map +1 -0
  25. package/dist/content-extraction.js +228 -0
  26. package/dist/content-extraction.js.map +1 -0
  27. package/dist/content-handler-file.d.ts +40 -0
  28. package/dist/content-handler-file.d.ts.map +1 -0
  29. package/dist/content-handler-file.js +91 -0
  30. package/dist/content-handler-file.js.map +1 -0
  31. package/dist/content-handler-image.d.ts +82 -0
  32. package/dist/content-handler-image.d.ts.map +1 -0
  33. package/dist/content-handler-image.js +120 -0
  34. package/dist/content-handler-image.js.map +1 -0
  35. package/dist/content-handler-url.d.ts +129 -0
  36. package/dist/content-handler-url.d.ts.map +1 -0
  37. package/dist/content-handler-url.js +244 -0
  38. package/dist/content-handler-url.js.map +1 -0
  39. package/dist/content-handlers.d.ts +67 -0
  40. package/dist/content-handlers.d.ts.map +1 -0
  41. package/dist/content-handlers.js +263 -0
  42. package/dist/content-handlers.js.map +1 -0
  43. package/dist/content-pipeline.d.ts +383 -0
  44. package/dist/content-pipeline.d.ts.map +1 -0
  45. package/dist/content-pipeline.js +232 -0
  46. package/dist/content-pipeline.js.map +1 -0
  47. package/dist/cursor-nav.d.ts +149 -0
  48. package/dist/cursor-nav.d.ts.map +1 -0
  49. package/dist/cursor-nav.js +230 -0
  50. package/dist/cursor-nav.js.map +1 -0
  51. package/dist/cursor-rect.d.ts +65 -0
  52. package/dist/cursor-rect.d.ts.map +1 -0
  53. package/dist/cursor-rect.js +98 -0
  54. package/dist/cursor-rect.js.map +1 -0
  55. package/dist/drop-indicator.d.ts +108 -0
  56. package/dist/drop-indicator.d.ts.map +1 -0
  57. package/dist/drop-indicator.js +236 -0
  58. package/dist/drop-indicator.js.map +1 -0
  59. package/dist/editor.d.ts +41 -0
  60. package/dist/editor.d.ts.map +1 -0
  61. package/dist/editor.js +710 -0
  62. package/dist/editor.js.map +1 -0
  63. package/dist/floating-toolbar.d.ts +93 -0
  64. package/dist/floating-toolbar.d.ts.map +1 -0
  65. package/dist/floating-toolbar.js +159 -0
  66. package/dist/floating-toolbar.js.map +1 -0
  67. package/dist/index.d.ts +62 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +119 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/input-bridge.d.ts +273 -0
  72. package/dist/input-bridge.d.ts.map +1 -0
  73. package/dist/input-bridge.js +884 -0
  74. package/dist/input-bridge.js.map +1 -0
  75. package/dist/link-popover.d.ts +38 -0
  76. package/dist/link-popover.d.ts.map +1 -0
  77. package/dist/link-popover.js +278 -0
  78. package/dist/link-popover.js.map +1 -0
  79. package/dist/mark-renderer.d.ts +275 -0
  80. package/dist/mark-renderer.d.ts.map +1 -0
  81. package/dist/mark-renderer.js +210 -0
  82. package/dist/mark-renderer.js.map +1 -0
  83. package/dist/perf.d.ts +145 -0
  84. package/dist/perf.d.ts.map +1 -0
  85. package/dist/perf.js +260 -0
  86. package/dist/perf.js.map +1 -0
  87. package/dist/plugin-kit.d.ts +265 -0
  88. package/dist/plugin-kit.d.ts.map +1 -0
  89. package/dist/plugin-kit.js +234 -0
  90. package/dist/plugin-kit.js.map +1 -0
  91. package/dist/plugins/alignment-plugin.d.ts +68 -0
  92. package/dist/plugins/alignment-plugin.d.ts.map +1 -0
  93. package/dist/plugins/alignment-plugin.js +98 -0
  94. package/dist/plugins/alignment-plugin.js.map +1 -0
  95. package/dist/plugins/block-utils.d.ts +113 -0
  96. package/dist/plugins/block-utils.d.ts.map +1 -0
  97. package/dist/plugins/block-utils.js +191 -0
  98. package/dist/plugins/block-utils.js.map +1 -0
  99. package/dist/plugins/blockquote-plugin.d.ts +39 -0
  100. package/dist/plugins/blockquote-plugin.d.ts.map +1 -0
  101. package/dist/plugins/blockquote-plugin.js +88 -0
  102. package/dist/plugins/blockquote-plugin.js.map +1 -0
  103. package/dist/plugins/bold-plugin.d.ts +37 -0
  104. package/dist/plugins/bold-plugin.d.ts.map +1 -0
  105. package/dist/plugins/bold-plugin.js +48 -0
  106. package/dist/plugins/bold-plugin.js.map +1 -0
  107. package/dist/plugins/callout-plugin.d.ts +100 -0
  108. package/dist/plugins/callout-plugin.d.ts.map +1 -0
  109. package/dist/plugins/callout-plugin.js +200 -0
  110. package/dist/plugins/callout-plugin.js.map +1 -0
  111. package/dist/plugins/code-block-plugin.d.ts +62 -0
  112. package/dist/plugins/code-block-plugin.d.ts.map +1 -0
  113. package/dist/plugins/code-block-plugin.js +176 -0
  114. package/dist/plugins/code-block-plugin.js.map +1 -0
  115. package/dist/plugins/code-plugin.d.ts +37 -0
  116. package/dist/plugins/code-plugin.d.ts.map +1 -0
  117. package/dist/plugins/code-plugin.js +48 -0
  118. package/dist/plugins/code-plugin.js.map +1 -0
  119. package/dist/plugins/embed-plugin.d.ts +90 -0
  120. package/dist/plugins/embed-plugin.d.ts.map +1 -0
  121. package/dist/plugins/embed-plugin.js +147 -0
  122. package/dist/plugins/embed-plugin.js.map +1 -0
  123. package/dist/plugins/font-family-plugin.d.ts +58 -0
  124. package/dist/plugins/font-family-plugin.d.ts.map +1 -0
  125. package/dist/plugins/font-family-plugin.js +57 -0
  126. package/dist/plugins/font-family-plugin.js.map +1 -0
  127. package/dist/plugins/font-size-plugin.d.ts +57 -0
  128. package/dist/plugins/font-size-plugin.d.ts.map +1 -0
  129. package/dist/plugins/font-size-plugin.js +56 -0
  130. package/dist/plugins/font-size-plugin.js.map +1 -0
  131. package/dist/plugins/heading-plugin.d.ts +52 -0
  132. package/dist/plugins/heading-plugin.d.ts.map +1 -0
  133. package/dist/plugins/heading-plugin.js +114 -0
  134. package/dist/plugins/heading-plugin.js.map +1 -0
  135. package/dist/plugins/hr-plugin.d.ts +33 -0
  136. package/dist/plugins/hr-plugin.d.ts.map +1 -0
  137. package/dist/plugins/hr-plugin.js +75 -0
  138. package/dist/plugins/hr-plugin.js.map +1 -0
  139. package/dist/plugins/image-plugin.d.ts +115 -0
  140. package/dist/plugins/image-plugin.d.ts.map +1 -0
  141. package/dist/plugins/image-plugin.js +199 -0
  142. package/dist/plugins/image-plugin.js.map +1 -0
  143. package/dist/plugins/indent-plugin.d.ts +62 -0
  144. package/dist/plugins/indent-plugin.d.ts.map +1 -0
  145. package/dist/plugins/indent-plugin.js +128 -0
  146. package/dist/plugins/indent-plugin.js.map +1 -0
  147. package/dist/plugins/index.d.ts +45 -0
  148. package/dist/plugins/index.d.ts.map +1 -0
  149. package/dist/plugins/index.js +42 -0
  150. package/dist/plugins/index.js.map +1 -0
  151. package/dist/plugins/italic-plugin.d.ts +37 -0
  152. package/dist/plugins/italic-plugin.d.ts.map +1 -0
  153. package/dist/plugins/italic-plugin.js +48 -0
  154. package/dist/plugins/italic-plugin.js.map +1 -0
  155. package/dist/plugins/link-plugin.d.ts +129 -0
  156. package/dist/plugins/link-plugin.d.ts.map +1 -0
  157. package/dist/plugins/link-plugin.js +212 -0
  158. package/dist/plugins/link-plugin.js.map +1 -0
  159. package/dist/plugins/list-plugin.d.ts +53 -0
  160. package/dist/plugins/list-plugin.d.ts.map +1 -0
  161. package/dist/plugins/list-plugin.js +309 -0
  162. package/dist/plugins/list-plugin.js.map +1 -0
  163. package/dist/plugins/mark-utils.d.ts +173 -0
  164. package/dist/plugins/mark-utils.d.ts.map +1 -0
  165. package/dist/plugins/mark-utils.js +425 -0
  166. package/dist/plugins/mark-utils.js.map +1 -0
  167. package/dist/plugins/mention-plugin.d.ts +191 -0
  168. package/dist/plugins/mention-plugin.d.ts.map +1 -0
  169. package/dist/plugins/mention-plugin.js +295 -0
  170. package/dist/plugins/mention-plugin.js.map +1 -0
  171. package/dist/plugins/strikethrough-plugin.d.ts +37 -0
  172. package/dist/plugins/strikethrough-plugin.d.ts.map +1 -0
  173. package/dist/plugins/strikethrough-plugin.js +48 -0
  174. package/dist/plugins/strikethrough-plugin.js.map +1 -0
  175. package/dist/plugins/text-color-plugin.d.ts +57 -0
  176. package/dist/plugins/text-color-plugin.d.ts.map +1 -0
  177. package/dist/plugins/text-color-plugin.js +56 -0
  178. package/dist/plugins/text-color-plugin.js.map +1 -0
  179. package/dist/plugins/underline-plugin.d.ts +37 -0
  180. package/dist/plugins/underline-plugin.d.ts.map +1 -0
  181. package/dist/plugins/underline-plugin.js +48 -0
  182. package/dist/plugins/underline-plugin.js.map +1 -0
  183. package/dist/presets.d.ts +95 -0
  184. package/dist/presets.d.ts.map +1 -0
  185. package/dist/presets.js +159 -0
  186. package/dist/presets.js.map +1 -0
  187. package/dist/renderer.d.ts +125 -0
  188. package/dist/renderer.d.ts.map +1 -0
  189. package/dist/renderer.js +415 -0
  190. package/dist/renderer.js.map +1 -0
  191. package/dist/scroll-to-cursor.d.ts +25 -0
  192. package/dist/scroll-to-cursor.d.ts.map +1 -0
  193. package/dist/scroll-to-cursor.js +59 -0
  194. package/dist/scroll-to-cursor.js.map +1 -0
  195. package/dist/selection-sync.d.ts +159 -0
  196. package/dist/selection-sync.d.ts.map +1 -0
  197. package/dist/selection-sync.js +527 -0
  198. package/dist/selection-sync.js.map +1 -0
  199. package/dist/shortcut-handler.d.ts +98 -0
  200. package/dist/shortcut-handler.d.ts.map +1 -0
  201. package/dist/shortcut-handler.js +155 -0
  202. package/dist/shortcut-handler.js.map +1 -0
  203. package/dist/toolbar.d.ts +103 -0
  204. package/dist/toolbar.d.ts.map +1 -0
  205. package/dist/toolbar.js +134 -0
  206. package/dist/toolbar.js.map +1 -0
  207. package/dist/trigger-manager.d.ts +205 -0
  208. package/dist/trigger-manager.d.ts.map +1 -0
  209. package/dist/trigger-manager.js +466 -0
  210. package/dist/trigger-manager.js.map +1 -0
  211. package/dist/types.d.ts +216 -0
  212. package/dist/types.d.ts.map +1 -0
  213. package/dist/types.js +2 -0
  214. package/dist/types.js.map +1 -0
  215. package/package.json +30 -0
@@ -0,0 +1,265 @@
1
+ /**
2
+ * Plugin kit — DX helper for defining custom RTIF web plugins.
3
+ *
4
+ * Provides typed factory functions that bundle an engine {@link Plugin} with
5
+ * web-layer renderers ({@link MarkRenderer}, {@link BlockRenderer},
6
+ * {@link BlockAttrRenderer}, {@link SpanReplacer}) in a single
7
+ * {@link WebPlugin} definition.
8
+ *
9
+ * Three factories cover the most common plugin patterns:
10
+ * - {@link defineBooleanMark} — on/off marks (highlight, subscript, etc.)
11
+ * - {@link defineParameterizedMark} — value-carrying marks (colors, sizes)
12
+ * - {@link defineBlockType} — toggle block types (aside, blockquote-style)
13
+ *
14
+ * The {@link installWebPlugins} utility registers all engine plugins and
15
+ * renderers from an array of {@link WebPlugin} objects.
16
+ *
17
+ * @module
18
+ */
19
+ import type { Plugin, ShortcutDescriptor, IEditorEngine } from '@rtif-sdk/engine';
20
+ import type { MarkRenderer, MarkRendererRegistry, SpanReplacer } from './mark-renderer.js';
21
+ import type { BlockRenderer, BlockAttrRenderer, BlockRendererRegistry } from './block-renderer.js';
22
+ /**
23
+ * A web plugin bundles an engine plugin with optional web-layer renderers.
24
+ *
25
+ * Pass an array of these to `createWebEditor({ webPlugins: [...] })` or
26
+ * call {@link installWebPlugins} manually.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * const highlight = defineBooleanMark({
31
+ * markType: 'highlight',
32
+ * shortcut: { key: 'h', mod: true, shift: true },
33
+ * renderer: { apply(el) { el.style.backgroundColor = 'yellow'; } },
34
+ * });
35
+ * createWebEditor({ ..., webPlugins: [highlight] });
36
+ * ```
37
+ */
38
+ export interface WebPlugin {
39
+ /** The engine plugin (registered via `engine.use()`). */
40
+ readonly plugin: Plugin;
41
+ /** Mark renderers keyed by mark type. */
42
+ readonly marks?: Readonly<Record<string, MarkRenderer>>;
43
+ /** Block renderers keyed by block type. */
44
+ readonly blocks?: Readonly<Record<string, BlockRenderer>>;
45
+ /** Block attribute renderers keyed by attribute name. */
46
+ readonly attrs?: Readonly<Record<string, BlockAttrRenderer>>;
47
+ /** Span replacers keyed by mark type. */
48
+ readonly replacers?: Readonly<Record<string, SpanReplacer>>;
49
+ }
50
+ /**
51
+ * Configuration for {@link defineBooleanMark}.
52
+ */
53
+ export interface BooleanMarkDef {
54
+ /** The mark type string (e.g., "highlight", "subscript"). */
55
+ readonly markType: string;
56
+ /**
57
+ * Custom plugin ID. Defaults to `"mark-<markType>"`.
58
+ * Use reverse-DNS for published plugins.
59
+ */
60
+ readonly pluginId?: string;
61
+ /**
62
+ * Custom toggle command name. Defaults to `"toggleMark:<markType>"`.
63
+ */
64
+ readonly commandName?: string;
65
+ /** Optional keyboard shortcut for the toggle command. */
66
+ readonly shortcut?: ShortcutDescriptor;
67
+ /** The mark renderer applied to span elements. */
68
+ readonly renderer: MarkRenderer;
69
+ }
70
+ /**
71
+ * Define a boolean (on/off) mark plugin.
72
+ *
73
+ * Creates a {@link WebPlugin} that registers a mark type with `validate: v === true`,
74
+ * a toggle command via `createToggleMarkCommand()`, an optional keyboard shortcut,
75
+ * and a mark renderer.
76
+ *
77
+ * @param config - Boolean mark definition
78
+ * @returns A WebPlugin ready for `createWebEditor({ webPlugins: [...] })`
79
+ *
80
+ * @example
81
+ * ```ts
82
+ * const highlight = defineBooleanMark({
83
+ * markType: 'highlight',
84
+ * shortcut: { key: 'h', mod: true, shift: true },
85
+ * renderer: { apply(el) { el.style.backgroundColor = 'yellow'; } },
86
+ * });
87
+ * ```
88
+ */
89
+ export declare function defineBooleanMark(config: BooleanMarkDef): WebPlugin;
90
+ /**
91
+ * Configuration for the set command in {@link ParameterizedMarkDef}.
92
+ */
93
+ export interface SetMarkCommandDef {
94
+ /** The command name (e.g., "setBgColor"). */
95
+ readonly name: string;
96
+ /**
97
+ * Extract the mark value from the command payload.
98
+ *
99
+ * @param payload - The payload passed to `engine.exec()`
100
+ * @returns The value to set on the mark
101
+ *
102
+ * @example
103
+ * ```ts
104
+ * extractValue: (p) => (p as { color: string }).color
105
+ * ```
106
+ */
107
+ readonly extractValue: (payload: unknown) => unknown;
108
+ /** Optional keyboard shortcut for the set command. */
109
+ readonly shortcut?: ShortcutDescriptor;
110
+ }
111
+ /**
112
+ * Configuration for {@link defineParameterizedMark}.
113
+ */
114
+ export interface ParameterizedMarkDef {
115
+ /** The mark type string (e.g., "bgColor", "highlight-color"). */
116
+ readonly markType: string;
117
+ /**
118
+ * Custom plugin ID. Defaults to `"mark-<markType>"`.
119
+ */
120
+ readonly pluginId?: string;
121
+ /**
122
+ * Validate mark values. Return `true` if the value is valid.
123
+ *
124
+ * @param value - The mark value to validate
125
+ * @returns Whether the value is valid
126
+ */
127
+ readonly validate: (value: unknown) => boolean;
128
+ /** Configuration for the "set" command. */
129
+ readonly setCommand: SetMarkCommandDef;
130
+ /** Name of the "remove" command (e.g., "removeBgColor"). */
131
+ readonly removeCommand: string;
132
+ /** The mark renderer applied to span elements. */
133
+ readonly renderer: MarkRenderer;
134
+ }
135
+ /**
136
+ * Define a parameterized (value-carrying) mark plugin.
137
+ *
138
+ * Creates a {@link WebPlugin} that registers a mark type with custom validation,
139
+ * a "set" command via `createSetMarkCommand()`, a "remove" command via
140
+ * `createRemoveMarkCommand()`, optional keyboard shortcuts, and a mark renderer.
141
+ *
142
+ * @param config - Parameterized mark definition
143
+ * @returns A WebPlugin ready for `createWebEditor({ webPlugins: [...] })`
144
+ *
145
+ * @example
146
+ * ```ts
147
+ * const bgColor = defineParameterizedMark({
148
+ * markType: 'bgColor',
149
+ * validate: (v) => typeof v === 'string' && v.length > 0,
150
+ * setCommand: {
151
+ * name: 'setBgColor',
152
+ * extractValue: (p) => (p as { color: string }).color,
153
+ * },
154
+ * removeCommand: 'removeBgColor',
155
+ * renderer: { apply(el, value) { el.style.backgroundColor = value as string; } },
156
+ * });
157
+ * ```
158
+ */
159
+ export declare function defineParameterizedMark(config: ParameterizedMarkDef): WebPlugin;
160
+ /**
161
+ * Input rule definition for {@link BlockTypeDef}.
162
+ */
163
+ export interface BlockInputRuleDef {
164
+ /** Regex tested against block text after insert. Must match at block start. */
165
+ readonly pattern: RegExp;
166
+ /** If true, no further rules are tested after this one matches. */
167
+ readonly exclusive?: boolean;
168
+ /** Optional attrs to set on the block when the rule fires. */
169
+ readonly attrs?: Record<string, unknown>;
170
+ }
171
+ /**
172
+ * Shortcut definition for {@link BlockTypeDef}.
173
+ */
174
+ export interface BlockShortcutDef {
175
+ /** The keyboard shortcut descriptor. */
176
+ readonly shortcut: ShortcutDescriptor;
177
+ /** Optional payload passed to the toggle command. */
178
+ readonly payload?: unknown;
179
+ }
180
+ /**
181
+ * Configuration for {@link defineBlockType}.
182
+ */
183
+ export interface BlockTypeDef {
184
+ /** The block type string (e.g., "aside", "note"). */
185
+ readonly blockType: string;
186
+ /**
187
+ * Custom plugin ID. Defaults to `"block-<blockType>"`.
188
+ */
189
+ readonly pluginId?: string;
190
+ /** Default attrs applied when a block of this type is created. */
191
+ readonly defaultAttrs?: Record<string, unknown>;
192
+ /** Validator for block attrs. Return `true` if valid. */
193
+ readonly validate?: (attrs: Record<string, unknown>) => boolean;
194
+ /**
195
+ * Toggle command configuration.
196
+ *
197
+ * - A `string` registers a simple toggle command (no attrs).
198
+ * - An object with `name` and `attrs` registers a toggle with static attrs.
199
+ *
200
+ * Omit to skip command registration.
201
+ */
202
+ readonly toggleCommand?: string | {
203
+ readonly name: string;
204
+ readonly attrs?: Record<string, unknown>;
205
+ };
206
+ /**
207
+ * Input rules that convert typed prefixes into this block type.
208
+ * Each rule fires `delete_text` + `set_block_type` + optional `set_block_attrs`.
209
+ */
210
+ readonly inputRules?: ReadonlyArray<BlockInputRuleDef>;
211
+ /**
212
+ * Keyboard shortcuts. Each maps to the toggle command with optional payload.
213
+ * Requires `toggleCommand` to be set.
214
+ */
215
+ readonly shortcuts?: ReadonlyArray<BlockShortcutDef>;
216
+ /** The block renderer applied to block elements. */
217
+ readonly renderer: BlockRenderer;
218
+ /** Optional attr renderers keyed by attribute name. */
219
+ readonly attrRenderers?: Readonly<Record<string, BlockAttrRenderer>>;
220
+ }
221
+ /**
222
+ * Define a block type plugin.
223
+ *
224
+ * Creates a {@link WebPlugin} that registers a block type with optional
225
+ * validation, a toggle command via `createToggleBlockTypeCommand()`,
226
+ * input rules for prefix-based conversion, keyboard shortcuts, and
227
+ * a block renderer.
228
+ *
229
+ * @param config - Block type definition
230
+ * @returns A WebPlugin ready for `createWebEditor({ webPlugins: [...] })`
231
+ *
232
+ * @example
233
+ * ```ts
234
+ * const aside = defineBlockType({
235
+ * blockType: 'aside',
236
+ * toggleCommand: 'toggleAside',
237
+ * inputRules: [{ pattern: /^!> $/, exclusive: true }],
238
+ * shortcuts: [{ shortcut: { key: 'a', mod: true, alt: true } }],
239
+ * renderer: { apply(el) { el.classList.add('rtif-aside'); } },
240
+ * });
241
+ * ```
242
+ */
243
+ export declare function defineBlockType(config: BlockTypeDef): WebPlugin;
244
+ /**
245
+ * Install an array of {@link WebPlugin} objects into an engine and renderer registries.
246
+ *
247
+ * For each plugin:
248
+ * 1. Calls `engine.use(wp.plugin)` to register the engine plugin.
249
+ * 2. Registers all mark renderers from `wp.marks`.
250
+ * 3. Registers all block renderers from `wp.blocks`.
251
+ * 4. Registers all attr renderers from `wp.attrs`.
252
+ * 5. Registers all span replacers from `wp.replacers`.
253
+ *
254
+ * @param plugins - The web plugins to install
255
+ * @param engine - The RTIF engine instance
256
+ * @param markRenderers - The mark renderer registry
257
+ * @param blockRenderers - The block renderer registry
258
+ *
259
+ * @example
260
+ * ```ts
261
+ * installWebPlugins([highlight, aside], engine, markRenderers, blockRenderers);
262
+ * ```
263
+ */
264
+ export declare function installWebPlugins(plugins: ReadonlyArray<WebPlugin>, engine: IEditorEngine, markRenderers: MarkRendererRegistry, blockRenderers: BlockRendererRegistry): void;
265
+ //# sourceMappingURL=plugin-kit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-kit.d.ts","sourceRoot":"","sources":["../src/plugin-kit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAElF,OAAO,KAAK,EAAE,YAAY,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC3F,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAQnG;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,SAAS;IACxB,yDAAyD;IACzD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB,yCAAyC;IACzC,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;IAExD,2CAA2C;IAC3C,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC;IAE1D,yDAAyD;IACzD,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAE7D,yCAAyC;IACzC,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;CAC7D;AAMD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,6DAA6D;IAC7D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAE3B;;OAEG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAE9B,yDAAyD;IACzD,QAAQ,CAAC,QAAQ,CAAC,EAAE,kBAAkB,CAAC;IAEvC,kDAAkD;IAClD,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,cAAc,GAAG,SAAS,CA4BnE;AAMD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,6CAA6C;IAC7C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,YAAY,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC;IAErD,sDAAsD;IACtD,QAAQ,CAAC,QAAQ,CAAC,EAAE,kBAAkB,CAAC;CACxC;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,iEAAiE;IACjE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B;;OAEG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAE3B;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;IAE/C,2CAA2C;IAC3C,QAAQ,CAAC,UAAU,EAAE,iBAAiB,CAAC;IAEvC,4DAA4D;IAC5D,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAE/B,kDAAkD;IAClD,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,oBAAoB,GAAG,SAAS,CAgC/E;AAMD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,+EAA+E;IAC/E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB,mEAAmE;IACnE,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAE7B,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC1C;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,wCAAwC;IACxC,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;IAEtC,qDAAqD;IACrD,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,qDAAqD;IACrD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B;;OAEG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAE3B,kEAAkE;IAClE,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAEhD,yDAAyD;IACzD,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC;IAEhE;;;;;;;OAOG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG;QAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAC1C,CAAC;IAEF;;;OAGG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAC;IAEvD;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAErD,oDAAoD;IACpD,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IAEjC,uDAAuD;IACvD,QAAQ,CAAC,aAAa,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC;CACtE;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,SAAS,CAsF/D;AAMD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,aAAa,CAAC,SAAS,CAAC,EACjC,MAAM,EAAE,aAAa,EACrB,aAAa,EAAE,oBAAoB,EACnC,cAAc,EAAE,qBAAqB,GACpC,IAAI,CA4BN"}
@@ -0,0 +1,234 @@
1
+ /**
2
+ * Plugin kit — DX helper for defining custom RTIF web plugins.
3
+ *
4
+ * Provides typed factory functions that bundle an engine {@link Plugin} with
5
+ * web-layer renderers ({@link MarkRenderer}, {@link BlockRenderer},
6
+ * {@link BlockAttrRenderer}, {@link SpanReplacer}) in a single
7
+ * {@link WebPlugin} definition.
8
+ *
9
+ * Three factories cover the most common plugin patterns:
10
+ * - {@link defineBooleanMark} — on/off marks (highlight, subscript, etc.)
11
+ * - {@link defineParameterizedMark} — value-carrying marks (colors, sizes)
12
+ * - {@link defineBlockType} — toggle block types (aside, blockquote-style)
13
+ *
14
+ * The {@link installWebPlugins} utility registers all engine plugins and
15
+ * renderers from an array of {@link WebPlugin} objects.
16
+ *
17
+ * @module
18
+ */
19
+ import { createToggleMarkCommand, createSetMarkCommand, createRemoveMarkCommand } from './plugins/mark-utils.js';
20
+ import { createToggleBlockTypeCommand, getBlockStartOffset } from './plugins/block-utils.js';
21
+ /**
22
+ * Define a boolean (on/off) mark plugin.
23
+ *
24
+ * Creates a {@link WebPlugin} that registers a mark type with `validate: v === true`,
25
+ * a toggle command via `createToggleMarkCommand()`, an optional keyboard shortcut,
26
+ * and a mark renderer.
27
+ *
28
+ * @param config - Boolean mark definition
29
+ * @returns A WebPlugin ready for `createWebEditor({ webPlugins: [...] })`
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * const highlight = defineBooleanMark({
34
+ * markType: 'highlight',
35
+ * shortcut: { key: 'h', mod: true, shift: true },
36
+ * renderer: { apply(el) { el.style.backgroundColor = 'yellow'; } },
37
+ * });
38
+ * ```
39
+ */
40
+ export function defineBooleanMark(config) {
41
+ const { markType, pluginId = `mark-${markType}`, commandName = `toggleMark:${markType}`, shortcut, renderer, } = config;
42
+ const plugin = {
43
+ id: pluginId,
44
+ init(ctx) {
45
+ ctx.registerMarkType(markType, {
46
+ validate: (value) => value === true,
47
+ });
48
+ ctx.registerCommand(commandName, createToggleMarkCommand(markType));
49
+ if (shortcut) {
50
+ ctx.registerShortcut(shortcut, commandName);
51
+ }
52
+ },
53
+ };
54
+ return {
55
+ plugin,
56
+ marks: { [markType]: renderer },
57
+ };
58
+ }
59
+ /**
60
+ * Define a parameterized (value-carrying) mark plugin.
61
+ *
62
+ * Creates a {@link WebPlugin} that registers a mark type with custom validation,
63
+ * a "set" command via `createSetMarkCommand()`, a "remove" command via
64
+ * `createRemoveMarkCommand()`, optional keyboard shortcuts, and a mark renderer.
65
+ *
66
+ * @param config - Parameterized mark definition
67
+ * @returns A WebPlugin ready for `createWebEditor({ webPlugins: [...] })`
68
+ *
69
+ * @example
70
+ * ```ts
71
+ * const bgColor = defineParameterizedMark({
72
+ * markType: 'bgColor',
73
+ * validate: (v) => typeof v === 'string' && v.length > 0,
74
+ * setCommand: {
75
+ * name: 'setBgColor',
76
+ * extractValue: (p) => (p as { color: string }).color,
77
+ * },
78
+ * removeCommand: 'removeBgColor',
79
+ * renderer: { apply(el, value) { el.style.backgroundColor = value as string; } },
80
+ * });
81
+ * ```
82
+ */
83
+ export function defineParameterizedMark(config) {
84
+ const { markType, pluginId = `mark-${markType}`, validate, setCommand, removeCommand, renderer, } = config;
85
+ const plugin = {
86
+ id: pluginId,
87
+ init(ctx) {
88
+ ctx.registerMarkType(markType, { validate });
89
+ ctx.registerCommand(setCommand.name, createSetMarkCommand(markType, setCommand.extractValue));
90
+ ctx.registerCommand(removeCommand, createRemoveMarkCommand(markType));
91
+ if (setCommand.shortcut) {
92
+ ctx.registerShortcut(setCommand.shortcut, setCommand.name);
93
+ }
94
+ },
95
+ };
96
+ return {
97
+ plugin,
98
+ marks: { [markType]: renderer },
99
+ };
100
+ }
101
+ /**
102
+ * Define a block type plugin.
103
+ *
104
+ * Creates a {@link WebPlugin} that registers a block type with optional
105
+ * validation, a toggle command via `createToggleBlockTypeCommand()`,
106
+ * input rules for prefix-based conversion, keyboard shortcuts, and
107
+ * a block renderer.
108
+ *
109
+ * @param config - Block type definition
110
+ * @returns A WebPlugin ready for `createWebEditor({ webPlugins: [...] })`
111
+ *
112
+ * @example
113
+ * ```ts
114
+ * const aside = defineBlockType({
115
+ * blockType: 'aside',
116
+ * toggleCommand: 'toggleAside',
117
+ * inputRules: [{ pattern: /^!> $/, exclusive: true }],
118
+ * shortcuts: [{ shortcut: { key: 'a', mod: true, alt: true } }],
119
+ * renderer: { apply(el) { el.classList.add('rtif-aside'); } },
120
+ * });
121
+ * ```
122
+ */
123
+ export function defineBlockType(config) {
124
+ const { blockType, pluginId = `block-${blockType}`, defaultAttrs, validate, toggleCommand, inputRules, shortcuts, renderer, attrRenderers, } = config;
125
+ // Resolve toggle command name and attrs
126
+ const commandName = typeof toggleCommand === 'string'
127
+ ? toggleCommand
128
+ : toggleCommand?.name;
129
+ const commandAttrs = typeof toggleCommand === 'object'
130
+ ? toggleCommand.attrs
131
+ : undefined;
132
+ const plugin = {
133
+ id: pluginId,
134
+ init(ctx) {
135
+ // Register block type
136
+ const blockConfig = {};
137
+ if (defaultAttrs !== undefined) {
138
+ blockConfig.defaultAttrs = defaultAttrs;
139
+ }
140
+ if (validate !== undefined) {
141
+ blockConfig.validate = validate;
142
+ }
143
+ ctx.registerBlockType(blockType, blockConfig);
144
+ // Register toggle command
145
+ if (commandName) {
146
+ ctx.registerCommand(commandName, createToggleBlockTypeCommand(blockType, commandAttrs));
147
+ }
148
+ // Register input rules
149
+ if (inputRules) {
150
+ for (const rule of inputRules) {
151
+ ctx.registerInputRule({
152
+ pattern: rule.pattern,
153
+ exclusive: rule.exclusive,
154
+ handler(engine, match, blockId) {
155
+ const blockStart = getBlockStartOffset(engine.state.doc, blockId);
156
+ const prefixLength = match[0].length;
157
+ const ops = [
158
+ { type: 'delete_text', offset: blockStart, count: prefixLength },
159
+ { type: 'set_block_type', blockId, blockType },
160
+ ];
161
+ if (rule.attrs) {
162
+ ops.push({ type: 'set_block_attrs', blockId, attrs: rule.attrs });
163
+ }
164
+ engine.dispatch(ops);
165
+ },
166
+ });
167
+ }
168
+ }
169
+ // Register shortcuts
170
+ if (shortcuts && commandName) {
171
+ for (const s of shortcuts) {
172
+ ctx.registerShortcut(s.shortcut, commandName, s.payload);
173
+ }
174
+ }
175
+ },
176
+ };
177
+ const result = {
178
+ plugin,
179
+ blocks: { [blockType]: renderer },
180
+ };
181
+ if (attrRenderers && Object.keys(attrRenderers).length > 0) {
182
+ result.attrs = attrRenderers;
183
+ }
184
+ return result;
185
+ }
186
+ // ---------------------------------------------------------------------------
187
+ // installWebPlugins
188
+ // ---------------------------------------------------------------------------
189
+ /**
190
+ * Install an array of {@link WebPlugin} objects into an engine and renderer registries.
191
+ *
192
+ * For each plugin:
193
+ * 1. Calls `engine.use(wp.plugin)` to register the engine plugin.
194
+ * 2. Registers all mark renderers from `wp.marks`.
195
+ * 3. Registers all block renderers from `wp.blocks`.
196
+ * 4. Registers all attr renderers from `wp.attrs`.
197
+ * 5. Registers all span replacers from `wp.replacers`.
198
+ *
199
+ * @param plugins - The web plugins to install
200
+ * @param engine - The RTIF engine instance
201
+ * @param markRenderers - The mark renderer registry
202
+ * @param blockRenderers - The block renderer registry
203
+ *
204
+ * @example
205
+ * ```ts
206
+ * installWebPlugins([highlight, aside], engine, markRenderers, blockRenderers);
207
+ * ```
208
+ */
209
+ export function installWebPlugins(plugins, engine, markRenderers, blockRenderers) {
210
+ for (const wp of plugins) {
211
+ engine.use(wp.plugin);
212
+ if (wp.marks) {
213
+ for (const [markType, renderer] of Object.entries(wp.marks)) {
214
+ markRenderers.register(markType, renderer);
215
+ }
216
+ }
217
+ if (wp.blocks) {
218
+ for (const [blockType, renderer] of Object.entries(wp.blocks)) {
219
+ blockRenderers.register(blockType, renderer);
220
+ }
221
+ }
222
+ if (wp.attrs) {
223
+ for (const [attrName, renderer] of Object.entries(wp.attrs)) {
224
+ blockRenderers.registerAttrRenderer(attrName, renderer);
225
+ }
226
+ }
227
+ if (wp.replacers) {
228
+ for (const [markType, replacer] of Object.entries(wp.replacers)) {
229
+ markRenderers.registerReplacer(markType, replacer);
230
+ }
231
+ }
232
+ }
233
+ }
234
+ //# sourceMappingURL=plugin-kit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-kit.js","sourceRoot":"","sources":["../src/plugin-kit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Alignment paragraph formatting plugin — registers four commands that set or
3
+ * remove the `align` block attr on the block at the cursor.
4
+ *
5
+ * Unlike block type plugins, the alignment plugin does NOT change the block's
6
+ * `type`. It works on any block type by setting `attrs.align` via
7
+ * `set_block_attrs`.
8
+ *
9
+ * @module
10
+ */
11
+ import type { Plugin } from '@rtif-sdk/engine';
12
+ /**
13
+ * Command name constants for the alignment plugin.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * engine.exec(AlignmentCommands.CENTER);
18
+ * engine.exec(AlignmentCommands.LEFT);
19
+ * ```
20
+ */
21
+ export declare const AlignmentCommands: {
22
+ readonly LEFT: "align:left";
23
+ readonly CENTER: "align:center";
24
+ readonly RIGHT: "align:right";
25
+ readonly JUSTIFY: "align:justify";
26
+ };
27
+ /**
28
+ * The four supported alignment values.
29
+ *
30
+ * `'left'` is the default alignment and is represented by the absence of the
31
+ * `align` attr (i.e., `align: null` or `align: undefined`).
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * const alignment: Alignment = 'center';
36
+ * ```
37
+ */
38
+ export type Alignment = 'left' | 'center' | 'right' | 'justify';
39
+ /**
40
+ * Create the alignment paragraph formatting plugin.
41
+ *
42
+ * Registers four commands:
43
+ * - `align:left` — removes the `align` attr (left is the default)
44
+ * - `align:center` — sets `align` to `'center'`
45
+ * - `align:right` — sets `align` to `'right'`
46
+ * - `align:justify` — sets `align` to `'justify'`
47
+ *
48
+ * Each command's `isActive()` returns `true` when the cursor block has the
49
+ * matching alignment. `align:left` is active when there is no `align` attr.
50
+ *
51
+ * No input rules, no keyboard shortcuts, no block type registrations.
52
+ *
53
+ * @returns A plugin instance ready for `engine.use()`
54
+ *
55
+ * @example
56
+ * ```ts
57
+ * const engine = createEngine(initialDoc);
58
+ * engine.use(alignmentPlugin());
59
+ *
60
+ * // Center the block at the cursor
61
+ * engine.exec(AlignmentCommands.CENTER);
62
+ *
63
+ * // Revert to default left alignment
64
+ * engine.exec(AlignmentCommands.LEFT);
65
+ * ```
66
+ */
67
+ export declare function alignmentPlugin(): Plugin;
68
+ //# sourceMappingURL=alignment-plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alignment-plugin.d.ts","sourceRoot":"","sources":["../../src/plugins/alignment-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAiB,MAAM,kBAAkB,CAAC;AAG9D;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB;;;;;CAKpB,CAAC;AAEX;;;;;;;;;;GAUG;AACH,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;AAkBhE;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAgCxC"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Alignment paragraph formatting plugin — registers four commands that set or
3
+ * remove the `align` block attr on the block at the cursor.
4
+ *
5
+ * Unlike block type plugins, the alignment plugin does NOT change the block's
6
+ * `type`. It works on any block type by setting `attrs.align` via
7
+ * `set_block_attrs`.
8
+ *
9
+ * @module
10
+ */
11
+ import { getBlockAtCursor } from './block-utils.js';
12
+ /**
13
+ * Command name constants for the alignment plugin.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * engine.exec(AlignmentCommands.CENTER);
18
+ * engine.exec(AlignmentCommands.LEFT);
19
+ * ```
20
+ */
21
+ export const AlignmentCommands = {
22
+ LEFT: 'align:left',
23
+ CENTER: 'align:center',
24
+ RIGHT: 'align:right',
25
+ JUSTIFY: 'align:justify',
26
+ };
27
+ /**
28
+ * Read the current alignment of a block, defaulting to `'left'` when no
29
+ * `align` attr is present.
30
+ *
31
+ * @param engine - The editor engine instance
32
+ * @returns The current alignment of the cursor block
33
+ */
34
+ function getCurrentAlignment(engine) {
35
+ const block = getBlockAtCursor(engine);
36
+ const align = block.attrs?.align;
37
+ if (align === 'center' || align === 'right' || align === 'justify') {
38
+ return align;
39
+ }
40
+ return 'left';
41
+ }
42
+ /**
43
+ * Create the alignment paragraph formatting plugin.
44
+ *
45
+ * Registers four commands:
46
+ * - `align:left` — removes the `align` attr (left is the default)
47
+ * - `align:center` — sets `align` to `'center'`
48
+ * - `align:right` — sets `align` to `'right'`
49
+ * - `align:justify` — sets `align` to `'justify'`
50
+ *
51
+ * Each command's `isActive()` returns `true` when the cursor block has the
52
+ * matching alignment. `align:left` is active when there is no `align` attr.
53
+ *
54
+ * No input rules, no keyboard shortcuts, no block type registrations.
55
+ *
56
+ * @returns A plugin instance ready for `engine.use()`
57
+ *
58
+ * @example
59
+ * ```ts
60
+ * const engine = createEngine(initialDoc);
61
+ * engine.use(alignmentPlugin());
62
+ *
63
+ * // Center the block at the cursor
64
+ * engine.exec(AlignmentCommands.CENTER);
65
+ *
66
+ * // Revert to default left alignment
67
+ * engine.exec(AlignmentCommands.LEFT);
68
+ * ```
69
+ */
70
+ export function alignmentPlugin() {
71
+ return {
72
+ id: 'attr-alignment',
73
+ init(ctx) {
74
+ const alignments = ['left', 'center', 'right', 'justify'];
75
+ for (const alignment of alignments) {
76
+ ctx.registerCommand(`align:${alignment}`, {
77
+ execute(engine) {
78
+ const block = getBlockAtCursor(engine);
79
+ // 'left' is the default — remove the attr instead of storing it
80
+ const value = alignment === 'left' ? null : alignment;
81
+ engine.dispatch({
82
+ type: 'set_block_attrs',
83
+ blockId: block.id,
84
+ attrs: { align: value },
85
+ });
86
+ },
87
+ canExecute(_engine) {
88
+ return true;
89
+ },
90
+ isActive(engine) {
91
+ return getCurrentAlignment(engine) === alignment;
92
+ },
93
+ });
94
+ }
95
+ },
96
+ };
97
+ }
98
+ //# sourceMappingURL=alignment-plugin.js.map