ckeditor5-livewire 1.8.0 → 1.10.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 (30) hide show
  1. package/dist/hooks/editable.d.ts +18 -6
  2. package/dist/hooks/editable.d.ts.map +1 -1
  3. package/dist/hooks/editor/editor.d.ts +14 -0
  4. package/dist/hooks/editor/editor.d.ts.map +1 -1
  5. package/dist/hooks/editor/plugins/livewire-sync.d.ts.map +1 -1
  6. package/dist/hooks/editor/utils/index.d.ts +0 -1
  7. package/dist/hooks/editor/utils/index.d.ts.map +1 -1
  8. package/dist/hooks/utils/index.d.ts +3 -0
  9. package/dist/hooks/utils/index.d.ts.map +1 -0
  10. package/dist/hooks/utils/is-wire-model-connected.d.ts +8 -0
  11. package/dist/hooks/utils/is-wire-model-connected.d.ts.map +1 -0
  12. package/dist/hooks/utils/root-attributes-updater.d.ts +16 -0
  13. package/dist/hooks/utils/root-attributes-updater.d.ts.map +1 -0
  14. package/dist/index.cjs +2 -2
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.mjs +160 -122
  17. package/dist/index.mjs.map +1 -1
  18. package/package.json +1 -1
  19. package/src/hooks/editable.test.ts +103 -0
  20. package/src/hooks/editable.ts +74 -32
  21. package/src/hooks/editor/editor.test.ts +68 -0
  22. package/src/hooks/editor/editor.ts +31 -1
  23. package/src/hooks/editor/plugins/livewire-sync.ts +28 -4
  24. package/src/hooks/editor/utils/index.ts +0 -1
  25. package/src/hooks/utils/index.ts +2 -0
  26. package/src/hooks/{editor/utils → utils}/is-wire-model-connected.test.ts +2 -1
  27. package/src/hooks/{editor/utils → utils}/is-wire-model-connected.ts +6 -0
  28. package/src/hooks/utils/root-attributes-updater.ts +46 -0
  29. package/dist/hooks/editor/utils/is-wire-model-connected.d.ts +0 -2
  30. package/dist/hooks/editor/utils/is-wire-model-connected.d.ts.map +0 -1
@@ -50,6 +50,58 @@ describe('editable component', () => {
50
50
  expect(editor.getData({ rootName: 'foo' })).toBe('<p>Initial foo component</p>');
51
51
  });
52
52
 
