@bpmnkit/plugins 0.0.8

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 (140) hide show
  1. package/README.md +153 -0
  2. package/dist/ai-bridge/css.d.ts +2 -0
  3. package/dist/ai-bridge/css.js +366 -0
  4. package/dist/ai-bridge/index.d.ts +44 -0
  5. package/dist/ai-bridge/index.js +132 -0
  6. package/dist/ai-bridge/panel.d.ts +27 -0
  7. package/dist/ai-bridge/panel.js +715 -0
  8. package/dist/ascii-view/css.d.ts +4 -0
  9. package/dist/ascii-view/css.js +83 -0
  10. package/dist/ascii-view/index.d.ts +25 -0
  11. package/dist/ascii-view/index.js +92 -0
  12. package/dist/command-palette/css.d.ts +4 -0
  13. package/dist/command-palette/css.js +157 -0
  14. package/dist/command-palette/index.d.ts +53 -0
  15. package/dist/command-palette/index.js +378 -0
  16. package/dist/command-palette-editor/index.d.ts +35 -0
  17. package/dist/command-palette-editor/index.js +60 -0
  18. package/dist/config-panel/css.d.ts +4 -0
  19. package/dist/config-panel/css.js +719 -0
  20. package/dist/config-panel/index.d.ts +36 -0
  21. package/dist/config-panel/index.js +73 -0
  22. package/dist/config-panel/renderer.d.ts +127 -0
  23. package/dist/config-panel/renderer.js +1162 -0
  24. package/dist/config-panel/types.d.ts +118 -0
  25. package/dist/config-panel/types.js +2 -0
  26. package/dist/config-panel-bpmn/index.d.ts +58 -0
  27. package/dist/config-panel-bpmn/index.js +1320 -0
  28. package/dist/config-panel-bpmn/template-engine.d.ts +17 -0
  29. package/dist/config-panel-bpmn/template-engine.js +307 -0
  30. package/dist/config-panel-bpmn/template-to-service-task.d.ts +30 -0
  31. package/dist/config-panel-bpmn/template-to-service-task.js +92 -0
  32. package/dist/config-panel-bpmn/template-types.d.ts +126 -0
  33. package/dist/config-panel-bpmn/template-types.js +6 -0
  34. package/dist/config-panel-bpmn/templates/generated.d.ts +3 -0
  35. package/dist/config-panel-bpmn/templates/generated.js +57865 -0
  36. package/dist/config-panel-bpmn/util.d.ts +46 -0
  37. package/dist/config-panel-bpmn/util.js +195 -0
  38. package/dist/dmn-editor/css.d.ts +3 -0
  39. package/dist/dmn-editor/css.js +667 -0
  40. package/dist/dmn-editor/dmn-editor.d.ts +34 -0
  41. package/dist/dmn-editor/dmn-editor.js +646 -0
  42. package/dist/dmn-editor/drd-canvas.d.ts +85 -0
  43. package/dist/dmn-editor/drd-canvas.js +1087 -0
  44. package/dist/dmn-editor/index.d.ts +3 -0
  45. package/dist/dmn-editor/index.js +2 -0
  46. package/dist/dmn-viewer/css.d.ts +3 -0
  47. package/dist/dmn-viewer/css.js +151 -0
  48. package/dist/dmn-viewer/dmn-viewer.d.ts +30 -0
  49. package/dist/dmn-viewer/dmn-viewer.js +160 -0
  50. package/dist/dmn-viewer/feel.d.ts +3 -0
  51. package/dist/dmn-viewer/feel.js +2 -0
  52. package/dist/dmn-viewer/index.d.ts +14 -0
  53. package/dist/dmn-viewer/index.js +12 -0
  54. package/dist/element-docs/content.d.ts +20 -0
  55. package/dist/element-docs/content.js +1032 -0
  56. package/dist/element-docs/index.d.ts +7 -0
  57. package/dist/element-docs/index.js +643 -0
  58. package/dist/feel-playground/css.d.ts +4 -0
  59. package/dist/feel-playground/css.js +292 -0
  60. package/dist/feel-playground/index.d.ts +4 -0
  61. package/dist/feel-playground/index.js +3 -0
  62. package/dist/feel-playground/playground-plugin.d.ts +14 -0
  63. package/dist/feel-playground/playground-plugin.js +292 -0
  64. package/dist/form-editor/css.d.ts +3 -0
  65. package/dist/form-editor/css.js +703 -0
  66. package/dist/form-editor/form-editor.d.ts +48 -0
  67. package/dist/form-editor/form-editor.js +1039 -0
  68. package/dist/form-editor/index.d.ts +3 -0
  69. package/dist/form-editor/index.js +2 -0
  70. package/dist/form-viewer/css.d.ts +3 -0
  71. package/dist/form-viewer/css.js +303 -0
  72. package/dist/form-viewer/form-viewer.d.ts +29 -0
  73. package/dist/form-viewer/form-viewer.js +376 -0
  74. package/dist/form-viewer/index.d.ts +12 -0
  75. package/dist/form-viewer/index.js +11 -0
  76. package/dist/history/checkpoint.d.ts +10 -0
  77. package/dist/history/checkpoint.js +92 -0
  78. package/dist/history/css.d.ts +2 -0
  79. package/dist/history/css.js +130 -0
  80. package/dist/history/history-panel.d.ts +12 -0
  81. package/dist/history/history-panel.js +142 -0
  82. package/dist/history/index.d.ts +5 -0
  83. package/dist/history/index.js +3 -0
  84. package/dist/main-menu/css.d.ts +4 -0
  85. package/dist/main-menu/css.js +272 -0
  86. package/dist/main-menu/index.d.ts +59 -0
  87. package/dist/main-menu/index.js +285 -0
  88. package/dist/minimap/css.d.ts +10 -0
  89. package/dist/minimap/css.js +54 -0
  90. package/dist/minimap/index.d.ts +38 -0
  91. package/dist/minimap/index.js +69 -0
  92. package/dist/minimap/minimap.d.ts +35 -0
  93. package/dist/minimap/minimap.js +166 -0
  94. package/dist/optimize/index.d.ts +21 -0
  95. package/dist/optimize/index.js +304 -0
  96. package/dist/process-runner/css.d.ts +2 -0
  97. package/dist/process-runner/css.js +467 -0
  98. package/dist/process-runner/index.d.ts +56 -0
  99. package/dist/process-runner/index.js +549 -0
  100. package/dist/storage/auto-save.d.ts +11 -0
  101. package/dist/storage/auto-save.js +44 -0
  102. package/dist/storage/css.d.ts +2 -0
  103. package/dist/storage/css.js +2 -0
  104. package/dist/storage/db.d.ts +99 -0
  105. package/dist/storage/db.js +116 -0
  106. package/dist/storage/dialog.d.ts +15 -0
  107. package/dist/storage/dialog.js +201 -0
  108. package/dist/storage/export.d.ts +3 -0
  109. package/dist/storage/export.js +137 -0
  110. package/dist/storage/index.d.ts +44 -0
  111. package/dist/storage/index.js +201 -0
  112. package/dist/storage/sidebar.d.ts +2 -0
  113. package/dist/storage/sidebar.js +2 -0
  114. package/dist/storage/storage-api.d.ts +76 -0
  115. package/dist/storage/storage-api.js +342 -0
  116. package/dist/storage/types.d.ts +44 -0
  117. package/dist/storage/types.js +2 -0
  118. package/dist/storage-tabs-bridge/index.d.ts +96 -0
  119. package/dist/storage-tabs-bridge/index.js +502 -0
  120. package/dist/tabs/css.d.ts +3 -0
  121. package/dist/tabs/css.js +642 -0
  122. package/dist/tabs/file-resolver.d.ts +71 -0
  123. package/dist/tabs/file-resolver.js +46 -0
  124. package/dist/tabs/index.d.ts +15 -0
  125. package/dist/tabs/index.js +13 -0
  126. package/dist/tabs/tabs-plugin.d.ts +250 -0
  127. package/dist/tabs/tabs-plugin.js +1119 -0
  128. package/dist/token-highlight/css.d.ts +2 -0
  129. package/dist/token-highlight/css.js +81 -0
  130. package/dist/token-highlight/index.d.ts +44 -0
  131. package/dist/token-highlight/index.js +164 -0
  132. package/dist/watermark/css.d.ts +10 -0
  133. package/dist/watermark/css.js +54 -0
  134. package/dist/watermark/index.d.ts +48 -0
  135. package/dist/watermark/index.js +64 -0
  136. package/dist/zoom-controls/css.d.ts +4 -0
  137. package/dist/zoom-controls/css.js +48 -0
  138. package/dist/zoom-controls/index.d.ts +36 -0
  139. package/dist/zoom-controls/index.js +111 -0
  140. package/package.json +121 -0
