@pilotiq/tiptap 3.10.5 → 3.10.6

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 (55) hide show
  1. package/CHANGELOG.md +745 -0
  2. package/boost/guidelines.md +268 -0
  3. package/boost/skills/pilotiq-tiptap-blocks/SKILL.md +48 -0
  4. package/boost/skills/pilotiq-tiptap-blocks/rules/custom-blocks.md +90 -0
  5. package/boost/skills/pilotiq-tiptap-blocks/rules/slash-menu-and-mentions.md +101 -0
  6. package/boost/skills/pilotiq-tiptap-blocks/rules/toolbar-and-extensibility.md +161 -0
  7. package/package.json +4 -3
  8. package/src/Block.ts +0 -75
  9. package/src/MentionProvider.ts +0 -153
  10. package/src/PlainTextEditor.dom.test.ts +0 -111
  11. package/src/PlainTextEditor.test.ts +0 -158
  12. package/src/PlainTextEditor.ts +0 -229
  13. package/src/RichTextField.test.ts +0 -447
  14. package/src/RichTextField.ts +0 -508
  15. package/src/extensions/AiInlineDiffExtension.ts +0 -286
  16. package/src/extensions/AiSuggestionExtension.test.ts +0 -141
  17. package/src/extensions/AiSuggestionExtension.ts +0 -522
  18. package/src/extensions/BlockNodeExtension.ts +0 -134
  19. package/src/extensions/DragHandleExtension.ts +0 -184
  20. package/src/extensions/GridExtension.test.ts +0 -31
  21. package/src/extensions/GridExtension.ts +0 -138
  22. package/src/extensions/MentionExtension.ts +0 -248
  23. package/src/extensions/MergeTagExtension.ts +0 -75
  24. package/src/extensions/SlashCommandExtension.test.ts +0 -147
  25. package/src/extensions/SlashCommandExtension.ts +0 -332
  26. package/src/extensions/TextSizeMarks.ts +0 -73
  27. package/src/index.ts +0 -62
  28. package/src/markdownExtension.ts +0 -19
  29. package/src/markdownStorage.ts +0 -49
  30. package/src/plugin.test.ts +0 -19
  31. package/src/plugin.ts +0 -26
  32. package/src/react/AiSuggestionBanner.tsx +0 -185
  33. package/src/react/BlockNodeView.tsx +0 -99
  34. package/src/react/BlockSidePanel.dom.test.tsx +0 -38
  35. package/src/react/BlockSidePanel.test.ts +0 -412
  36. package/src/react/BlockSidePanel.tsx +0 -451
  37. package/src/react/CollabTextRenderer.tsx +0 -228
  38. package/src/react/FloatingToolbar.tsx +0 -304
  39. package/src/react/MarkdownEditor.tsx +0 -603
  40. package/src/react/MentionMenu.tsx +0 -120
  41. package/src/react/Palette.tsx +0 -86
  42. package/src/react/SlashMenu.tsx +0 -129
  43. package/src/react/TableFloatingToolbar.tsx +0 -154
  44. package/src/react/TiptapEditor.dom.test.tsx +0 -112
  45. package/src/react/TiptapEditor.tsx +0 -777
  46. package/src/react/Toolbar.tsx +0 -438
  47. package/src/react/toolbarButtons.tsx +0 -579
  48. package/src/react/useAiInlineDiff.ts +0 -342
  49. package/src/react/useAiSuggestionBridge.ts +0 -223
  50. package/src/register.test.ts +0 -14
  51. package/src/register.ts +0 -42
  52. package/src/render.test.ts +0 -745
  53. package/src/render.ts +0 -480
  54. package/src/surgicalOps.ts +0 -205
  55. package/src/test/setup.ts +0 -64