53
+ it('should apply root attributes when mounting editable', async () => {
54
+ appendMultirootEditor();
55
+
56
+ const editor = await waitForTestEditor();
57
+
58
+ livewireStub.$internal.appendComponentToDOM({
59
+ name: 'ckeditor5-editable',
60
+ el: createEditableHtmlElement(),
61
+ canonical: {
62
+ ...createEditableSnapshot('foo', '<p>Initial foo component</p>'),
63
+ rootAttributes: {
64
+ 'data-test': 'initial',
65
+ },
66
+ },
67
+ });
68
+
69
+ const root = editor.model.document.getRoot('foo')!;
70
+
71
+ expect(root.getAttribute('data-test')).toBe('initial');
72
+ });
73
+
74
+ it('should update root attributes after commit', async () => {
75
+ appendMultirootEditor();
76
+
77
+ const editor = await waitForTestEditor();
78
+
79
+ const { id } = livewireStub.$internal.appendComponentToDOM({
80
+ name: 'ckeditor5-editable',
81
+ el: createEditableHtmlElement(),
82
+ canonical: {
83
+ ...createEditableSnapshot('foo', '<p>Initial foo component</p>'),
84
+ rootAttributes: {
85
+ 'data-test': 'initial',
86
+ },
87
+ },
88
+ });
89
+
90
+ const root = editor.model.document.getRoot('foo')!;
91
+
92
+ expect(root.getAttribute('data-test')).toBe('initial');
93
+
94
+ await livewireStub.$internal.dispatchComponentCommit(id, {
95
+ rootAttributes: {
96
+ 'data-test': 'updated',
97
+ },
98
+ });
99
+
100
+ await vi.waitFor(() => {
101
+ expect(root.getAttribute('data-test')).toBe('updated');
102
+ });
103
+ });
104
+
53
105
  it('should add editable root to the editor after mounting editor (non-empty editor, other editable defined before)', async () => {
54
106
  livewireStub.$internal.appendComponentToDOM({
55
107
  name: 'ckeditor5-editable',
@@ -200,6 +252,9 @@ describe('editable component', () => {
200
252
 
201
253
  expect(input.value).toBe('<p>Initial foo component</p>');
202
254
 
255
+ // Debounce should be active only while the editor is focused.
256
+ editor.ui.focusTracker.isFocused = true;
257
+
203
258
  editor.setData({
204
259
  foo: '<p>Modified foo content</p>',
205
260
  });
@@ -212,6 +267,28 @@ describe('editable component', () => {
212
267
 
213
268
  expect(input.value).toBe('<p>Modified foo content</p>');
214
269
  });
270
+
271
+ it('should synchronize input value immediately when editor is not focused', async () => {
272
+ livewireStub.$internal.appendComponentToDOM({
273
+ name: 'ckeditor5-editable',
274
+ el: createEditableHtmlElement({
275
+ id: 'editable-foo',
276
+ }),
277
+ canonical: createEditableSnapshot('foo', '<p>Initial foo component</p>'),
278
+ });
279
+
280
+ const input = queryEditableInput('editable-foo')!;
281
+
282
+ expect(input.value).toBe('<p>Initial foo component</p>');
283
+
284
+ editor.ui.focusTracker.isFocused = false;
285
+
286
+ editor.setData({
287
+ foo: '<p>Modified foo content</p>',
288
+ });
289
+
290
+ expect(input.value).toBe('<p>Modified foo content</p>');
291
+ });
215
292
  });
216
293
 
217
294
  describe('livewire <> editor synchronization', () => {
@@ -250,6 +327,9 @@ describe('editable component', () => {
250
327
 
251
328
  expect($wire.set).toHaveBeenCalledWith('content', '<p>Initial foo component</p>');
252
329
 
330
+ // Debounce should be active only when the editor is focused.
331
+ editor.ui.focusTracker.isFocused = true;
332
+
253
333
  editor.setData({
254
334
  foo: '<p>Modified foo content</p>',
255
335
  });
@@ -262,6 +342,29 @@ describe('editable component', () => {
262
342
 
263
343
  expect($wire.set).toHaveBeenCalledWith('content', '<p>Modified foo content</p>');
264
344
  });
345
+
346
+ it('should synchronize socket content immediately when editor is not focused', async () => {
347
+ const { $wire } = livewireStub.$internal.appendComponentToDOM({
348
+ name: 'ckeditor5-editable',
349
+ el: createEditableHtmlElement(),
350
+ canonical: {
351
+ ...createEditableSnapshot('foo', '<p>Initial foo component</p>'),
352
+ saveDebounceMs: 500,
353
+ },
354
+ });
355
+
356
+ expect($wire.set).toHaveBeenCalledWith('content', '<p>Initial foo component</p>');
357
+
358
+ vi.mocked($wire.set).mockClear();
359
+
360
+ editor.ui.focusTracker.isFocused = false;
361
+
362
+ editor.setData({
363
+ foo: '<p>Modified foo content</p>',
364
+ });
365
+
366
+ expect($wire.set).toHaveBeenCalledWith('content', '<p>Modified foo content</p>');
367
+ });
265
368
  });
266
369
 
267
370
  describe('sync editable content after commit', () => {
@@ -1,9 +1,11 @@
1
1
  import type { MultiRootEditor } from 'ckeditor5';
2
2
 
3
+ import type { RootAttributesUpdater } from './utils';
4
+
3
5
  import { debounce } from '../shared';
4
6
  import { EditorsRegistry } from './editor/editors-registry';
5
- import { isWireModelConnected } from './editor/utils';
6
7
  import { ClassHook } from './hook';
8
+ import { createRootAttributesUpdater, isWireModelConnected } from './utils';
7
9
 
8
10
  /**
9
11
  * Editable hook for Livewire. It allows you to create editables for multi-root editors.
@@ -14,6 +16,11 @@ export class EditableComponentHook extends ClassHook<Snapshot> {
14
16
  */
15
17
  private editorPromise: Promise<MultiRootEditor | null> | null = null;
16
18
 
19
+ /**
20
+ * The root attributes updater for the editable's root.
21
+ */
22
+ private rootAttributesUpdater: RootAttributesUpdater | null = null;
23
+
17
24
  /**
18
25
  * Pending content to apply when the editor loses focus.
19
26
  */
@@ -65,19 +72,64 @@ export class EditableComponentHook extends ClassHook<Snapshot> {
65
72
  // Add livewire sync.
66
73
  this.syncTypingContentPush(editor);
67
74
  this.setupPendingReceivedContentHandlers(editor);
75
+ this.applyRootAttributes(editor);
68
76
 
69
77
  return editor;
70
78
  });
71
79
  }
72
80
 
81
+ /**
82
+ * Called when the component is updated by Livewire.
83
+ */
84
+ override async afterCommitSynced(): Promise<void> {
85
+ const editor = (await this.editorPromise)!;
86
+
87
+ this.applyCanonicalContentToEditor(editor);
88
+ this.applyRootAttributes(editor);
89
+ }
90
+
91
+ /**
92
+ * Destroys the editable component. Unmounts root from the editor.
93
+ */
94
+ override async destroyed() {
95
+ const { rootName } = this.canonical;
96
+
97
+ // Let's hide the element during destruction to prevent flickering.
98
+ this.element.style.display = 'none';
99
+
100
+ // Let's wait for the mounted promise to resolve before proceeding with destruction.
101
+ const editor = await this.editorPromise;
102
+ this.editorPromise = null;
103
+
104
+ // Remove root attributes we may have set on this root.
105
+ this.rootAttributesUpdater?.(null);
106
+
107
+ // Unmount root from the editor if editor is still registered.
108
+ if (editor && editor.state !== 'destroyed') {
109
+ const root = editor.model.document.getRoot(rootName);
110
+
111
+ /* v8 ignore next if -- @preserve */
112
+ if (root && 'detachEditable' in editor) {
113
+ editor.detachEditable(root);
114
+ editor.detachRoot(rootName, false);
115
+ }
116
+ }
117
+ }
118
+
73
119
  /**
74
120
  * Setups the content sync from the editor to Livewire on user input with debounce.
75
121
  */
76
122
  private syncTypingContentPush(editor: MultiRootEditor) {
77
123
  const { rootName, saveDebounceMs } = this.canonical;
124
+
78
125
  const input = this.element.querySelector<HTMLInputElement>('input');
126
+ let isDestroyed = false;
79
127
 
80
128
  const sync = () => {
129
+ if (isDestroyed) {
130
+ return;
131
+ }
132
+
81
133
  const html = editor.getData({ rootName });
82
134
 
83
135
  if (input) {
@@ -88,12 +140,21 @@ export class EditableComponentHook extends ClassHook<Snapshot> {
88
140
  };
89
141
 
90
142
  const debouncedSync = debounce(saveDebounceMs, sync);
143
+ const onChangeData = () => {
144
+ if (editor.ui.focusTracker.isFocused) {
145
+ debouncedSync();
146
+ }
147
+ else {
148
+ sync();
149
+ }
150
+ };
91
151
 
92
- editor.model.document.on('change:data', debouncedSync);
152
+ editor.model.document.on('change:data', onChangeData);
93
153
  sync();
94
154
 
95
155
  this.onBeforeDestroy(() => {
96
- editor.model.document.off('change:data', debouncedSync);
156
+ isDestroyed = true;
157
+ editor.model.document.off('change:data', onChangeData);
97
158
  });
98
159
  }
99
160
 
@@ -155,37 +216,13 @@ export class EditableComponentHook extends ClassHook<Snapshot> {
155
216
  }
156
217
 
157
218
  /**
158
- * Called when the component is updated by Livewire.
219
+ * Applies root attributes from the Livewire snapshot to the editor root.
159
220
  */
160
- override async afterCommitSynced(): Promise<void> {
161
- const editor = (await this.editorPromise)!;
221
+ private applyRootAttributes(editor: MultiRootEditor): void {
222
+ const { rootName, rootAttributes } = this.canonical;
162
223
 
163
- this.applyCanonicalContentToEditor(editor);
164
- }
165
-
166
- /**
167
- * Destroys the editable component. Unmounts root from the editor.
168
- */
169
- override async destroyed() {
170
- const { rootName } = this.canonical;
171
-
172
- // Let's hide the element during destruction to prevent flickering.
173
- this.element.style.display = 'none';
174
-
175
- // Let's wait for the mounted promise to resolve before proceeding with destruction.
176
- const editor = await this.editorPromise;
177
- this.editorPromise = null;
178
-
179
- // Unmount root from the editor if editor is still registered.
180
- if (editor && editor.state !== 'destroyed') {
181
- const root = editor.model.document.getRoot(rootName);
182
-
183
- /* v8 ignore next if -- @preserve */
184
- if (root && 'detachEditable' in editor) {
185
- editor.detachEditable(root);
186
- editor.detachRoot(rootName, false);
187
- }
188
- }
224
+ this.rootAttributesUpdater ??= createRootAttributesUpdater(editor, rootName);
225
+ this.rootAttributesUpdater(rootAttributes);
189
226
  }
190
227
  }
191
228
 
@@ -212,4 +249,9 @@ export type Snapshot = {
212
249
  * The debounce time in milliseconds for saving changes.
213
250
  */
214
251
  saveDebounceMs: number;
252
+
253
+ /**
254
+ * Root attributes to apply to the editable root.
255
+ */
256
+ rootAttributes?: Record<string, unknown>;
215
257
  };
@@ -375,6 +375,53 @@ describe('editor component', () => {
375
375
  }).not.toThrow();
376
376
  });
377
377
  });
378
+
379
+ describe('root attributes', () => {
380
+ it('should apply root attributes from snapshot', async () => {
381
+ const { id } = livewireStub.$internal.appendComponentToDOM<EditorSnapshot>({
382
+ name: 'ckeditor5',
383
+ el: createEditorHtmlElement(),
384
+ canonical: createEditorSnapshot({
385
+ rootAttributes: {
386
+ 'data-test': 'initial',
387
+ 'foo': 'bar',
388
+ },
389
+ }),
390
+ });
391
+
392
+ const editor = await waitForTestEditor();
393
+ const root = editor.model.document.getRoot('main')!;
394
+
395
+ expect(root.getAttribute('data-test')).toBe('initial');
396
+ expect(root.getAttribute('foo')).toBe('bar');
397
+
398
+ // Ensure attributes managed by other consumers are not removed.
399
+ editor.model.change((writer) => {
400
+ writer.setAttribute('external', 'value', root);
401
+ });
402
+
403
+ await livewireStub.$internal.dispatchComponentCommit<EditorSnapshot>(id, {
404
+ rootAttributes: {
405
+ 'data-test': 'updated',
406
+ },
407
+ });
408
+
409
+ await vi.waitFor(() => {
410
+ expect(root.getAttribute('data-test')).toBe('updated');
411
+ expect(root.getAttribute('foo')).toBeUndefined();
412
+ expect(root.getAttribute('external')).toBe('value');
413
+ });
414
+
415
+ await livewireStub.$internal.dispatchComponentCommit<EditorSnapshot>(id, {
416
+ rootAttributes: null as any,
417
+ });
418
+
419
+ await vi.waitFor(() => {
420
+ expect(root.getAttribute('data-test')).toBeUndefined();
421
+ expect(root.getAttribute('external')).toBe('value');
422
+ });
423
+ });
424
+ });
378
425
  });
379
426
 
380
427
  describe('`editableHeight` snapshot parameter`', () => {
@@ -432,6 +479,9 @@ describe('editor component', () => {
432
479
 
433
480
  const editor = await waitForTestEditor();
434
481
 
482
+ // Debounce should only be applied while the editor is focused.
483
+ editor.ui.focusTracker.isFocused = true;
484
+
435
485
  vi.mocked($wire.set).mockClear();
436
486
  editor.setData('<p>Debounce test</p>');
437
487
 
@@ -442,6 +492,24 @@ describe('editor component', () => {
442
492
  expect($wire.set).toHaveBeenCalledExactlyOnceWith('content', { main: '<p>Debounce test</p>' });
443
493
  });
444
494
 
495
+ it('should immediately send `$wire.set` when editor is not focused', async () => {
496
+ const { $wire } = livewireStub.$internal.appendComponentToDOM<EditorSnapshot>({
497
+ name: 'ckeditor5',
498
+ el: createEditorHtmlElement(),
499
+ canonical: {
500
+ ...createEditorSnapshot(),
501
+ saveDebounceMs: 400,
502
+ },
503
+ });
504
+
505
+ const editor = await waitForTestEditor();
506
+
507
+ vi.mocked($wire.set).mockClear();
508
+ editor.setData('<p>Debounce test</p>');
509
+
510
+ expect($wire.set).toHaveBeenCalledExactlyOnceWith('content', { main: '<p>Debounce test</p>' });
511
+ });
512
+
445
513
  it('should use parameter to debounce input sync', async () => {
446
514
  livewireStub.$internal.appendComponentToDOM<EditorSnapshot>({
447
515
  name: 'ckeditor5',
@@ -1,11 +1,13 @@
1
1
  import type { Editor } from 'ckeditor5';
2
2
 
3
+ import type { RootAttributesUpdater } from '../utils';
3
4
  import type { EditorId, EditorLanguage, EditorPreset } from './typings';
4
5
  import type { EditorCreator } from './utils';
5
6
 
6
7
  import { ContextsRegistry } from '../../hooks/context';
7
8
  import { isEmptyObject, waitFor } from '../../shared';
8
9
  import { ClassHook } from '../hook';
10
+ import { createRootAttributesUpdater } from '../utils';
9
11
  import { EditorsRegistry } from './editors-registry';
10
12
  import {
11
13
  createLivewireSyncPlugin,
@@ -37,6 +39,11 @@ export class EditorComponentHook extends ClassHook<Snapshot> {
37
39
  */
38
40
  private editorPromise: Promise<Editor> | null = null;
39
41
 
42
+ /**
43
+ * Root attributes updater for the main editor root.
44
+ */
45
+ private rootAttributesUpdater: RootAttributesUpdater | null = null;
46
+
40
47
  /**
41
48
  * @inheritdoc
42
49
  */
@@ -115,7 +122,23 @@ export class EditorComponentHook extends ClassHook<Snapshot> {
115
122
  override async afterCommitSynced(): Promise<void> {
116
123
  const editor = await this.editorPromise;
117
124
 
118
- editor?.fire('afterCommitSynced');
125
+ /* v8 ignore if -- @preserve */
126
+ if (editor) {
127
+ editor.fire('afterCommitSynced');
128
+ this.applyRootAttributes(editor);
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Applies root attributes from the Livewire snapshot to the editor.
134
+ *
135
+ * Note: we only apply attributes to the `main` root in the editor.
136
+ */
137
+ private applyRootAttributes(editor: Editor): void {
138
+ const { rootAttributes } = this.canonical;
139
+
140
+ this.rootAttributesUpdater ??= createRootAttributesUpdater(editor, 'main');
141
+ this.rootAttributesUpdater(rootAttributes);
119
142
  }
120
143
 
121
144
  /**
@@ -261,6 +284,8 @@ export class EditorComponentHook extends ClassHook<Snapshot> {
261
284
  setEditorEditableHeight(editor, editableHeight);
262
285
  }
263
286
 
287
+ this.applyRootAttributes(editor);
288
+
264
289
  return editor;
265
290
  };
266
291
  }
@@ -350,4 +375,9 @@ export type Snapshot = {
350
375
  * The language of the editor UI and content.
351
376
  */
352
377
  language: EditorLanguage;
378
+
379
+ /**
380
+ * Root attributes to apply to the main editor root.
381
+ */
382
+ rootAttributes?: Record<string, unknown>;
353
383
  };
@@ -3,7 +3,8 @@ import type { PluginConstructor } from 'ckeditor5';
3
3
  import type { EditorComponentHook } from '../editor';
4
4
 
5
5
  import { debounce, shallowEqual } from '../../../shared';
6
- import { getEditorRootsValues, isWireModelConnected } from '../utils';
6
+ import { isWireModelConnected } from '../../utils';
7
+ import { getEditorRootsValues } from '../utils';
7
8
 
8
9
  /**
9
10
  * Creates a LivewireSync plugin class.
@@ -124,10 +125,18 @@ export async function createLivewireSyncPlugin(
124
125
  * Setups the content push event for the editor.
125
126
  */
126
127
  private setupTypingContentPush() {
127
- const { model } = this.editor;
128
+ const { editor } = this;
129
+ const { model, ui } = editor;
128
130
  const { $wire } = component;
129
131
 
132
+ let isDestroyed = false;
133
+
130
134
  const syncContentChange = () => {
135
+ /* v8 ignore next if -- @preserve */
136
+ if (isDestroyed) {
137
+ return;
138
+ }
139
+
131
140
  const values = this.getEditorRootsValues();
132
141
 
133
142
  // Prevent looping when editor changed content from Livewire.
@@ -140,8 +149,23 @@ export async function createLivewireSyncPlugin(
140
149
  }
141
150
  };
142
151
 
143
- model.document.on('change:data', debounce(saveDebounceMs, syncContentChange));
144
- this.editor.once('ready', syncContentChange);
152
+ const debouncedSync = debounce(saveDebounceMs, syncContentChange);
153
+ const onChangeData = () => {
154
+ if (ui.focusTracker.isFocused) {
155
+ debouncedSync();
156
+ }
157
+ else {
158
+ syncContentChange();
159
+ }
160
+ };
161
+
162
+ model.document.on('change:data', onChangeData);
163
+
164
+ editor.once('ready', syncContentChange);
165
+ editor.once('destroy', () => {
166
+ isDestroyed = true;
167
+ model.document.off('change:data', onChangeData);
168
+ });
145
169
  }
146
170
 
147
171
  /**
@@ -1,7 +1,6 @@
1
1
  export * from './create-editor-in-context';
2
2
  export * from './get-editor-roots-values';
3
3
  export * from './is-single-root-editor';
4
- export * from './is-wire-model-connected';
5
4
  export * from './load-editor-constructor';
6
5
  export * from './load-editor-plugins';
7
6
  export * from './load-editor-translations';
@@ -0,0 +1,2 @@
1
+ export * from './is-wire-model-connected';
2
+ export * from './root-attributes-updater';
@@ -1,6 +1,7 @@
1
1
  import { describe, expect, it } from 'vitest';
2
2
 
3
- import { html } from '../../../../test-utils/html';
3
+ import { html } from '~/test-utils/html';
4
+
4
5
  import { isWireModelConnected } from './is-wire-model-connected';
5
6
 
6
7
  describe('isWireModelConnected', () => {
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Checks if the given element is connected to a wire:model directive in its ancestry.
3
+ *
4
+ * @param element - The HTML element to check for wire:model connection.
5
+ * @returns True if the element is connected to a wire:model directive, false otherwise.
6
+ */
1
7
  export function isWireModelConnected(element: HTMLElement): boolean {
2
8
  let parent: HTMLElement | null = element;
3
9
 
@@ -0,0 +1,46 @@
1
+ import type { Editor } from 'ckeditor5';
2
+
3
+ /**
4
+ * Creates a function that synchronizes root attributes on the given editor root.
5
+ *
6
+ * The returned function tracks which attributes were set by itself and will only
7
+ * remove attributes it previously managed. This avoids interfering with other
8
+ * consumers that may also change attributes on the same root.
9
+ *
10
+ * @param editor The editor instance containing the root to manage.
11
+ * @param rootName The name of the root to manage attributes on.
12
+ * @returns A function that can be called with the desired set of attributes to apply them to the root.
13
+ * Calling the function with `null` or an empty object will clear all attributes previously set by it.
14
+ */
15
+ export function createRootAttributesUpdater(editor: Editor, rootName: string): RootAttributesUpdater {
16
+ const managedAttrs = new Set<string>();
17
+
18
+ return (rootAttributes?: Record<string, unknown> | null) => {
19
+ editor.model.enqueueChange({ isUndoable: false }, (writer) => {
20
+ const root = editor.model.document.getRoot(rootName);
21
+
22
+ /* v8 ignore next if -- @preserve */
23
+ if (!root) {
24
+ return;
25
+ }
26
+
27
+ // Remove previously managed attributes that are no longer requested.
28
+ for (const key of managedAttrs) {
29
+ if (rootAttributes && key in rootAttributes) {
30
+ continue;
31
+ }
32
+
33
+ writer.removeAttribute(key, root);
34
+ managedAttrs.delete(key);
35
+ }
36
+
37
+ // Apply or overwrite requested attributes.
38
+ for (const [key, value] of Object.entries(rootAttributes ?? {})) {
39
+ writer.setAttribute(key, value, root);
40
+ managedAttrs.add(key);
41
+ }
42
+ });
43
+ };
44
+ }
45
+
46
+ export type RootAttributesUpdater = (rootAttributes?: Record<string, unknown> | null) => void;
@@ -1,2 +0,0 @@
1
- export declare function isWireModelConnected(element: HTMLElement): boolean;
2
- //# sourceMappingURL=is-wire-model-connected.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"is-wire-model-connected.d.ts","sourceRoot":"","sources":["../../../../../src/hooks/editor/utils/is-wire-model-connected.ts"],"names":[],"mappings":"AAAA,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAalE"}