@@ -0,0 +1,646 @@
1
+ import { Dmn } from "@bpmnkit/core";
2
+ import { injectDmnEditorStyles } from "./css.js";
3
+ import { DrdCanvas } from "./drd-canvas.js";
4
+ const HP_OPTIONS = [
5
+ { label: "U - Unique", abbr: "U", hitPolicy: "UNIQUE" },
6
+ { label: "F - First", abbr: "F", hitPolicy: "FIRST" },
7
+ { label: "A - Any", abbr: "A", hitPolicy: "ANY" },
8
+ { label: "P - Priority", abbr: "P", hitPolicy: "PRIORITY" },
9
+ { label: "C - Collect", abbr: "C", hitPolicy: "COLLECT" },
10
+ { label: "C+ - Sum", abbr: "C+", hitPolicy: "COLLECT", aggregation: "SUM" },
11
+ { label: "C< - Min", abbr: "C<", hitPolicy: "COLLECT", aggregation: "MIN" },
12
+ { label: "C> - Max", abbr: "C>", hitPolicy: "COLLECT", aggregation: "MAX" },
13
+ { label: "C# - Count", abbr: "C#", hitPolicy: "COLLECT", aggregation: "COUNT" },
14
+ { label: "R - Rule Order", abbr: "R", hitPolicy: "RULE ORDER" },
15
+ { label: "O - Output Order", abbr: "O", hitPolicy: "OUTPUT ORDER" },
16
+ ];
17
+ const TYPEREFS = [
18
+ { value: "", label: "(none)" },
19
+ { value: "string", label: "string" },
20
+ { value: "number", label: "number" },
21
+ { value: "boolean", label: "boolean" },
22
+ { value: "date", label: "date" },
23
+ ];
24
+ function uid() {
25
+ return Math.random().toString(36).slice(2, 10);
26
+ }
27
+ function hpAbbr(hitPolicy, aggregation) {
28
+ if (!hitPolicy || hitPolicy === "UNIQUE")
29
+ return "U";
30
+ if (hitPolicy === "FIRST")
31
+ return "F";
32
+ if (hitPolicy === "ANY")
33
+ return "A";
34
+ if (hitPolicy === "PRIORITY")
35
+ return "P";
36
+ if (hitPolicy === "RULE ORDER")
37
+ return "R";
38
+ if (hitPolicy === "OUTPUT ORDER")
39
+ return "O";
40
+ if (hitPolicy === "COLLECT") {
41
+ if (aggregation === "SUM")
42
+ return "C+";
43
+ if (aggregation === "MIN")
44
+ return "C<";
45
+ if (aggregation === "MAX")
46
+ return "C>";
47
+ if (aggregation === "COUNT")
48
+ return "C#";
49
+ return "C";
50
+ }
51
+ return "U";
52
+ }
53
+ function hpOptionValue(opt) {
54
+ return opt.aggregation ? `${opt.hitPolicy}|${opt.aggregation}` : opt.hitPolicy;
55
+ }
56
+ /** Native DMN editor with DRD canvas and editable decision tables. Zero external dependencies. */
57
+ export class DmnEditor {
58
+ _defs = null;
59
+ _root;
60
+ _body;
61
+ _handlers = [];
62
+ _destroyed = false;
63
+ _ctxMenu = null;
64
+ // View state: "drd" = DRD canvas, "table" = specific decision table
65
+ _view = "drd";
66
+ _activeDecisionId = null;
67
+ _drdCanvas = null;
68
+ constructor(options) {
69
+ injectDmnEditorStyles();
70
+ this._root = document.createElement("div");
71
+ this._root.className = `dmn-editor ${options.theme ?? "light"}`;
72
+ this._body = document.createElement("div");
73
+ this._body.className = "dmn-editor-body";
74
+ this._root.appendChild(this._body);
75
+ options.container.appendChild(this._root);
76
+ }
77
+ async loadXML(xml) {
78
+ this._defs = Dmn.parse(xml);
79
+ this._view = "drd";
80
+ this._activeDecisionId = null;
81
+ this._render();
82
+ }
83
+ async getXML() {
84
+ if (!this._defs)
85
+ return "";
86
+ return Dmn.export(this._defs);
87
+ }
88
+ onChange(handler) {
89
+ this._handlers.push(handler);
90
+ return () => {
91
+ const idx = this._handlers.indexOf(handler);
92
+ if (idx !== -1)
93
+ this._handlers.splice(idx, 1);
94
+ };
95
+ }
96
+ setTheme(theme) {
97
+ this._root.className = `dmn-editor ${theme}`;
98
+ }
99
+ destroy() {
100
+ this._destroyed = true;
101
+ this._handlers.length = 0;
102
+ this._closeCtxMenu();
103
+ this._drdCanvas?.destroy();
104
+ this._drdCanvas = null;
105
+ this._root.remove();
106
+ }
107
+ _emit() {
108
+ if (this._destroyed)
109
+ return;
110
+ for (const h of this._handlers)
111
+ h();
112
+ }
113
+ // ── Routing ────────────────────────────────────────────────────────────────
114
+ _render() {
115
+ this._body.innerHTML = "";
116
+ this._drdCanvas?.destroy();
117
+ this._drdCanvas = null;
118
+ if (!this._defs)
119
+ return;
120
+ if (this._view === "drd") {
121
+ this._renderDrd();
122
+ }
123
+ else {
124
+ this._renderTableView();
125
+ }
126
+ }
127
+ _renderDrd() {
128
+ if (!this._defs)
129
+ return;
130
+ const defs = this._defs;
131
+ this._drdCanvas = new DrdCanvas({
132
+ container: this._body,
133
+ defs,
134
+ onChange: () => this._emit(),
135
+ onDecisionOpen: (id) => {
136
+ this._activeDecisionId = id;
137
+ this._view = "table";
138
+ this._render();
139
+ },
140
+ });
141
+ }
142
+ _renderTableView() {
143
+ if (!this._defs || !this._activeDecisionId)
144
+ return;
145
+ const decision = this._defs.decisions.find((d) => d.id === this._activeDecisionId);
146
+ if (!decision)
147
+ return;
148
+ // Back bar
149
+ const backBar = document.createElement("div");
150
+ backBar.className = "dme-back-bar";
151
+ const backBtn = document.createElement("button");
152
+ backBtn.type = "button";
153
+ backBtn.className = "dme-btn dme-back-btn";
154
+ backBtn.textContent = "← DRD";
155
+ backBtn.title = "Back to diagram";
156
+ backBtn.addEventListener("click", () => {
157
+ this._view = "drd";
158
+ this._activeDecisionId = null;
159
+ this._render();
160
+ });
161
+ backBar.appendChild(backBtn);
162
+ const title = document.createElement("span");
163
+ title.className = "dme-back-title";
164
+ title.textContent = decision.name ?? decision.id;
165
+ backBar.appendChild(title);
166
+ this._body.appendChild(backBar);
167
+ // Table content
168
+ const tableWrap = document.createElement("div");
169
+ tableWrap.className = "dme-table-wrap";
170
+ this._body.appendChild(tableWrap);
171
+ tableWrap.appendChild(this._renderDecision(decision));
172
+ }
173
+ // ── Context menu ────────────────────────────────────────────────────────────
174
+ _closeCtxMenu() {
175
+ if (this._ctxMenu) {
176
+ this._ctxMenu.remove();
177
+ this._ctxMenu = null;
178
+ }
179
+ }
180
+ _openCtxMenu(e, items) {
181
+ e.preventDefault();
182
+ this._closeCtxMenu();
183
+ const menu = document.createElement("div");
184
+ menu.className = "dme-ctx-menu";
185
+ menu.style.left = `${e.clientX}px`;
186
+ menu.style.top = `${e.clientY}px`;
187
+ for (const item of items) {
188
+ if (item === "sep") {
189
+ const sep = document.createElement("hr");
190
+ sep.className = "dme-ctx-sep";
191
+ menu.appendChild(sep);
192
+ }
193
+ else {
194
+ const btn = document.createElement("div");
195
+ btn.className = "dme-ctx-item";
196
+ btn.textContent = item.label;
197
+ btn.addEventListener("click", () => {
198
+ item.action();
199
+ this._closeCtxMenu();
200
+ });
201
+ menu.appendChild(btn);
202
+ }
203
+ }
204
+ this._ctxMenu = menu;
205
+ document.body.appendChild(menu);
206
+ setTimeout(() => {
207
+ const closeHandler = (ev) => {
208
+ if (!menu.contains(ev.target)) {
209
+ this._closeCtxMenu();
210
+ document.removeEventListener("click", closeHandler);
211
+ }
212
+ };
213
+ document.addEventListener("click", closeHandler);
214
+ }, 0);
215
+ }
216
+ // ── Decision table rendering ────────────────────────────────────────────────
217
+ _renderDecision(decision) {
218
+ const section = document.createElement("div");
219
+ section.className = "dme-decision";
220
+ const header = document.createElement("div");
221
+ header.className = "dme-decision-header";
222
+ const nameInput = document.createElement("input");
223
+ nameInput.type = "text";
224
+ nameInput.className = "dme-name-input";
225
+ nameInput.value = decision.name ?? "";
226
+ nameInput.placeholder = "Decision name";
227
+ nameInput.addEventListener("input", () => {
228
+ decision.name = nameInput.value;
229
+ // Update breadcrumb title if in table view
230
+ const titleEl = this._body.querySelector(".dme-back-title");
231
+ if (titleEl)
232
+ titleEl.textContent = decision.name || decision.id;
233
+ // Update DRD canvas label (re-render DRD after returning)
234
+ this._emit();
235
+ });
236
+ header.appendChild(nameInput);
237
+ section.appendChild(header);
238
+ // Ensure decision table exists
239
+ if (!decision.decisionTable) {
240
+ decision.decisionTable = {
241
+ id: uid(),
242
+ inputs: [],
243
+ outputs: [{ id: uid(), name: "result", label: "Result" }],
244
+ rules: [],
245
+ };
246
+ }
247
+ const dt = decision.decisionTable;
248
+ const tableWrapper = document.createElement("div");
249
+ const rerender = () => {
250
+ tableWrapper.innerHTML = "";
251
+ tableWrapper.appendChild(this._buildTable(dt, rerender));
252
+ };
253
+ rerender();
254
+ section.appendChild(tableWrapper);
255
+ const addRuleBtn = document.createElement("button");
256
+ addRuleBtn.type = "button";
257
+ addRuleBtn.className = "dme-btn dme-add-rule";
258
+ addRuleBtn.textContent = "+ Add Rule";
259
+ addRuleBtn.addEventListener("click", () => {
260
+ const inputEntries = dt.inputs.map(() => ({ id: uid(), text: "" }));
261
+ const outputEntries = dt.outputs.map(() => ({ id: uid(), text: "" }));
262
+ dt.rules.push({ id: uid(), inputEntries, outputEntries });
263
+ rerender();
264
+ this._emit();
265
+ });
266
+ section.appendChild(addRuleBtn);
267
+ return section;
268
+ }
269
+ _buildTable(dt, rerender) {
270
+ const table = document.createElement("table");
271
+ table.className = "dme-table";
272
+ // ── thead ──
273
+ const thead = document.createElement("thead");
274
+ const headerRow = document.createElement("tr");
275
+ // Hit policy cell
276
+ const hpTh = document.createElement("th");
277
+ hpTh.className = "dme-th-hp";
278
+ const hpAbbrSpan = document.createElement("span");
279
+ hpAbbrSpan.className = "dme-hp-abbr";
280
+ hpAbbrSpan.textContent = hpAbbr(dt.hitPolicy, dt.aggregation);
281
+ const hpSel = document.createElement("select");
282
+ hpSel.className = "dme-hp-select";
283
+ const currentHpVal = hpOptionValue({
284
+ hitPolicy: dt.hitPolicy ?? "UNIQUE",
285
+ aggregation: dt.aggregation,
286
+ });
287
+ for (const opt of HP_OPTIONS) {
288
+ const optEl = document.createElement("option");
289
+ optEl.value = hpOptionValue(opt);
290
+ optEl.textContent = opt.label;
291
+ optEl.selected = hpOptionValue(opt) === currentHpVal;
292
+ hpSel.appendChild(optEl);
293
+ }
294
+ hpSel.addEventListener("change", () => {
295
+ const parts = hpSel.value.split("|");
296
+ dt.hitPolicy = parts[0];
297
+ dt.aggregation = parts[1];
298
+ hpAbbrSpan.textContent = hpAbbr(dt.hitPolicy, dt.aggregation);
299
+ this._emit();
300
+ });
301
+ hpTh.appendChild(hpAbbrSpan);
302
+ hpTh.appendChild(hpSel);
303
+ headerRow.appendChild(hpTh);
304
+ // Input column headers
305
+ for (let i = 0; i < dt.inputs.length; i++) {
306
+ const input = dt.inputs[i];
307
+ if (!input)
308
+ continue;
309
+ const isLast = i === dt.inputs.length - 1;
310
+ const th = document.createElement("th");
311
+ th.className = isLast ? "dme-th-input dme-last-input" : "dme-th-input";
312
+ const clauseDiv = document.createElement("div");
313
+ clauseDiv.className = "dme-clause";
314
+ clauseDiv.textContent = i === 0 ? "When" : "And";
315
+ th.appendChild(clauseDiv);
316
+ const labelIn = document.createElement("input");
317
+ labelIn.type = "text";
318
+ labelIn.className = "dme-col-label";
319
+ labelIn.value = input.label ?? "";
320
+ labelIn.placeholder = "Label";
321
+ labelIn.addEventListener("input", () => {
322
+ input.label = labelIn.value;
323
+ this._emit();
324
+ });
325
+ th.appendChild(labelIn);
326
+ const exprIn = document.createElement("input");
327
+ exprIn.type = "text";
328
+ exprIn.className = "dme-col-expr";
329
+ exprIn.value = input.inputExpression.text ?? "";
330
+ exprIn.placeholder = "Expression";
331
+ exprIn.addEventListener("input", () => {
332
+ input.inputExpression.text = exprIn.value;
333
+ this._emit();
334
+ });
335
+ th.appendChild(exprIn);
336
+ const footer = document.createElement("div");
337
+ footer.className = "dme-col-footer";
338
+ const typeRefSel = this._buildTypeRefSelect(input.inputExpression.typeRef, (val) => {
339
+ input.inputExpression.typeRef = val;
340
+ this._emit();
341
+ });
342
+ footer.appendChild(typeRefSel);
343
+ const delBtn = document.createElement("button");
344
+ delBtn.type = "button";
345
+ delBtn.className = "dme-btn dme-btn-icon";
346
+ delBtn.title = "Remove input column";
347
+ delBtn.textContent = "×";
348
+ delBtn.addEventListener("click", () => {
349
+ dt.inputs.splice(i, 1);
350
+ for (const rule of dt.rules)
351
+ rule.inputEntries.splice(i, 1);
352
+ rerender();
353
+ this._emit();
354
+ });
355
+ footer.appendChild(delBtn);
356
+ th.appendChild(footer);
357
+ th.addEventListener("contextmenu", (e) => {
358
+ this._openCtxMenu(e, [
359
+ {
360
+ label: "Add input left",
361
+ action: () => {
362
+ dt.inputs.splice(i, 0, {
363
+ id: uid(),
364
+ label: "",
365
+ inputExpression: { id: uid(), text: "" },
366
+ });
367
+ for (const r of dt.rules)
368
+ r.inputEntries.splice(i, 0, { id: uid(), text: "" });
369
+ rerender();
370
+ this._emit();
371
+ },
372
+ },
373
+ {
374
+ label: "Add input right",
375
+ action: () => {
376
+ dt.inputs.splice(i + 1, 0, {
377
+ id: uid(),
378
+ label: "",
379
+ inputExpression: { id: uid(), text: "" },
380
+ });
381
+ for (const r of dt.rules)
382
+ r.inputEntries.splice(i + 1, 0, { id: uid(), text: "" });
383
+ rerender();
384
+ this._emit();
385
+ },
386
+ },
387
+ "sep",
388
+ {
389
+ label: "Remove column",
390
+ action: () => {
391
+ dt.inputs.splice(i, 1);
392
+ for (const r of dt.rules)
393
+ r.inputEntries.splice(i, 1);
394
+ rerender();
395
+ this._emit();
396
+ },
397
+ },
398
+ ]);
399
+ });
400
+ headerRow.appendChild(th);
401
+ }
402
+ // Output column headers
403
+ for (let i = 0; i < dt.outputs.length; i++) {
404
+ const output = dt.outputs[i];
405
+ if (!output)
406
+ continue;
407
+ const th = document.createElement("th");
408
+ th.className = "dme-th-output";
409
+ const clauseDiv = document.createElement("div");
410
+ clauseDiv.className = "dme-clause";
411
+ clauseDiv.textContent = i === 0 ? "Then" : "And";
412
+ th.appendChild(clauseDiv);
413
+ const labelIn = document.createElement("input");
414
+ labelIn.type = "text";
415
+ labelIn.className = "dme-col-label";
416
+ labelIn.value = output.label ?? "";
417
+ labelIn.placeholder = "Label";
418
+ labelIn.addEventListener("input", () => {
419
+ output.label = labelIn.value;
420
+ this._emit();
421
+ });
422
+ th.appendChild(labelIn);
423
+ const nameIn = document.createElement("input");
424
+ nameIn.type = "text";
425
+ nameIn.className = "dme-col-expr";
426
+ nameIn.value = output.name ?? "";
427
+ nameIn.placeholder = "Variable";
428
+ nameIn.addEventListener("input", () => {
429
+ output.name = nameIn.value;
430
+ this._emit();
431
+ });
432
+ th.appendChild(nameIn);
433
+ const footer = document.createElement("div");
434
+ footer.className = "dme-col-footer";
435
+ const typeRefSel = this._buildTypeRefSelect(output.typeRef, (val) => {
436
+ output.typeRef = val;
437
+ this._emit();
438
+ });
439
+ footer.appendChild(typeRefSel);
440
+ const delBtn = document.createElement("button");
441
+ delBtn.type = "button";
442
+ delBtn.className = "dme-btn dme-btn-icon";
443
+ delBtn.title = "Remove output column";
444
+ delBtn.textContent = "×";
445
+ delBtn.addEventListener("click", () => {
446
+ dt.outputs.splice(i, 1);
447
+ for (const rule of dt.rules)
448
+ rule.outputEntries.splice(i, 1);
449
+ rerender();
450
+ this._emit();
451
+ });
452
+ footer.appendChild(delBtn);
453
+ th.appendChild(footer);
454
+ th.addEventListener("contextmenu", (e) => {
455
+ this._openCtxMenu(e, [
456
+ {
457
+ label: "Add output left",
458
+ action: () => {
459
+ dt.outputs.splice(i, 0, { id: uid(), label: "", name: "" });
460
+ for (const r of dt.rules)
461
+ r.outputEntries.splice(i, 0, { id: uid(), text: "" });
462
+ rerender();
463
+ this._emit();
464
+ },
465
+ },
466
+ {
467
+ label: "Add output right",
468
+ action: () => {
469
+ dt.outputs.splice(i + 1, 0, { id: uid(), label: "", name: "" });
470
+ for (const r of dt.rules)
471
+ r.outputEntries.splice(i + 1, 0, { id: uid(), text: "" });
472
+ rerender();
473
+ this._emit();
474
+ },
475
+ },
476
+ "sep",
477
+ {
478
+ label: "Remove column",
479
+ action: () => {
480
+ dt.outputs.splice(i, 1);
481
+ for (const r of dt.rules)
482
+ r.outputEntries.splice(i, 1);
483
+ rerender();
484
+ this._emit();
485
+ },
486
+ },
487
+ ]);
488
+ });
489
+ headerRow.appendChild(th);
490
+ }
491
+ // Annotation column header
492
+ const annotTh = document.createElement("th");
493
+ annotTh.className = "dme-th-annotation";
494
+ const annotClause = document.createElement("div");
495
+ annotClause.className = "dme-clause";
496
+ annotClause.textContent = "Annotation";
497
+ annotTh.appendChild(annotClause);
498
+ headerRow.appendChild(annotTh);
499
+ // Add column buttons
500
+ const addTh = document.createElement("th");
501
+ addTh.className = "dme-th-add";
502
+ const addInBtn = document.createElement("button");
503
+ addInBtn.type = "button";
504
+ addInBtn.className = "dme-btn dme-btn-icon";
505
+ addInBtn.title = "Add input column";
506
+ addInBtn.textContent = "+I";
507
+ addInBtn.addEventListener("click", () => {
508
+ dt.inputs.push({ id: uid(), label: "", inputExpression: { id: uid(), text: "" } });
509
+ for (const rule of dt.rules)
510
+ rule.inputEntries.push({ id: uid(), text: "" });
511
+ rerender();
512
+ this._emit();
513
+ });
514
+ addTh.appendChild(addInBtn);
515
+ const addOutBtn = document.createElement("button");
516
+ addOutBtn.type = "button";
517
+ addOutBtn.className = "dme-btn dme-btn-icon";
518
+ addOutBtn.title = "Add output column";
519
+ addOutBtn.textContent = "+O";
520
+ addOutBtn.addEventListener("click", () => {
521
+ dt.outputs.push({ id: uid(), label: "", name: "" });
522
+ for (const rule of dt.rules)
523
+ rule.outputEntries.push({ id: uid(), text: "" });
524
+ rerender();
525
+ this._emit();
526
+ });
527
+ addTh.appendChild(addOutBtn);
528
+ headerRow.appendChild(addTh);
529
+ thead.appendChild(headerRow);
530
+ table.appendChild(thead);
531
+ // ── tbody ──
532
+ const tbody = document.createElement("tbody");
533
+ for (let ri = 0; ri < dt.rules.length; ri++) {
534
+ const rule = dt.rules[ri];
535
+ if (!rule)
536
+ continue;
537
+ tbody.appendChild(this._buildRuleRow(rule, ri, dt, rerender));
538
+ }
539
+ table.appendChild(tbody);
540
+ return table;
541
+ }
542
+ _buildTypeRefSelect(current, onChange) {
543
+ const sel = document.createElement("select");
544
+ sel.className = "dme-typeref";
545
+ for (const tr of TYPEREFS) {
546
+ const opt = document.createElement("option");
547
+ opt.value = tr.value;
548
+ opt.textContent = tr.label;
549
+ opt.selected = (current ?? "") === tr.value;
550
+ sel.appendChild(opt);
551
+ }
552
+ sel.addEventListener("change", () => {
553
+ onChange((sel.value || undefined));
554
+ });
555
+ return sel;
556
+ }
557
+ _buildRuleRow(rule, ruleIdx, dt, rerender) {
558
+ const tr = document.createElement("tr");
559
+ const numTd = document.createElement("td");
560
+ numTd.className = "dme-row-num";
561
+ numTd.textContent = String(ruleIdx + 1);
562
+ numTd.addEventListener("contextmenu", (e) => {
563
+ this._openCtxMenu(e, [
564
+ {
565
+ label: "Add rule above",
566
+ action: () => {
567
+ const inputEntries = dt.inputs.map(() => ({ id: uid(), text: "" }));
568
+ const outputEntries = dt.outputs.map(() => ({ id: uid(), text: "" }));
569
+ dt.rules.splice(ruleIdx, 0, { id: uid(), inputEntries, outputEntries });
570
+ rerender();
571
+ this._emit();
572
+ },
573
+ },
574
+ {
575
+ label: "Add rule below",
576
+ action: () => {
577
+ const inputEntries = dt.inputs.map(() => ({ id: uid(), text: "" }));
578
+ const outputEntries = dt.outputs.map(() => ({ id: uid(), text: "" }));
579
+ dt.rules.splice(ruleIdx + 1, 0, { id: uid(), inputEntries, outputEntries });
580
+ rerender();
581
+ this._emit();
582
+ },
583
+ },
584
+ "sep",
585
+ {
586
+ label: "Remove rule",
587
+ action: () => {
588
+ dt.rules.splice(ruleIdx, 1);
589
+ rerender();
590
+ this._emit();
591
+ },
592
+ },
593
+ ]);
594
+ });
595
+ tr.appendChild(numTd);
596
+ for (let i = 0; i < dt.inputs.length; i++) {
597
+ const entry = rule.inputEntries[i];
598
+ if (!entry)
599
+ continue;
600
+ const td = document.createElement("td");
601
+ if (i === dt.inputs.length - 1)
602
+ td.className = "dme-last-input";
603
+ td.appendChild(this._buildEntryInput(entry));
604
+ tr.appendChild(td);
605
+ }
606
+ for (let i = 0; i < dt.outputs.length; i++) {
607
+ const entry = rule.outputEntries[i];
608
+ if (!entry)
609
+ continue;
610
+ const td = document.createElement("td");
611
+ td.appendChild(this._buildEntryInput(entry));
612
+ tr.appendChild(td);
613
+ }
614
+ const annotTd = document.createElement("td");
615
+ annotTd.className = "dme-cell-annotation";
616
+ const annotTa = document.createElement("textarea");
617
+ annotTa.className = "dme-entry";
618
+ annotTa.value = rule.description ?? "";
619
+ annotTa.rows = 1;
620
+ annotTa.spellcheck = false;
621
+ annotTa.addEventListener("input", () => {
622
+ rule.description = annotTa.value || undefined;
623
+ annotTa.style.height = "auto";
624
+ annotTa.style.height = `${annotTa.scrollHeight}px`;
625
+ this._emit();
626
+ });
627
+ annotTd.appendChild(annotTa);
628
+ tr.appendChild(annotTd);
629
+ return tr;
630
+ }
631
+ _buildEntryInput(entry) {
632
+ const ta = document.createElement("textarea");
633
+ ta.className = "dme-entry";
634
+ ta.value = entry.text;
635
+ ta.rows = 1;
636
+ ta.spellcheck = false;
637
+ ta.addEventListener("input", () => {
638
+ entry.text = ta.value;
639
+ ta.style.height = "auto";
640
+ ta.style.height = `${ta.scrollHeight}px`;
641
+ this._emit();
642
+ });
643
+ return ta;
644
+ }
645
+ }
646
+ //# sourceMappingURL=dmn-editor.js.map