@kedataindo/docflow-plugins 0.0.78 → 0.0.80

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/dist/index.cjs CHANGED
@@ -2074,8 +2074,8 @@ var BibliographyNode = import_core6.Node.create({
2074
2074
  dom.setAttribute("data-node-type", "bibliography");
2075
2075
  let attrs = props.node?.attrs ?? {};
2076
2076
  const render = () => {
2077
- const engine2 = getEngine(editor);
2078
- const items = engine2?.getBibliography() ?? [];
2077
+ const engine = getEngine(editor);
2078
+ const items = engine?.getBibliography() ?? [];
2079
2079
  const showHeading = !isHeadingHidden(attrs.showHeading);
2080
2080
  const headingText = headingLabel(attrs.headingText);
2081
2081
  dom.innerHTML = "";
@@ -2104,8 +2104,19 @@ var BibliographyNode = import_core6.Node.create({
2104
2104
  dom.appendChild(list);
2105
2105
  };
2106
2106
  render();
2107
- const engine = getEngine(editor);
2108
- const unsubscribe = engine?.onChange(render);
2107
+ let unsubscribe = null;
2108
+ let bound = null;
2109
+ const syncEngine = () => {
2110
+ const engine = getEngine(editor);
2111
+ if (engine === bound) return;
2112
+ unsubscribe?.();
2113
+ bound = engine;
2114
+ unsubscribe = engine ? engine.onChange(render) : null;
2115
+ render();
2116
+ };
2117
+ syncEngine();
2118
+ editor.on("create", syncEngine);
2119
+ editor.on("citationEngineReady", syncEngine);
2109
2120
  return {
2110
2121
  dom,
2111
2122
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -2118,6 +2129,8 @@ var BibliographyNode = import_core6.Node.create({
2118
2129
  return true;
2119
2130
  },
2120
2131
  destroy() {
2132
+ editor.off("create", syncEngine);
2133
+ editor.off("citationEngineReady", syncEngine);
2121
2134
  unsubscribe?.();
2122
2135
  }
2123
2136
  };
@@ -2158,83 +2171,91 @@ var CitationEngineExtension = import_core7.Extension.create({
2158
2171
  * recomputes only when the ordered signature changed, so plain typing
2159
2172
  * costs one cheap walk and no citeproc work.
2160
2173
  */
2174
+ /**
2175
+ * Keep the engine's cluster registry in sync with the document — see
2176
+ * `syncCitationClusters`. The engine recomputes only when the ordered
2177
+ * signature changed, so plain typing costs one cheap walk and no citeproc
2178
+ * work.
2179
+ */
2161
2180
  onUpdate() {
2162
- const editor = this.editor;
2163
- const engine = getCitationEngine(editor);
2164
- if (!engine) return;
2165
- {
2166
- const seen = /* @__PURE__ */ new Set();
2167
- const repairs = [];
2168
- editor.state.doc.descendants((node, pos) => {
2169
- if (node.type.name === "citation" || node.type.name === "footnote" && node.attrs.sourceId) {
2170
- const id = node.attrs.citationId;
2171
- if (id) {
2172
- if (seen.has(id)) {
2173
- repairs.push({ pos, attrs: { ...node.attrs } });
2174
- } else {
2175
- seen.add(id);
2176
- }
2177
- }
2178
- }
2179
- return true;
2180
- });
2181
- if (repairs.length > 0) {
2182
- const tr = editor.state.tr;
2183
- for (const { pos, attrs } of repairs) {
2184
- tr.setNodeMarkup(pos, void 0, { ...attrs, citationId: nextCitationId() });
2185
- }
2186
- editor.view.dispatch(tr);
2187
- return;
2188
- }
2189
- }
2190
- const ordered = [];
2181
+ syncCitationClusters(this.editor);
2182
+ }
2183
+ });
2184
+ function syncCitationClusters(editor) {
2185
+ const engine = getCitationEngine(editor);
2186
+ if (!engine) return;
2187
+ {
2188
+ const seen = /* @__PURE__ */ new Set();
2189
+ const repairs = [];
2191
2190
  editor.state.doc.descendants((node, pos) => {
2192
2191
  if (node.type.name === "citation" || node.type.name === "footnote" && node.attrs.sourceId) {
2193
- ordered.push({
2194
- citationId: node.attrs.citationId ?? `anon-${pos}`,
2195
- attrs: {
2196
- sourceId: node.attrs.sourceId ?? null,
2197
- locator: node.attrs.locator || "",
2198
- label: node.attrs.label || "page",
2199
- mode: node.attrs.mode || "normal",
2200
- prefix: node.attrs.prefix || "",
2201
- suffix: node.attrs.suffix || ""
2192
+ const id = node.attrs.citationId;
2193
+ if (id) {
2194
+ if (seen.has(id)) {
2195
+ repairs.push({ pos, attrs: { ...node.attrs } });
2196
+ } else {
2197
+ seen.add(id);
2202
2198
  }
2203
- });
2199
+ }
2204
2200
  }
2205
2201
  return true;
2206
2202
  });
2207
- const changed = engine.syncCitations(ordered);
2208
- if (changed) {
2209
- const port = editor.storage.editorContext;
2210
- port?.citation?.onSourcesChange?.(engine.getCitedSourceIds());
2203
+ if (repairs.length > 0) {
2204
+ const tr = editor.state.tr;
2205
+ for (const { pos, attrs } of repairs) {
2206
+ tr.setNodeMarkup(pos, void 0, { ...attrs, citationId: nextCitationId() });
2207
+ }
2208
+ editor.view.dispatch(tr);
2209
+ return;
2211
2210
  }
2212
- {
2213
- const updates = [];
2214
- editor.state.doc.descendants((node, pos) => {
2215
- if (node.type.name === "footnote" && node.attrs.sourceId) {
2216
- const id = node.attrs.citationId;
2217
- if (!id) return true;
2218
- const text = engine.renderCluster(id);
2219
- if (text && text !== node.attrs.content) {
2220
- updates.push({ pos, content: text });
2221
- }
2211
+ }
2212
+ const ordered = [];
2213
+ editor.state.doc.descendants((node, pos) => {
2214
+ if (node.type.name === "citation" || node.type.name === "footnote" && node.attrs.sourceId) {
2215
+ ordered.push({
2216
+ citationId: node.attrs.citationId ?? `anon-${pos}`,
2217
+ attrs: {
2218
+ sourceId: node.attrs.sourceId ?? null,
2219
+ locator: node.attrs.locator || "",
2220
+ label: node.attrs.label || "page",
2221
+ mode: node.attrs.mode || "normal",
2222
+ prefix: node.attrs.prefix || "",
2223
+ suffix: node.attrs.suffix || ""
2222
2224
  }
2223
- return true;
2224
2225
  });
2225
- if (updates.length > 0) {
2226
- const tr = editor.state.tr;
2227
- for (const { pos, content } of updates) {
2228
- const node = editor.state.doc.nodeAt(pos);
2229
- if (node) {
2230
- tr.setNodeMarkup(pos, void 0, { ...node.attrs, content });
2231
- }
2226
+ }
2227
+ return true;
2228
+ });
2229
+ const changed = engine.syncCitations(ordered);
2230
+ if (changed) {
2231
+ const port = editor.storage.editorContext;
2232
+ port?.citation?.onSourcesChange?.(engine.getCitedSourceIds());
2233
+ }
2234
+ {
2235
+ const updates = [];
2236
+ editor.state.doc.descendants((node, pos) => {
2237
+ if (node.type.name === "footnote" && node.attrs.sourceId) {
2238
+ const id = node.attrs.citationId;
2239
+ if (!id) return true;
2240
+ const text = engine.renderCluster(id);
2241
+ if (text && text !== node.attrs.content) {
2242
+ updates.push({ pos, content: text });
2243
+ }
2244
+ }
2245
+ return true;
2246
+ });
2247
+ if (updates.length > 0) {
2248
+ const tr = editor.state.tr;
2249
+ for (const { pos, content } of updates) {
2250
+ const node = editor.state.doc.nodeAt(pos);
2251
+ if (node) {
2252
+ tr.setNodeMarkup(pos, void 0, { ...node.attrs, content });
2232
2253
  }
2233
- editor.view.dispatch(tr);
2234
2254
  }
2255
+ editor.view.dispatch(tr);
2235
2256
  }
2236
2257
  }
2237
- });
2258
+ }
2238
2259
  var CitationNode = import_core7.Node.create({
2239
2260
  name: "citation",
2240
2261
  group: "inline",
@@ -2297,9 +2318,9 @@ var CitationNode = import_core7.Node.create({
2297
2318
  dom.className = "docs-citation";
2298
2319
  dom.setAttribute("data-node-type", "citation");
2299
2320
  const render = () => {
2300
- const engine2 = getCitationEngine(editor);
2321
+ const engine = getCitationEngine(editor);
2301
2322
  const citationId = node.attrs.citationId;
2302
- const text = engine2 && citationId ? engine2.renderCluster(citationId) : "";
2323
+ const text = engine && citationId ? engine.renderCluster(citationId) : "";
2303
2324
  if (text) {
2304
2325
  dom.innerHTML = text;
2305
2326
  dom.classList.remove("docs-citation--missing");
@@ -2311,8 +2332,19 @@ var CitationNode = import_core7.Node.create({
2311
2332
  dom.setAttribute("data-citation-source-id", String(node.attrs.sourceId ?? ""));
2312
2333
  };
2313
2334
  render();
2314
- const engine = getCitationEngine(editor);
2315
- const unsubscribe = engine?.onChange(render);
2335
+ let unsubscribe = null;
2336
+ let bound = null;
2337
+ const syncEngine = () => {
2338
+ const engine = getCitationEngine(editor);
2339
+ if (engine === bound) return;
2340
+ unsubscribe?.();
2341
+ bound = engine;
2342
+ unsubscribe = engine ? engine.onChange(render) : null;
2343
+ render();
2344
+ };
2345
+ syncEngine();
2346
+ editor.on("create", syncEngine);
2347
+ editor.on("citationEngineReady", syncEngine);
2316
2348
  return {
2317
2349
  dom,
2318
2350
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -2326,6 +2358,8 @@ var CitationNode = import_core7.Node.create({
2326
2358
  return true;
2327
2359
  },
2328
2360
  destroy() {
2361
+ editor.off("create", syncEngine);
2362
+ editor.off("citationEngineReady", syncEngine);
2329
2363
  unsubscribe?.();
2330
2364
  }
2331
2365
  };
@@ -2397,6 +2431,8 @@ var citationPlugin = (0, import_docflow_core17.definePlugin)({
2397
2431
  const sources = typeof citation.sources === "function" ? citation.sources() : citation.sources;
2398
2432
  const engine = new CiteEngine({ sources, style: citation.style });
2399
2433
  editor.storage.citationEngine.engine = engine;
2434
+ editor.emit("citationEngineReady", { editor });
2435
+ syncCitationClusters(editor);
2400
2436
  },
2401
2437
  onDestroy(editor) {
2402
2438
  ;
package/dist/index.d.cts CHANGED
@@ -100,6 +100,19 @@ declare const textColorPlugin: _kedata_indonesia_docflow_core.DocsEditorPlugin;
100
100
 
101
101
  declare const highlightPlugin: _kedata_indonesia_docflow_core.DocsEditorPlugin;
102
102
 
103
+ declare module '@tiptap/core' {
104
+ interface EditorEvents {
105
+ /**
106
+ * Emitted once the document-scoped CiteEngine exists. It is created by
107
+ * `citationPlugin.hooks.onInit`, i.e. AFTER the editor view (and therefore
108
+ * after the node views for the already-loaded document), so node views
109
+ * cannot rely on the engine being there when they are constructed.
110
+ */
111
+ citationEngineReady: {
112
+ editor: Editor;
113
+ };
114
+ }
115
+ }
103
116
  declare function getCitationEngine(editor: Editor): CiteEngine | null;
104
117
  /**
105
118
  * Carries the document-scoped CiteEngine in editor storage. The engine is
package/dist/index.d.ts CHANGED
@@ -100,6 +100,19 @@ declare const textColorPlugin: _kedata_indonesia_docflow_core.DocsEditorPlugin;
100
100
 
101
101
  declare const highlightPlugin: _kedata_indonesia_docflow_core.DocsEditorPlugin;
102
102
 
103
+ declare module '@tiptap/core' {
104
+ interface EditorEvents {
105
+ /**
106
+ * Emitted once the document-scoped CiteEngine exists. It is created by
107
+ * `citationPlugin.hooks.onInit`, i.e. AFTER the editor view (and therefore
108
+ * after the node views for the already-loaded document), so node views
109
+ * cannot rely on the engine being there when they are constructed.
110
+ */
111
+ citationEngineReady: {
112
+ editor: Editor;
113
+ };
114
+ }
115
+ }
103
116
  declare function getCitationEngine(editor: Editor): CiteEngine | null;
104
117
  /**
105
118
  * Carries the document-scoped CiteEngine in editor storage. The engine is
package/dist/index.js CHANGED
@@ -1981,8 +1981,8 @@ var BibliographyNode = Node5.create({
1981
1981
  dom.setAttribute("data-node-type", "bibliography");
1982
1982
  let attrs = props.node?.attrs ?? {};
1983
1983
  const render = () => {
1984
- const engine2 = getEngine(editor);
1985
- const items = engine2?.getBibliography() ?? [];
1984
+ const engine = getEngine(editor);
1985
+ const items = engine?.getBibliography() ?? [];
1986
1986
  const showHeading = !isHeadingHidden(attrs.showHeading);
1987
1987
  const headingText = headingLabel(attrs.headingText);
1988
1988
  dom.innerHTML = "";
@@ -2011,8 +2011,19 @@ var BibliographyNode = Node5.create({
2011
2011
  dom.appendChild(list);
2012
2012
  };
2013
2013
  render();
2014
- const engine = getEngine(editor);
2015
- const unsubscribe = engine?.onChange(render);
2014
+ let unsubscribe = null;
2015
+ let bound = null;
2016
+ const syncEngine = () => {
2017
+ const engine = getEngine(editor);
2018
+ if (engine === bound) return;
2019
+ unsubscribe?.();
2020
+ bound = engine;
2021
+ unsubscribe = engine ? engine.onChange(render) : null;
2022
+ render();
2023
+ };
2024
+ syncEngine();
2025
+ editor.on("create", syncEngine);
2026
+ editor.on("citationEngineReady", syncEngine);
2016
2027
  return {
2017
2028
  dom,
2018
2029
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -2025,6 +2036,8 @@ var BibliographyNode = Node5.create({
2025
2036
  return true;
2026
2037
  },
2027
2038
  destroy() {
2039
+ editor.off("create", syncEngine);
2040
+ editor.off("citationEngineReady", syncEngine);
2028
2041
  unsubscribe?.();
2029
2042
  }
2030
2043
  };
@@ -2065,83 +2078,91 @@ var CitationEngineExtension = Extension2.create({
2065
2078
  * recomputes only when the ordered signature changed, so plain typing
2066
2079
  * costs one cheap walk and no citeproc work.
2067
2080
  */
2081
+ /**
2082
+ * Keep the engine's cluster registry in sync with the document — see
2083
+ * `syncCitationClusters`. The engine recomputes only when the ordered
2084
+ * signature changed, so plain typing costs one cheap walk and no citeproc
2085
+ * work.
2086
+ */
2068
2087
  onUpdate() {
2069
- const editor = this.editor;
2070
- const engine = getCitationEngine(editor);
2071
- if (!engine) return;
2072
- {
2073
- const seen = /* @__PURE__ */ new Set();
2074
- const repairs = [];
2075
- editor.state.doc.descendants((node, pos) => {
2076
- if (node.type.name === "citation" || node.type.name === "footnote" && node.attrs.sourceId) {
2077
- const id = node.attrs.citationId;
2078
- if (id) {
2079
- if (seen.has(id)) {
2080
- repairs.push({ pos, attrs: { ...node.attrs } });
2081
- } else {
2082
- seen.add(id);
2083
- }
2084
- }
2085
- }
2086
- return true;
2087
- });
2088
- if (repairs.length > 0) {
2089
- const tr = editor.state.tr;
2090
- for (const { pos, attrs } of repairs) {
2091
- tr.setNodeMarkup(pos, void 0, { ...attrs, citationId: nextCitationId() });
2092
- }
2093
- editor.view.dispatch(tr);
2094
- return;
2095
- }
2096
- }
2097
- const ordered = [];
2088
+ syncCitationClusters(this.editor);
2089
+ }
2090
+ });
2091
+ function syncCitationClusters(editor) {
2092
+ const engine = getCitationEngine(editor);
2093
+ if (!engine) return;
2094
+ {
2095
+ const seen = /* @__PURE__ */ new Set();
2096
+ const repairs = [];
2098
2097
  editor.state.doc.descendants((node, pos) => {
2099
2098
  if (node.type.name === "citation" || node.type.name === "footnote" && node.attrs.sourceId) {
2100
- ordered.push({
2101
- citationId: node.attrs.citationId ?? `anon-${pos}`,
2102
- attrs: {
2103
- sourceId: node.attrs.sourceId ?? null,
2104
- locator: node.attrs.locator || "",
2105
- label: node.attrs.label || "page",
2106
- mode: node.attrs.mode || "normal",
2107
- prefix: node.attrs.prefix || "",
2108
- suffix: node.attrs.suffix || ""
2099
+ const id = node.attrs.citationId;
2100
+ if (id) {
2101
+ if (seen.has(id)) {
2102
+ repairs.push({ pos, attrs: { ...node.attrs } });
2103
+ } else {
2104
+ seen.add(id);
2109
2105
  }
2110
- });
2106
+ }
2111
2107
  }
2112
2108
  return true;
2113
2109
  });
2114
- const changed = engine.syncCitations(ordered);
2115
- if (changed) {
2116
- const port = editor.storage.editorContext;
2117
- port?.citation?.onSourcesChange?.(engine.getCitedSourceIds());
2110
+ if (repairs.length > 0) {
2111
+ const tr = editor.state.tr;
2112
+ for (const { pos, attrs } of repairs) {
2113
+ tr.setNodeMarkup(pos, void 0, { ...attrs, citationId: nextCitationId() });
2114
+ }
2115
+ editor.view.dispatch(tr);
2116
+ return;
2118
2117
  }
2119
- {
2120
- const updates = [];
2121
- editor.state.doc.descendants((node, pos) => {
2122
- if (node.type.name === "footnote" && node.attrs.sourceId) {
2123
- const id = node.attrs.citationId;
2124
- if (!id) return true;
2125
- const text = engine.renderCluster(id);
2126
- if (text && text !== node.attrs.content) {
2127
- updates.push({ pos, content: text });
2128
- }
2118
+ }
2119
+ const ordered = [];
2120
+ editor.state.doc.descendants((node, pos) => {
2121
+ if (node.type.name === "citation" || node.type.name === "footnote" && node.attrs.sourceId) {
2122
+ ordered.push({
2123
+ citationId: node.attrs.citationId ?? `anon-${pos}`,
2124
+ attrs: {
2125
+ sourceId: node.attrs.sourceId ?? null,
2126
+ locator: node.attrs.locator || "",
2127
+ label: node.attrs.label || "page",
2128
+ mode: node.attrs.mode || "normal",
2129
+ prefix: node.attrs.prefix || "",
2130
+ suffix: node.attrs.suffix || ""
2129
2131
  }
2130
- return true;
2131
2132
  });
2132
- if (updates.length > 0) {
2133
- const tr = editor.state.tr;
2134
- for (const { pos, content } of updates) {
2135
- const node = editor.state.doc.nodeAt(pos);
2136
- if (node) {
2137
- tr.setNodeMarkup(pos, void 0, { ...node.attrs, content });
2138
- }
2133
+ }
2134
+ return true;
2135
+ });
2136
+ const changed = engine.syncCitations(ordered);
2137
+ if (changed) {
2138
+ const port = editor.storage.editorContext;
2139
+ port?.citation?.onSourcesChange?.(engine.getCitedSourceIds());
2140
+ }
2141
+ {
2142
+ const updates = [];
2143
+ editor.state.doc.descendants((node, pos) => {
2144
+ if (node.type.name === "footnote" && node.attrs.sourceId) {
2145
+ const id = node.attrs.citationId;
2146
+ if (!id) return true;
2147
+ const text = engine.renderCluster(id);
2148
+ if (text && text !== node.attrs.content) {
2149
+ updates.push({ pos, content: text });
2150
+ }
2151
+ }
2152
+ return true;
2153
+ });
2154
+ if (updates.length > 0) {
2155
+ const tr = editor.state.tr;
2156
+ for (const { pos, content } of updates) {
2157
+ const node = editor.state.doc.nodeAt(pos);
2158
+ if (node) {
2159
+ tr.setNodeMarkup(pos, void 0, { ...node.attrs, content });
2139
2160
  }
2140
- editor.view.dispatch(tr);
2141
2161
  }
2162
+ editor.view.dispatch(tr);
2142
2163
  }
2143
2164
  }
2144
- });
2165
+ }
2145
2166
  var CitationNode = Node6.create({
2146
2167
  name: "citation",
2147
2168
  group: "inline",
@@ -2204,9 +2225,9 @@ var CitationNode = Node6.create({
2204
2225
  dom.className = "docs-citation";
2205
2226
  dom.setAttribute("data-node-type", "citation");
2206
2227
  const render = () => {
2207
- const engine2 = getCitationEngine(editor);
2228
+ const engine = getCitationEngine(editor);
2208
2229
  const citationId = node.attrs.citationId;
2209
- const text = engine2 && citationId ? engine2.renderCluster(citationId) : "";
2230
+ const text = engine && citationId ? engine.renderCluster(citationId) : "";
2210
2231
  if (text) {
2211
2232
  dom.innerHTML = text;
2212
2233
  dom.classList.remove("docs-citation--missing");
@@ -2218,8 +2239,19 @@ var CitationNode = Node6.create({
2218
2239
  dom.setAttribute("data-citation-source-id", String(node.attrs.sourceId ?? ""));
2219
2240
  };
2220
2241
  render();
2221
- const engine = getCitationEngine(editor);
2222
- const unsubscribe = engine?.onChange(render);
2242
+ let unsubscribe = null;
2243
+ let bound = null;
2244
+ const syncEngine = () => {
2245
+ const engine = getCitationEngine(editor);
2246
+ if (engine === bound) return;
2247
+ unsubscribe?.();
2248
+ bound = engine;
2249
+ unsubscribe = engine ? engine.onChange(render) : null;
2250
+ render();
2251
+ };
2252
+ syncEngine();
2253
+ editor.on("create", syncEngine);
2254
+ editor.on("citationEngineReady", syncEngine);
2223
2255
  return {
2224
2256
  dom,
2225
2257
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -2233,6 +2265,8 @@ var CitationNode = Node6.create({
2233
2265
  return true;
2234
2266
  },
2235
2267
  destroy() {
2268
+ editor.off("create", syncEngine);
2269
+ editor.off("citationEngineReady", syncEngine);
2236
2270
  unsubscribe?.();
2237
2271
  }
2238
2272
  };
@@ -2304,6 +2338,8 @@ var citationPlugin = definePlugin17({
2304
2338
  const sources = typeof citation.sources === "function" ? citation.sources() : citation.sources;
2305
2339
  const engine = new CiteEngine({ sources, style: citation.style });
2306
2340
  editor.storage.citationEngine.engine = engine;
2341
+ editor.emit("citationEngineReady", { editor });
2342
+ syncCitationClusters(editor);
2307
2343
  },
2308
2344
  onDestroy(editor) {
2309
2345
  ;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kedataindo/docflow-plugins",
3
3
  "license": "UNLICENSED",
4
- "version": "0.0.78",
4
+ "version": "0.0.80",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.js",
@@ -31,7 +31,7 @@
31
31
  "@tiptap/pm": "^2.11.0",
32
32
  "citeproc": "^2.4.63",
33
33
  "tiptap-markdown": "0.8.10",
34
- "@kedataindo/docflow-core": "0.0.76"
34
+ "@kedataindo/docflow-core": "0.0.78"
35
35
  },
36
36
  "peerDependencies": {
37
37
  "@tiptap/core": "^2.11.0",