@licium/editor-plugin-details 3.2.13 → 3.2.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@licium/editor-plugin-details",
3
- "version": "3.2.13",
3
+ "version": "3.2.14",
4
4
  "description": "Details/Summary plugin for Toast UI Editor",
5
5
  "keywords": [
6
6
  "nhn",
@@ -48,5 +48,5 @@
48
48
  "publishConfig": {
49
49
  "access": "public"
50
50
  },
51
- "gitHead": "019ce2e0c8210746f0072903ebec7efe79a8374a"
51
+ "gitHead": "474aa76d6fcc3523669c320a45286ac0cfe51a91"
52
52
  }
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  /* eslint-disable */
2
+ import { Plugin } from 'prosemirror-state';
2
3
  import type { PluginContext, PluginInfo, I18n, MdNode } from '@licium/editor';
3
4
  import { PluginOptions } from '@t/index';
4
5
  import { addLangs } from './i18n/langs';
@@ -6,6 +7,63 @@ import './css/plugin.css';
6
7
 
7
8
  const PREFIX = 'toastui-editor-';
8
9
 
10
+ // Factory function for the ProseMirror plugin (TUI Editor expects functions, not instances)
11
+ function createDetailsClickPlugin() {
12
+ return new Plugin({
13
+ props: {
14
+ handleClick(view, pos, event) {
15
+ const target = event.target as HTMLElement;
16
+ const summary = target.closest('summary');
17
+
18
+ if (summary) {
19
+ event.preventDefault();
20
+
21
+ const $pos = view.state.doc.resolve(pos);
22
+ let detailsNode = null;
23
+ let detailsPos = -1;
24
+
25
+ // Walk up depth to find the parent Details node
26
+ for (let d = $pos.depth; d >= 0; d -= 1) {
27
+ if ($pos.node(d).type.name === 'details') {
28
+ detailsNode = $pos.node(d);
29
+ detailsPos = $pos.before(d);
30
+ break;
31
+ }
32
+ }
33
+
34
+ if (detailsNode && detailsPos !== -1) {
35
+ const node = detailsNode;
36
+ const htmlAttrs = (node.attrs && node.attrs.htmlAttrs) || {};
37
+ const isOpenAttr = node.attrs.open;
38
+
39
+ const isOpen = isOpenAttr === true || (htmlAttrs && htmlAttrs.open !== null && typeof htmlAttrs.open !== 'undefined');
40
+
41
+ console.log('[Details Plugin] Click intercepted. Toggling from:', isOpen);
42
+
43
+ const newHtmlAttrs = { ...htmlAttrs };
44
+
45
+ if (isOpen) {
46
+ delete newHtmlAttrs.open;
47
+ } else {
48
+ newHtmlAttrs.open = '';
49
+ }
50
+
51
+ const newAttrs = {
52
+ ...node.attrs,
53
+ open: !isOpen,
54
+ htmlAttrs: newHtmlAttrs,
55
+ };
56
+
57
+ view.dispatch(view.state.tr.setNodeMarkup(detailsPos, null, newAttrs));
58
+ return true; // Stop propagation, we handled it
59
+ }
60
+ }
61
+ return false;
62
+ }
63
+ }
64
+ });
65
+ }
66
+
9
67
  function createToolbarItemOption(i18n: I18n) {
10
68
  return {
11
69
  name: 'details',
@@ -170,6 +228,7 @@ export default function detailsPlugin(
170
228
  handleDetailsExit(context, event);
171
229
  });
172
230
 
231
+
173
232
  return {
174
233
  toHTMLRenderers: {
175
234
  htmlBlock: {
@@ -202,12 +261,74 @@ export default function detailsPlugin(
202
261
  },
203
262
  },
204
263
 
264
+ // Inject the ProseMirror plugin
265
+ wysiwygPlugins: [(() => {
266
+ console.log('[Details Plugin] Initializing ProseMirror plugin');
267
+ // @ts-ignore
268
+ if (typeof Plugin === 'undefined') {
269
+ console.error('[Details Plugin] CRITICAL: ProseMirror Plugin class is undefined');
270
+ return {};
271
+ }
272
+ return new Plugin({
273
+ props: {
274
+ handleClick(view, pos, event) {
275
+ const target = event.target as HTMLElement;
276
+ const summary = target.closest('summary');
277
+
278
+ if (summary) {
279
+ event.preventDefault();
280
+
281
+ const $pos = view.state.doc.resolve(pos);
282
+ let detailsNode = null;
283
+ let detailsPos = -1;
284
+
285
+ // Walk up depth to find the parent Details node
286
+ for (let d = $pos.depth; d >= 0; d -= 1) {
287
+ if ($pos.node(d).type.name === 'details') {
288
+ detailsNode = $pos.node(d);
289
+ detailsPos = $pos.before(d);
290
+ break;
291
+ }
292
+ }
293
+
294
+ if (detailsNode && detailsPos !== -1) {
295
+ const node = detailsNode;
296
+ const htmlAttrs = (node.attrs && node.attrs.htmlAttrs) || {};
297
+ const isOpenAttr = node.attrs.open;
298
+
299
+ const isOpen = isOpenAttr === true || (htmlAttrs && htmlAttrs.open !== null && typeof htmlAttrs.open !== 'undefined');
300
+
301
+ console.log('[Details Plugin] Click intercepted. Toggling from:', isOpen);
302
+
303
+ const newHtmlAttrs = { ...htmlAttrs };
304
+
305
+ if (isOpen) {
306
+ delete newHtmlAttrs.open;
307
+ } else {
308
+ newHtmlAttrs.open = '';
309
+ }
310
+
311
+ const newAttrs = {
312
+ ...node.attrs,
313
+ open: !isOpen,
314
+ htmlAttrs: newHtmlAttrs,
315
+ };
316
+
317
+ view.dispatch(view.state.tr.setNodeMarkup(detailsPos, null, newAttrs));
318
+ return true; // Stop propagation
319
+ }
320
+ }
321
+ return false;
322
+ }
323
+ }
324
+ });
325
+ }) as any],
205
326
 
206
327
  wysiwygNodeViews: {
207
328
  details: (node, view, getPos) => {
208
329
  const dom = document.createElement('details');
209
330
  const htmlAttrs = (node.attrs && node.attrs.htmlAttrs) || {};
210
- const isOpenAttr = node.attrs.open; // Core definition uses direct attribute
331
+ const isOpenAttr = node.attrs.open;
211
332
 
212
333
  // Check both direct attribute (priority) and htmlAttrs (legacy/plugin)
213
334
  const isOpen = isOpenAttr === true || (htmlAttrs && htmlAttrs.open !== null && typeof htmlAttrs.open !== 'undefined');
@@ -216,34 +337,7 @@ export default function detailsPlugin(
216
337
  dom.open = true;
217
338
  }
218
339
 
219
- dom.addEventListener('click', (e) => {
220
- const target = e.target as HTMLElement;
221
-
222
- if (target.tagName === 'SUMMARY' || target.closest('summary')) {
223
- e.preventDefault();
224
-
225
- const pos = getPos();
226
-
227
- if (typeof pos === 'number') {
228
- const isOpen = htmlAttrs.open !== null && typeof htmlAttrs.open !== 'undefined';
229
- const newHtmlAttrs = { ...htmlAttrs };
230
-
231
- if (isOpen) {
232
- delete newHtmlAttrs.open;
233
- } else {
234
- newHtmlAttrs.open = '';
235
- }
236
-
237
- const newAttrs = {
238
- ...node.attrs,
239
- htmlAttrs: newHtmlAttrs,
240
- };
241
-
242
- view.dispatch(view.state.tr.setNodeMarkup(pos, null, newAttrs));
243
- }
244
- }
245
- });
246
-
340
+ // Clean NodeView, no event listeners here
247
341
  return { dom, contentDOM: dom };
248
342
  },
249
343
  },