@@ -1,508 +0,0 @@
1
- import { Field, type FieldMeta, type FieldType, type RenderContext } from '@pilotiq/pilotiq'
2
- import { Block, type BlockMeta } from './Block.js'
3
- import {
4
- MentionProvider,
5
- type MentionItem,
6
- type MentionProviderMeta,
7
- type MentionResolverContext,
8
- } from './MentionProvider.js'
9
-
10
- /**
11
- * Identifier for a single toolbar action. The renderer maps each id to a
12
- * Tiptap command + an icon. Unknown ids are rendered as nothing — keeps the
13
- * surface forward-compatible: a config that targets a button shipped in a
14
- * later version stays inert today instead of crashing.
15
- *
16
- * Buttons that aren't yet shipped (textColor, highlight, attachFiles, table
17
- * variants, …) still appear in the union — registering them in user code is
18
- * a no-op today and lights up automatically when a later phase wires them.
19
- */
20
- export type ToolbarButtonId =
21
- // Inline marks
22
- | 'bold' | 'italic' | 'underline' | 'strike' | 'subscript' | 'superscript' | 'code'
23
- // Inline size variants — `lead` paragraph styling + semantic `<small>`.
24
- | 'lead' | 'small'
25
- // Block / heading switches
26
- | 'paragraph' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'
27
- // Alignment
28
- | 'alignStart' | 'alignCenter' | 'alignEnd' | 'alignJustify'
29
- // Block primitives
30
- | 'blockquote' | 'codeBlock' | 'bulletList' | 'orderedList' | 'horizontalRule'
31
- // Editing helpers
32
- | 'clearFormatting' | 'link' | 'undo' | 'redo'
33
- // Reserved — wired in later phases
34
- | 'textColor' | 'highlight' | 'attachFiles'
35
- | 'table' | 'tableAddColumnBefore' | 'tableAddColumnAfter' | 'tableDeleteColumn'
36
- | 'tableAddRowBefore' | 'tableAddRowAfter' | 'tableDeleteRow'
37
- | 'tableMergeCells' | 'tableSplitCell'
38
- | 'tableToggleHeaderRow' | 'tableToggleHeaderCell' | 'tableDelete'
39
- // Collapsible `<details>` block — single button, opt-in via `.toolbarButtons`.
40
- | 'details'
41
- // Multi-column grid layout. `grid` inserts a 2-column grid by default;
42
- // `gridDelete` unwraps the enclosing grid. Both default-off — opt-in via
43
- // `.toolbarButtons([...])`.
44
- | 'grid' | 'gridDelete'
45
-
46
- export type ToolbarGroups = ToolbarButtonId[][]
47
-
48
- /** Default top-level toolbar groups — mirrors the reference admin's layout. */
49
- export const DEFAULT_TOOLBAR_GROUPS: ToolbarGroups = [
50
- ['bold', 'italic', 'underline', 'strike', 'subscript', 'superscript', 'link'],
51
- ['h2', 'h3'],
52
- ['alignStart', 'alignCenter', 'alignEnd'],
53
- ['blockquote', 'codeBlock', 'bulletList', 'orderedList'],
54
- ['undo', 'redo'],
55
- ]
56
-
57
- export type RichTextStorage = 'json' | 'html'
58
-
59
- /**
60
- * One swatch in a text-color or highlight palette. `value` is what gets
61
- * written into the editor (a CSS color); `dark` is an optional override
62
- * shown when the editor's parent is in dark mode.
63
- */
64
- export interface ColorSwatch {
65
- value: string
66
- label: string
67
- dark?: string
68
- }
69
-
70
- /**
71
- * Tailwind-flavored fallback palette. Used when the field doesn't override
72
- * the colors via `.textColors([...])`. Mirrors the reference admin's
73
- * "popular Tailwind hues" default.
74
- */
75
- export const DEFAULT_TEXT_COLORS: ColorSwatch[] = [
76
- { value: '#ef4444', label: 'Red' },
77
- { value: '#f97316', label: 'Orange' },
78
- { value: '#eab308', label: 'Yellow' },
79
- { value: '#22c55e', label: 'Green' },
80
- { value: '#06b6d4', label: 'Cyan' },
81
- { value: '#3b82f6', label: 'Blue' },
82
- { value: '#a855f7', label: 'Purple' },
83
- { value: '#ec4899', label: 'Pink' },
84
- { value: '#000000', label: 'Black', dark: '#ffffff' },
85
- { value: '#6b7280', label: 'Gray' },
86
- ]
87
-
88
- export const DEFAULT_HIGHLIGHT_COLORS: ColorSwatch[] = [
89
- { value: '#fef08a', label: 'Yellow' },
90
- { value: '#fed7aa', label: 'Orange' },
91
- { value: '#fecaca', label: 'Red' },
92
- { value: '#bbf7d0', label: 'Green' },
93
- { value: '#bfdbfe', label: 'Blue' },
94
- { value: '#e9d5ff', label: 'Purple' },
95
- { value: '#f5d0fe', label: 'Pink' },
96
- { value: '#e5e7eb', label: 'Gray' },
97
- ]
98
-
99
- export type RichTextAttachmentVisibility = 'public' | 'private'
100
-
101
- // Inherits `fieldType` from FieldMeta; we don't narrow it here because the
102
- // `FieldType` union admits `(string & {})` which makes the narrow `'richtext'`
103
- // literal incompatible during interface extension. `fieldType` is always
104
- // `'richtext'` at runtime.
105
- export interface RichTextFieldMeta extends FieldMeta {
106
- blocks: BlockMeta[]
107
- slashCommand: boolean
108
- /** Always-on top-level toolbar groups. `null` = hidden. */
109
- toolbarGroups: ToolbarGroups | null
110
- /** Selection-anchored quick-format toolbar. */
111
- floatingToolbar: boolean
112
- storage: RichTextStorage
113
- /** Text-color palette shown when the `textColor` button opens. */
114
- textColors: ColorSwatch[]
115
- /** Whether to expose a free-form color picker below the swatches. */
116
- customTextColors: boolean
117
- /** Highlight palette shown when the `highlight` button opens. */
118
- highlightColors: ColorSwatch[]
119
- /** Allow drag-resize of inserted images via a corner handle. */
120
- resizableImages: boolean
121
- /** MIME-type allowlist for the `attachFiles` picker (e.g. `['image/*']`). */
122
- fileAttachmentsAcceptedFileTypes?: string[]
123
- /** Per-file size cap in bytes; the upload route also enforces this. */
124
- fileAttachmentsMaxSize?: number
125
- /** Sub-directory hint forwarded to the upload adapter. */
126
- fileAttachmentsDirectory?: string
127
- /** Adapter-defined visibility hint — `'public'` or `'private'`. */
128
- fileAttachmentsVisibility?: RichTextAttachmentVisibility
129
- /** URL of the panel's `_uploads` route. Only stamped when both
130
- * `RenderContext.uploadUrl` and `RenderContext.hasUploadAdapter` are
131
- * set — so its presence is itself the "adapter is wired" signal that
132
- * the slash-menu Image entry consults. */
133
- uploadUrl?: string
134
- /**
135
- * Identifier list for `{{ tag }}` placeholders surfaced in the slash menu.
136
- * Empty array = no merge tags.
137
- */
138
- mergeTags: string[]
139
- /**
140
- * Mention providers — one entry per trigger character (`@`, `#`, …) with
141
- * its static item list. Empty array = no mentions wired.
142
- */
143
- mentions: MentionProviderMeta[]
144
- /**
145
- * Endpoint stamped by `tagRichTextMentionUrls` when this field has at
146
- * least one async provider (`MentionProvider.itemsUsing(fn)`). The
147
- * client POSTs `{ field, trigger, query }` per keystroke; the server
148
- * runs the user resolver and returns `{ ok, items }`. Absent when
149
- * every provider on this field is static.
150
- */
151
- mentionsUrl?: string
152
- }
153
-
154
- /**
155
- * Field that renders a Tiptap-based rich-text editor with slash menu,
156
- * draggable blocks, and a custom-block API.
157
- *
158
- * @example
159
- * ```ts
160
- * RichTextField.make('body')
161
- * .label('Article body')
162
- * .placeholder('Start writing…')
163
- * .toolbarButtons([
164
- * ['bold', 'italic', 'underline', 'strike', 'link'],
165
- * ['h2', 'h3'],
166
- * ['bulletList', 'orderedList'],
167
- * ['undo', 'redo'],
168
- * ])
169
- * .blocks([
170
- * Block.make('callout').label('Callout').icon('💡').schema([
171
- * TextField.make('title'),
172
- * TextareaField.make('content').required(),
173
- * ]),
174
- * ])
175
- * ```
176
- */
177
- export class RichTextField extends Field {
178
- private _blocks: Block[] = []
179
- private _slashCommand = true
180
- /** `undefined` = use default, `null` = hidden, array = explicit override. */
181
- private _toolbarOverride: ToolbarGroups | null | undefined = undefined
182
- private _enabled: ToolbarButtonId[] = []
183
- private _disabled: ToolbarButtonId[] = []
184
- private _floatingToolbar = true
185
- private _storage: RichTextStorage = 'json'
186
- private _textColors: ColorSwatch[] | null = null
187
- private _customTextColors = false
188
- private _highlightColors: ColorSwatch[] | null = null
189
- private _resizableImages = false
190
- private _fileAttachmentsAcceptedFileTypes?: string[]
191
- private _fileAttachmentsMaxSize?: number
192
- private _fileAttachmentsDirectory?: string
193
- private _fileAttachmentsVisibility?: RichTextAttachmentVisibility
194
- private _mergeTags: string[] = []
195
- private _mentions: MentionProvider[] = []
196
- private _mentionsUrl?: string
197
-
198
- private constructor(name: string) {
199
- super(name, 'richtext' as FieldType)
200
- }
201
-
202
- static make(name: string): RichTextField {
203
- return new RichTextField(name)
204
- }
205
-
206
- /** Custom blocks available via the slash menu. */
207
- blocks(blocks: Block[]): this {
208
- this._blocks = blocks
209
- return this
210
- }
211
-
212
- /** Toggle the slash menu (`/`) on/off. Defaults to `true`. */
213
- slashCommand(enabled: boolean): this {
214
- this._slashCommand = enabled
215
- return this
216
- }
217
-
218
- /**
219
- * Replace the top-level toolbar layout. Pass nested arrays — each inner
220
- * array becomes a button group separated by a thin divider.
221
- *
222
- * Pass `null` (or call `toolbar(false)`) to hide the toolbar entirely.
223
- */
224
- toolbarButtons(groups: ToolbarGroups | null): this {
225
- this._toolbarOverride = groups
226
- return this
227
- }
228
-
229
- /** Add buttons on top of whichever layout is active. */
230
- enableToolbarButtons(buttons: ToolbarButtonId[]): this {
231
- this._enabled = [...this._enabled, ...buttons]
232
- return this
233
- }
234
-
235
- /** Remove buttons from whichever layout is active. */
236
- disableToolbarButtons(buttons: ToolbarButtonId[]): this {
237
- this._disabled = [...this._disabled, ...buttons]
238
- return this
239
- }
240
-
241
- /**
242
- * Toolbar visibility shortcut.
243
- *
244
- * - `true` (default) — show the top-level toolbar with the default groups
245
- * unless `toolbarButtons([...])` was called.
246
- * - `false` — hide the top-level toolbar.
247
- *
248
- * Selection-anchored floating toolbar is controlled separately via
249
- * {@link floatingToolbar}.
250
- */
251
- toolbar(enabled: boolean): this {
252
- if (!enabled) this._toolbarOverride = null
253
- else if (this._toolbarOverride === null) this._toolbarOverride = undefined
254
- return this
255
- }
256
-
257
- /** Toggle the selection-anchored quick-format toolbar. Defaults to `true`. */
258
- floatingToolbar(enabled: boolean): this {
259
- this._floatingToolbar = enabled
260
- return this
261
- }
262
-
263
- /**
264
- * Storage format for the field's value.
265
- *
266
- * - `'json'` (default) — Tiptap JSON document, parsed via `JSON.parse`.
267
- * - `'html'` — serialized HTML string, useful for display surfaces that
268
- * can't render JSON (e.g. existing blog/CMS columns).
269
- */
270
- storage(format: RichTextStorage): this {
271
- this._storage = format
272
- return this
273
- }
274
-
275
- /**
276
- * Replace the text-color palette opened by the `textColor` toolbar button.
277
- * Pass `null` to fall back to the default Tailwind-derived palette.
278
- *
279
- * @example
280
- * ```ts
281
- * RichTextField.make('body').textColors([
282
- * { value: '#1e293b', label: 'Slate' },
283
- * { value: '#dc2626', label: 'Red', dark: '#fca5a5' },
284
- * ])
285
- * ```
286
- */
287
- textColors(palette: ColorSwatch[] | null): this {
288
- this._textColors = palette
289
- return this
290
- }
291
-
292
- /** Show a free-form color picker below the swatches. */
293
- customTextColors(enabled = true): this {
294
- this._customTextColors = enabled
295
- return this
296
- }
297
-
298
- /** Replace the highlight palette opened by the `highlight` toolbar button. */
299
- highlightColors(palette: ColorSwatch[] | null): this {
300
- this._highlightColors = palette
301
- return this
302
- }
303
-
304
- /**
305
- * Allow drag-resizing of inserted images via a corner handle. Off by
306
- * default — when enabled, the editor mounts a NodeView that wraps the
307
- * image in a resize-aware wrapper and writes `width` / `height` attrs
308
- * back into the document.
309
- */
310
- resizableImages(enabled = true): this {
311
- this._resizableImages = enabled
312
- return this
313
- }
314
-
315
- /**
316
- * Restrict the `attachFiles` picker to specific MIME types — passed
317
- * verbatim to the file input's `accept` attribute and re-checked
318
- * server-side by the upload route.
319
- *
320
- * @example
321
- * ```ts
322
- * RichTextField.make('body').fileAttachmentsAcceptedFileTypes(['image/*'])
323
- * ```
324
- */
325
- fileAttachmentsAcceptedFileTypes(types: string[]): this {
326
- this._fileAttachmentsAcceptedFileTypes = types
327
- return this
328
- }
329
-
330
- /** Per-file size cap in bytes for `attachFiles`. */
331
- fileAttachmentsMaxSize(bytes: number): this {
332
- this._fileAttachmentsMaxSize = bytes
333
- return this
334
- }
335
-
336
- /**
337
- * Sub-directory hint forwarded to the upload adapter alongside the
338
- * `attachFiles` payload. Adapters honor it differently (`localUpload`
339
- * writes to `<root>/<directory>/...`, S3 prepends to the key, etc.).
340
- */
341
- fileAttachmentsDirectory(d: string): this {
342
- this._fileAttachmentsDirectory = d
343
- return this
344
- }
345
-
346
- /** Adapter-defined visibility hint — `'public'` or `'private'`. */
347
- fileAttachmentsVisibility(v: RichTextAttachmentVisibility): this {
348
- this._fileAttachmentsVisibility = v
349
- return this
350
- }
351
-
352
- /**
353
- * Surface a `{{ tag }}` placeholder for each id in the slash menu under
354
- * the "Merge tags" group. The placeholder stores as a `mergeTag` atom
355
- * node and renders read-side via
356
- * `renderRichTextToHtml(content, { mergeTags: { name: 'Sleman', … } })` —
357
- * the substitution map replaces each id with the resolved value
358
- * (HTML-escaped).
359
- *
360
- * @example
361
- * ```ts
362
- * RichTextField.make('body').mergeTags(['firstName', 'company'])
363
- * ```
364
- */
365
- mergeTags(tags: string[]): this {
366
- this._mergeTags = tags
367
- return this
368
- }
369
-
370
- /**
371
- * Wire one or more mention providers. Each provider owns a trigger
372
- * character (`@` / `#` / …) and a static item list. Typing the trigger
373
- * opens a popover anchored to the cursor; picking an item inserts a
374
- * `mention` atom node carrying `id`, `label`, and `trigger`.
375
- *
376
- * Read-side rendering uses the cached label by default; pass
377
- * `renderRichTextToHtml(content, { resolveMention: (trigger, id) =>
378
- * latestLabel })` to override at display time.
379
- *
380
- * @example
381
- * ```ts
382
- * RichTextField.make('body').mentions([
383
- * MentionProvider.make('@').items([
384
- * { id: 'sleman', label: 'Sleman' },
385
- * { id: 'alex', label: 'Alex' },
386
- * ]),
387
- * ])
388
- * ```
389
- */
390
- mentions(providers: MentionProvider[]): this {
391
- this._mentions = providers
392
- return this
393
- }
394
-
395
- getBlocks(): readonly Block[] { return this._blocks }
396
- getMergeTags(): readonly string[] { return this._mergeTags }
397
- getMentionProviders(): readonly MentionProvider[] { return this._mentions }
398
- /**
399
- * `true` iff at least one provider was configured with `itemsUsing(fn)`.
400
- * Pilotiq's `tagRichTextMentionUrls` walker uses this to gate URL
401
- * stamping — fields with only static providers stay URL-less.
402
- */
403
- hasAsyncMentions(): boolean {
404
- return this._mentions.some(p => p.isAsync())
405
- }
406
- /**
407
- * Look up a provider by trigger char and run its resolver with `query`
408
- * and `ctx`. Returns the matched items, or `null` when no provider
409
- * carries that trigger. Static providers run too (using their cached
410
- * list) — keeps the dispatcher uniform; the client just won't call
411
- * the endpoint for static providers.
412
- */
413
- async resolveMention(trigger: string, query: string, ctx: MentionResolverContext): Promise<MentionItem[] | null> {
414
- const provider = this._mentions.find(p => p.getTrigger() === trigger)
415
- if (!provider) return null
416
- return await provider.runResolver(query, ctx)
417
- }
418
- /**
419
- * Render-time setter — pilotiq stamps the URL after schema resolution
420
- * via `tagRichTextMentionUrls`. The setter is idempotent; the last
421
- * call wins.
422
- */
423
- withMentionsUrl(url: string): this {
424
- this._mentionsUrl = url
425
- return this
426
- }
427
- isSlashEnabled(): boolean { return this._slashCommand }
428
- getStorage(): RichTextStorage { return this._storage }
429
- isResizableImages(): boolean { return this._resizableImages }
430
- getFileAttachmentsAcceptedFileTypes(): string[] | undefined { return this._fileAttachmentsAcceptedFileTypes }
431
- getFileAttachmentsMaxSize(): number | undefined { return this._fileAttachmentsMaxSize }
432
- getFileAttachmentsDirectory(): string | undefined { return this._fileAttachmentsDirectory }
433
- getFileAttachmentsVisibility(): RichTextAttachmentVisibility | undefined { return this._fileAttachmentsVisibility }
434
-
435
- /**
436
- * Resolve the actual button layout — base layout (override or default) with
437
- * `enableToolbarButtons` appended to the last group and
438
- * `disableToolbarButtons` filtered out across every group. Empty groups
439
- * are dropped. Returns `null` when the toolbar is hidden.
440
- */
441
- getToolbarGroups(): ToolbarGroups | null {
442
- const override = this._toolbarOverride
443
- const base: ToolbarGroups | null =
444
- override === null ? null :
445
- override === undefined ? DEFAULT_TOOLBAR_GROUPS :
446
- override
447
-
448
- if (base === null) return null
449
-
450
- const enabled = this._enabled
451
- const disabled = new Set(this._disabled)
452
-
453
- const groups = base.map((group) => group.filter((id) => !disabled.has(id)))
454
- if (enabled.length > 0) {
455
- const extras = enabled.filter((id) => !disabled.has(id))
456
- if (groups.length === 0) groups.push(extras)
457
- else {
458
- const last = groups[groups.length - 1]!
459
- groups[groups.length - 1] = [...last, ...extras]
460
- }
461
- }
462
- return groups.filter((g) => g.length > 0)
463
- }
464
-
465
- isFloatingToolbarEnabled(): boolean {
466
- return this._floatingToolbar
467
- }
468
-
469
- override toMeta(ctx?: RenderContext): RichTextFieldMeta {
470
- // RichTextField has no async resolvers, so the parent always returns
471
- // the sync FieldMeta branch — cast away the union for the spread.
472
- const base = super.toMeta(ctx) as FieldMeta
473
- // Strip `attachFiles` server-side when the panel hasn't registered an
474
- // upload adapter — same posture as `MarkdownField` and the editor
475
- // chrome stays clean. `uploadUrl` is the wire-side URL for the picker
476
- // dialog; only stamped when adapter is wired (otherwise the button is
477
- // already gone from the toolbar groups).
478
- const groups = this.getToolbarGroups()
479
- const filteredGroups = ctx?.hasUploadAdapter
480
- ? groups
481
- : groups?.map(g => g.filter(b => b !== 'attachFiles'))
482
- .filter(g => g.length > 0) ?? null
483
- return {
484
- ...base,
485
- blocks: this._blocks.map((b) => b.toMeta()),
486
- slashCommand: this._slashCommand,
487
- toolbarGroups: filteredGroups,
488
- floatingToolbar: this._floatingToolbar,
489
- storage: this._storage,
490
- textColors: this._textColors ?? DEFAULT_TEXT_COLORS,
491
- customTextColors: this._customTextColors,
492
- highlightColors: this._highlightColors ?? DEFAULT_HIGHLIGHT_COLORS,
493
- resizableImages: this._resizableImages,
494
- ...(this._fileAttachmentsAcceptedFileTypes !== undefined
495
- ? { fileAttachmentsAcceptedFileTypes: this._fileAttachmentsAcceptedFileTypes } : {}),
496
- ...(this._fileAttachmentsMaxSize !== undefined
497
- ? { fileAttachmentsMaxSize: this._fileAttachmentsMaxSize } : {}),
498
- ...(this._fileAttachmentsDirectory !== undefined
499
- ? { fileAttachmentsDirectory: this._fileAttachmentsDirectory } : {}),
500
- ...(this._fileAttachmentsVisibility !== undefined
501
- ? { fileAttachmentsVisibility: this._fileAttachmentsVisibility } : {}),
502
- ...(ctx?.uploadUrl && ctx?.hasUploadAdapter ? { uploadUrl: ctx.uploadUrl } : {}),
503
- mergeTags: [...this._mergeTags],
504
- mentions: this._mentions.map((p) => p.toMeta()),
505
- ...(this._mentionsUrl !== undefined ? { mentionsUrl: this._mentionsUrl } : {}),
506
- }
507
- }
508
- }