@luckydraw/blex 0.1.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 (97) hide show
  1. package/README.md +298 -0
  2. package/dist/blex-chart.min.global.js +23 -0
  3. package/dist/blex-chart.min.global.js.map +1 -0
  4. package/dist/blex.min.global.js +105 -0
  5. package/dist/blex.min.global.js.map +1 -0
  6. package/dist/esm/base-renderer.d.ts +28 -0
  7. package/dist/esm/base-renderer.d.ts.map +1 -0
  8. package/dist/esm/calendar-HUZDQQN2.js +314 -0
  9. package/dist/esm/calendar-HUZDQQN2.js.map +1 -0
  10. package/dist/esm/chart/index.d.ts +14 -0
  11. package/dist/esm/chart/index.d.ts.map +1 -0
  12. package/dist/esm/chart/index.js +3 -0
  13. package/dist/esm/chart/index.js.map +1 -0
  14. package/dist/esm/chart-2QT47W6E.js +38 -0
  15. package/dist/esm/chart-2QT47W6E.js.map +1 -0
  16. package/dist/esm/chunk-ODHF7VXV.js +74 -0
  17. package/dist/esm/chunk-ODHF7VXV.js.map +1 -0
  18. package/dist/esm/chunk-PBRPD4A5.js +91 -0
  19. package/dist/esm/chunk-PBRPD4A5.js.map +1 -0
  20. package/dist/esm/chunk-ZKSJGHJI.js +1573 -0
  21. package/dist/esm/chunk-ZKSJGHJI.js.map +1 -0
  22. package/dist/esm/defaults.d.ts +6 -0
  23. package/dist/esm/defaults.d.ts.map +1 -0
  24. package/dist/esm/fallback.d.ts +11 -0
  25. package/dist/esm/fallback.d.ts.map +1 -0
  26. package/dist/esm/gallery-ISM7FZA3.js +130 -0
  27. package/dist/esm/gallery-ISM7FZA3.js.map +1 -0
  28. package/dist/esm/index.d.ts +8 -0
  29. package/dist/esm/index.d.ts.map +1 -0
  30. package/dist/esm/index.js +91 -0
  31. package/dist/esm/index.js.map +1 -0
  32. package/dist/esm/kanban-XUXVTRX2.js +126 -0
  33. package/dist/esm/kanban-XUXVTRX2.js.map +1 -0
  34. package/dist/esm/mermaid-W3HX2CK2.js +130 -0
  35. package/dist/esm/mermaid-W3HX2CK2.js.map +1 -0
  36. package/dist/esm/placeholder.d.ts +8 -0
  37. package/dist/esm/placeholder.d.ts.map +1 -0
  38. package/dist/esm/plugin.d.ts +34 -0
  39. package/dist/esm/plugin.d.ts.map +1 -0
  40. package/dist/esm/react/chart.d.ts +12 -0
  41. package/dist/esm/react/chart.d.ts.map +1 -0
  42. package/dist/esm/react/chart.js +50 -0
  43. package/dist/esm/react/chart.js.map +1 -0
  44. package/dist/esm/react/index.d.ts +13 -0
  45. package/dist/esm/react/index.d.ts.map +1 -0
  46. package/dist/esm/react/index.js +66 -0
  47. package/dist/esm/react/index.js.map +1 -0
  48. package/dist/esm/registry.d.ts +46 -0
  49. package/dist/esm/registry.d.ts.map +1 -0
  50. package/dist/esm/render.d.ts +13 -0
  51. package/dist/esm/render.d.ts.map +1 -0
  52. package/dist/esm/renderers/calendar.d.ts +34 -0
  53. package/dist/esm/renderers/calendar.d.ts.map +1 -0
  54. package/dist/esm/renderers/chart.d.ts +12 -0
  55. package/dist/esm/renderers/chart.d.ts.map +1 -0
  56. package/dist/esm/renderers/code.d.ts +19 -0
  57. package/dist/esm/renderers/code.d.ts.map +1 -0
  58. package/dist/esm/renderers/confirm.d.ts +13 -0
  59. package/dist/esm/renderers/confirm.d.ts.map +1 -0
  60. package/dist/esm/renderers/diff.d.ts +24 -0
  61. package/dist/esm/renderers/diff.d.ts.map +1 -0
  62. package/dist/esm/renderers/file-tree.d.ts +24 -0
  63. package/dist/esm/renderers/file-tree.d.ts.map +1 -0
  64. package/dist/esm/renderers/form.d.ts +27 -0
  65. package/dist/esm/renderers/form.d.ts.map +1 -0
  66. package/dist/esm/renderers/gallery.d.ts +24 -0
  67. package/dist/esm/renderers/gallery.d.ts.map +1 -0
  68. package/dist/esm/renderers/image.d.ts +17 -0
  69. package/dist/esm/renderers/image.d.ts.map +1 -0
  70. package/dist/esm/renderers/kanban.d.ts +29 -0
  71. package/dist/esm/renderers/kanban.d.ts.map +1 -0
  72. package/dist/esm/renderers/layout.d.ts +17 -0
  73. package/dist/esm/renderers/layout.d.ts.map +1 -0
  74. package/dist/esm/renderers/mermaid.d.ts +19 -0
  75. package/dist/esm/renderers/mermaid.d.ts.map +1 -0
  76. package/dist/esm/renderers/metric.d.ts +16 -0
  77. package/dist/esm/renderers/metric.d.ts.map +1 -0
  78. package/dist/esm/renderers/poll.d.ts +17 -0
  79. package/dist/esm/renderers/poll.d.ts.map +1 -0
  80. package/dist/esm/renderers/progress.d.ts +18 -0
  81. package/dist/esm/renderers/progress.d.ts.map +1 -0
  82. package/dist/esm/renderers/status.d.ts +17 -0
  83. package/dist/esm/renderers/status.d.ts.map +1 -0
  84. package/dist/esm/renderers/svg.d.ts +13 -0
  85. package/dist/esm/renderers/svg.d.ts.map +1 -0
  86. package/dist/esm/renderers/table.d.ts +20 -0
  87. package/dist/esm/renderers/table.d.ts.map +1 -0
  88. package/dist/esm/renderers/terminal.d.ts +16 -0
  89. package/dist/esm/renderers/terminal.d.ts.map +1 -0
  90. package/dist/esm/renderers/timeline.d.ts +20 -0
  91. package/dist/esm/renderers/timeline.d.ts.map +1 -0
  92. package/dist/esm/theme.d.ts +10 -0
  93. package/dist/esm/theme.d.ts.map +1 -0
  94. package/dist/esm/types-C42V92x6.d.ts +75 -0
  95. package/dist/esm/types.d.ts +81 -0
  96. package/dist/esm/types.d.ts.map +1 -0
  97. package/package.json +82 -0
@@ -0,0 +1,1573 @@
1
+ import { BaseRenderer } from './chunk-ODHF7VXV.js';
2
+ import DOMPurify from 'dompurify';
3
+
4
+ // src/registry.ts
5
+ var registry = /* @__PURE__ */ new Map();
6
+ var builtInTypes = /* @__PURE__ */ new Set();
7
+ function registerBlockType(type, factory) {
8
+ registry.set(type, { factory });
9
+ }
10
+ function markBuiltIn(type) {
11
+ builtInTypes.add(type);
12
+ }
13
+ function isBuiltIn(type) {
14
+ return builtInTypes.has(type);
15
+ }
16
+ function unregisterBlockType(type, options) {
17
+ if (!registry.has(type)) return false;
18
+ if (builtInTypes.has(type) && !options?.force) {
19
+ throw new Error(`Cannot unregister built-in block type "${type}" without force: true`);
20
+ }
21
+ registry.delete(type);
22
+ builtInTypes.delete(type);
23
+ return true;
24
+ }
25
+ function registerLazyBlockType(type, loader) {
26
+ registry.set(type, { loader });
27
+ }
28
+ async function resolveRenderer(type) {
29
+ const entry = registry.get(type);
30
+ if (!entry) return null;
31
+ if (entry.factory) {
32
+ return entry.factory();
33
+ }
34
+ if (entry.loader) {
35
+ const factory = await entry.loader();
36
+ entry.factory = factory;
37
+ entry.loader = void 0;
38
+ return factory();
39
+ }
40
+ return null;
41
+ }
42
+ function hasBlockType(type) {
43
+ return registry.has(type);
44
+ }
45
+ function getRegisteredTypes() {
46
+ return Array.from(registry.keys());
47
+ }
48
+
49
+ // src/fallback.ts
50
+ var FallbackRenderer = class extends BaseRenderer {
51
+ render(block, container) {
52
+ this.container = container;
53
+ const details = document.createElement("details");
54
+ details.setAttribute("data-testid", `blex-fallback-${block.id}`);
55
+ const summary = document.createElement("summary");
56
+ summary.textContent = `Unknown block type: ${block.type}`;
57
+ summary.setAttribute("data-testid", `blex-fallback-summary-${block.id}`);
58
+ details.appendChild(summary);
59
+ const pre = document.createElement("pre");
60
+ const code = document.createElement("code");
61
+ code.textContent = JSON.stringify(block.data, null, 2);
62
+ pre.appendChild(code);
63
+ details.appendChild(pre);
64
+ container.appendChild(details);
65
+ container.setAttribute("data-blex-ready", "true");
66
+ }
67
+ update(block) {
68
+ if (!this.container) return;
69
+ const code = this.container.querySelector("code");
70
+ if (code) {
71
+ code.textContent = JSON.stringify(block.data, null, 2);
72
+ }
73
+ }
74
+ };
75
+
76
+ // src/theme.ts
77
+ var THEME_ID = "blex-theme-defaults";
78
+ var DEFAULT_STYLES = `
79
+ :root {
80
+ --blex-bg: #ffffff;
81
+ --blex-text: #1a1a1a;
82
+ --blex-border: #e5e5e5;
83
+ --blex-accent: #3b82f6;
84
+ --blex-success: #22c55e;
85
+ --blex-warning: #f59e0b;
86
+ --blex-error: #ef4444;
87
+ --blex-chart-bg: var(--blex-bg);
88
+ --blex-chart-text: var(--blex-text);
89
+ --blex-animation-duration: 200ms;
90
+ --blex-font-family: system-ui, -apple-system, sans-serif;
91
+ --blex-font-mono: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, monospace;
92
+ }
93
+
94
+ [data-theme="dark"] {
95
+ --blex-bg: #1a1a1a;
96
+ --blex-text: #e5e5e5;
97
+ --blex-border: #333333;
98
+ --blex-accent: #60a5fa;
99
+ --blex-success: #4ade80;
100
+ --blex-warning: #fbbf24;
101
+ --blex-error: #f87171;
102
+ }
103
+
104
+ [data-test-mode="true"] *,
105
+ [data-test-mode="true"] *::before,
106
+ [data-test-mode="true"] *::after {
107
+ animation-duration: 0.001ms !important;
108
+ transition-duration: 0.001ms !important;
109
+ }
110
+
111
+ .blex-placeholder {
112
+ display: flex;
113
+ align-items: center;
114
+ gap: 8px;
115
+ padding: 12px 16px;
116
+ border: 1px solid var(--blex-border);
117
+ border-radius: 6px;
118
+ background: var(--blex-bg);
119
+ color: var(--blex-text);
120
+ font-family: var(--blex-font-family);
121
+ }
122
+
123
+ .blex-placeholder__label {
124
+ font-size: 12px;
125
+ opacity: 0.6;
126
+ text-transform: uppercase;
127
+ letter-spacing: 0.05em;
128
+ }
129
+
130
+ .blex-placeholder__pulse {
131
+ width: 100%;
132
+ height: 20px;
133
+ background: linear-gradient(90deg, var(--blex-border) 25%, transparent 50%, var(--blex-border) 75%);
134
+ background-size: 200% 100%;
135
+ animation: blex-pulse var(--blex-animation-duration, 200ms) ease-in-out infinite;
136
+ animation-duration: 1.5s;
137
+ border-radius: 4px;
138
+ }
139
+
140
+ @keyframes blex-pulse {
141
+ 0% { background-position: 200% 0; }
142
+ 100% { background-position: -200% 0; }
143
+ }
144
+ `;
145
+ var injected = false;
146
+ function ensureTheme() {
147
+ if (injected) return;
148
+ if (typeof document === "undefined") return;
149
+ if (document.getElementById(THEME_ID)) {
150
+ injected = true;
151
+ return;
152
+ }
153
+ const style = document.createElement("style");
154
+ style.id = THEME_ID;
155
+ style.textContent = DEFAULT_STYLES;
156
+ document.head.appendChild(style);
157
+ injected = true;
158
+ }
159
+
160
+ // src/render.ts
161
+ async function renderBlock(block, container, options) {
162
+ ensureTheme();
163
+ container.innerHTML = "";
164
+ container.setAttribute("data-blex-type", block.type);
165
+ container.setAttribute("data-blex-id", block.id);
166
+ let renderer = await resolveRenderer(block.type);
167
+ if (!renderer) {
168
+ renderer = new FallbackRenderer();
169
+ }
170
+ renderer.render(block, container);
171
+ container.setAttribute("data-blex-ready", "true");
172
+ if (options?.onReady) {
173
+ options.onReady();
174
+ }
175
+ const handle = {
176
+ update(updatedBlock) {
177
+ if (renderer?.update) {
178
+ renderer.update(updatedBlock);
179
+ }
180
+ },
181
+ onInteraction(callback) {
182
+ if (renderer?.onInteraction) {
183
+ renderer.onInteraction(callback);
184
+ }
185
+ },
186
+ destroy() {
187
+ renderer?.destroy();
188
+ renderer = null;
189
+ container.removeAttribute("data-blex-type");
190
+ container.removeAttribute("data-blex-id");
191
+ container.removeAttribute("data-blex-ready");
192
+ }
193
+ };
194
+ return handle;
195
+ }
196
+
197
+ // src/renderers/confirm.ts
198
+ var DEFAULT_BUTTONS = ["Yes", "No", "Cancel"];
199
+ var ConfirmRenderer = class extends BaseRenderer {
200
+ render(block, container) {
201
+ this.container = container;
202
+ this._build(block);
203
+ container.setAttribute("data-blex-ready", "true");
204
+ }
205
+ update(block) {
206
+ if (!this.container) return;
207
+ this.container.innerHTML = "";
208
+ this._build(block);
209
+ }
210
+ _build(block) {
211
+ const container = this.container;
212
+ const data = block.data;
213
+ const buttons = data.buttons ?? DEFAULT_BUTTONS;
214
+ const wrapper = document.createElement("div");
215
+ wrapper.className = "blex-confirm";
216
+ wrapper.setAttribute("data-testid", `blex-confirm-${block.id}`);
217
+ const msg = document.createElement("p");
218
+ msg.className = "blex-confirm__message";
219
+ msg.setAttribute("data-testid", `blex-confirm-message-${block.id}`);
220
+ msg.textContent = data.message;
221
+ wrapper.appendChild(msg);
222
+ const btnGroup = document.createElement("div");
223
+ btnGroup.className = "blex-confirm__buttons";
224
+ for (const label of buttons) {
225
+ const btn = document.createElement("button");
226
+ btn.className = "blex-confirm__button";
227
+ btn.textContent = label;
228
+ btn.setAttribute("data-testid", `blex-confirm-btn-${label.toLowerCase()}`);
229
+ this.addListener(btn, "click", () => {
230
+ this.emit({
231
+ blockId: block.id,
232
+ type: "click",
233
+ payload: { button: label },
234
+ serialized: `User confirmed: ${data.message} \u2192 ${label}`
235
+ });
236
+ });
237
+ btnGroup.appendChild(btn);
238
+ }
239
+ wrapper.appendChild(btnGroup);
240
+ container.appendChild(wrapper);
241
+ }
242
+ };
243
+ function createConfirmRenderer() {
244
+ return new ConfirmRenderer();
245
+ }
246
+
247
+ // src/renderers/poll.ts
248
+ var PollRenderer = class extends BaseRenderer {
249
+ constructor() {
250
+ super(...arguments);
251
+ this.selected = /* @__PURE__ */ new Set();
252
+ this.writeInValue = "";
253
+ }
254
+ render(block, container) {
255
+ this.container = container;
256
+ this._build(block);
257
+ container.setAttribute("data-blex-ready", "true");
258
+ }
259
+ update(block) {
260
+ if (!this.container) return;
261
+ const newOptionCount = block.data.options.length;
262
+ for (const idx of Array.from(this.selected)) {
263
+ if (idx >= newOptionCount) this.selected.delete(idx);
264
+ }
265
+ this.container.innerHTML = "";
266
+ this._build(block);
267
+ }
268
+ _build(block) {
269
+ const container = this.container;
270
+ const { question, options, multiSelect, writeIn } = block.data;
271
+ const wrapper = document.createElement("div");
272
+ wrapper.className = "blex-poll";
273
+ wrapper.setAttribute("data-testid", `blex-poll-${block.id}`);
274
+ const q = document.createElement("p");
275
+ q.className = "blex-poll__question";
276
+ q.textContent = question;
277
+ wrapper.appendChild(q);
278
+ const optionsList = document.createElement("div");
279
+ optionsList.className = "blex-poll__options";
280
+ options.forEach((opt, i) => {
281
+ const btn = document.createElement("button");
282
+ btn.className = "blex-poll__option";
283
+ if (this.selected.has(i)) {
284
+ btn.classList.add("blex-poll__option--selected");
285
+ }
286
+ btn.setAttribute("data-testid", `blex-poll-option-${i}`);
287
+ btn.textContent = opt;
288
+ this.addListener(btn, "click", () => {
289
+ if (multiSelect) {
290
+ if (this.selected.has(i)) {
291
+ this.selected.delete(i);
292
+ btn.classList.remove("blex-poll__option--selected");
293
+ } else {
294
+ this.selected.add(i);
295
+ btn.classList.add("blex-poll__option--selected");
296
+ }
297
+ } else {
298
+ const allOptionBtns = optionsList.querySelectorAll(".blex-poll__option");
299
+ allOptionBtns.forEach((b) => b.classList.remove("blex-poll__option--selected"));
300
+ this.selected.clear();
301
+ this.selected.add(i);
302
+ btn.classList.add("blex-poll__option--selected");
303
+ }
304
+ });
305
+ optionsList.appendChild(btn);
306
+ });
307
+ wrapper.appendChild(optionsList);
308
+ if (writeIn) {
309
+ const writeInInput = document.createElement("input");
310
+ writeInInput.type = "text";
311
+ writeInInput.className = "blex-poll__writein";
312
+ writeInInput.placeholder = "Other...";
313
+ writeInInput.setAttribute("data-testid", `blex-poll-writein-${block.id}`);
314
+ writeInInput.value = this.writeInValue;
315
+ this.addListener(writeInInput, "input", () => {
316
+ this.writeInValue = writeInInput.value;
317
+ });
318
+ wrapper.appendChild(writeInInput);
319
+ }
320
+ const submitBtn = document.createElement("button");
321
+ submitBtn.className = "blex-poll__submit";
322
+ submitBtn.textContent = "Submit";
323
+ submitBtn.setAttribute("data-testid", `blex-poll-submit-${block.id}`);
324
+ this.addListener(submitBtn, "click", () => {
325
+ const selectedLabels = Array.from(this.selected).sort((a, b) => a - b).map((i) => options[i]);
326
+ const payload = {
327
+ selected: selectedLabels
328
+ };
329
+ let serialized = `Poll response: ${question}
330
+ Selected: ${selectedLabels.join(", ")}`;
331
+ if (this.writeInValue) {
332
+ payload.writeIn = this.writeInValue;
333
+ serialized += `
334
+ Write-in: ${this.writeInValue}`;
335
+ }
336
+ this.emit({
337
+ blockId: block.id,
338
+ type: "submit",
339
+ payload,
340
+ serialized
341
+ });
342
+ });
343
+ wrapper.appendChild(submitBtn);
344
+ container.appendChild(wrapper);
345
+ }
346
+ };
347
+ function createPollRenderer() {
348
+ return new PollRenderer();
349
+ }
350
+
351
+ // src/renderers/status.ts
352
+ var StatusRenderer = class extends BaseRenderer {
353
+ render(block, container) {
354
+ this.container = container;
355
+ this.renderContent(block);
356
+ }
357
+ update(block) {
358
+ if (!this.container) return;
359
+ this.container.innerHTML = "";
360
+ this.renderContent(block);
361
+ }
362
+ renderContent(block) {
363
+ const container = this.container;
364
+ const { entries } = block.data;
365
+ const wrapper = document.createElement("div");
366
+ wrapper.className = "blex-status";
367
+ wrapper.setAttribute("data-testid", `blex-status-${block.id}`);
368
+ for (let i = 0; i < entries.length; i++) {
369
+ const entry = entries[i];
370
+ const row = document.createElement("div");
371
+ row.className = "blex-status__entry";
372
+ row.setAttribute("data-testid", `blex-status-entry-${i}`);
373
+ const keyEl = document.createElement("span");
374
+ keyEl.className = "blex-status__key";
375
+ keyEl.textContent = entry.key;
376
+ row.appendChild(keyEl);
377
+ const valueEl = document.createElement("span");
378
+ valueEl.className = "blex-status__value";
379
+ valueEl.textContent = entry.value;
380
+ row.appendChild(valueEl);
381
+ if (entry.status) {
382
+ const dot = document.createElement("span");
383
+ dot.className = `blex-status__indicator blex-status__indicator--${entry.status}`;
384
+ row.appendChild(dot);
385
+ }
386
+ wrapper.appendChild(row);
387
+ }
388
+ container.appendChild(wrapper);
389
+ container.setAttribute("data-blex-ready", "true");
390
+ }
391
+ };
392
+ function createStatusRenderer() {
393
+ return new StatusRenderer();
394
+ }
395
+
396
+ // src/renderers/metric.ts
397
+ var TREND_ARROWS = {
398
+ up: "\u2191",
399
+ down: "\u2193",
400
+ flat: "\u2192"
401
+ };
402
+ var MetricRenderer = class extends BaseRenderer {
403
+ render(block, container) {
404
+ this.container = container;
405
+ this.renderContent(block);
406
+ }
407
+ update(block) {
408
+ if (!this.container) return;
409
+ this.container.innerHTML = "";
410
+ this.renderContent(block);
411
+ }
412
+ renderContent(block) {
413
+ const container = this.container;
414
+ const { value, label, trend, trendDirection } = block.data;
415
+ const wrapper = document.createElement("div");
416
+ wrapper.className = "blex-metric";
417
+ wrapper.setAttribute("data-testid", `blex-metric-${block.id}`);
418
+ const valueEl = document.createElement("div");
419
+ valueEl.className = "blex-metric__value";
420
+ valueEl.setAttribute("data-testid", `blex-metric-value-${block.id}`);
421
+ valueEl.textContent = value;
422
+ wrapper.appendChild(valueEl);
423
+ const labelEl = document.createElement("div");
424
+ labelEl.className = "blex-metric__label";
425
+ labelEl.setAttribute("data-testid", `blex-metric-label-${block.id}`);
426
+ labelEl.textContent = label;
427
+ wrapper.appendChild(labelEl);
428
+ if (trend !== void 0) {
429
+ const trendEl = document.createElement("div");
430
+ const arrow = trendDirection ? TREND_ARROWS[trendDirection] : "";
431
+ const directionClass = trendDirection ? ` blex-metric__trend--${trendDirection}` : "";
432
+ trendEl.className = `blex-metric__trend${directionClass}`;
433
+ trendEl.setAttribute("data-testid", `blex-metric-trend-${block.id}`);
434
+ trendEl.textContent = arrow ? `${arrow} ${trend}` : trend;
435
+ wrapper.appendChild(trendEl);
436
+ }
437
+ container.appendChild(wrapper);
438
+ container.setAttribute("data-blex-ready", "true");
439
+ }
440
+ };
441
+ function createMetricRenderer() {
442
+ return new MetricRenderer();
443
+ }
444
+ var ImageRenderer = class extends BaseRenderer {
445
+ render(block, container) {
446
+ this.container = container;
447
+ this._build(block);
448
+ container.setAttribute("data-blex-ready", "true");
449
+ }
450
+ update(block) {
451
+ if (!this.container) return;
452
+ this.container.innerHTML = "";
453
+ this._build(block);
454
+ }
455
+ _build(block) {
456
+ const container = this.container;
457
+ const { src, alt, caption, width, height } = block.data;
458
+ const wrapper = document.createElement("figure");
459
+ wrapper.className = "blex-image";
460
+ wrapper.setAttribute("data-testid", `blex-image-${block.id}`);
461
+ const img = document.createElement("img");
462
+ img.src = src;
463
+ img.alt = alt ?? "";
464
+ img.className = "blex-image__img";
465
+ img.setAttribute("data-testid", `blex-image-img-${block.id}`);
466
+ if (width !== void 0) img.width = width;
467
+ if (height !== void 0) img.height = height;
468
+ this.addListener(img, "click", () => this._openOverlay(src, alt));
469
+ wrapper.appendChild(img);
470
+ if (caption) {
471
+ const cap = document.createElement("figcaption");
472
+ cap.className = "blex-image__caption";
473
+ cap.setAttribute("data-testid", `blex-image-caption-${block.id}`);
474
+ cap.innerHTML = DOMPurify.sanitize(caption);
475
+ wrapper.appendChild(cap);
476
+ }
477
+ const actions = document.createElement("div");
478
+ actions.className = "blex-image__actions";
479
+ const zoomBtn = document.createElement("button");
480
+ zoomBtn.className = "blex-image__btn";
481
+ zoomBtn.textContent = "Zoom";
482
+ zoomBtn.setAttribute("data-testid", `blex-image-zoom-${block.id}`);
483
+ this.addListener(zoomBtn, "click", () => this._openOverlay(src, alt));
484
+ actions.appendChild(zoomBtn);
485
+ const downloadBtn = document.createElement("button");
486
+ downloadBtn.className = "blex-image__btn";
487
+ downloadBtn.textContent = "Download";
488
+ downloadBtn.setAttribute("data-testid", `blex-image-download-${block.id}`);
489
+ this.addListener(downloadBtn, "click", () => {
490
+ const a = document.createElement("a");
491
+ a.href = src;
492
+ a.download = alt ?? "image";
493
+ a.click();
494
+ });
495
+ actions.appendChild(downloadBtn);
496
+ wrapper.appendChild(actions);
497
+ container.appendChild(wrapper);
498
+ }
499
+ _openOverlay(src, alt) {
500
+ const overlay = document.createElement("div");
501
+ overlay.className = "blex-image__overlay";
502
+ const img = document.createElement("img");
503
+ img.src = src;
504
+ img.alt = alt ?? "";
505
+ overlay.appendChild(img);
506
+ const closeOverlay = () => {
507
+ overlay.remove();
508
+ document.removeEventListener("keydown", onKeyDown);
509
+ };
510
+ const onKeyDown = (e) => {
511
+ if (e.key === "Escape") closeOverlay();
512
+ };
513
+ this.addListener(overlay, "click", closeOverlay);
514
+ document.addEventListener("keydown", onKeyDown);
515
+ document.body.appendChild(overlay);
516
+ }
517
+ };
518
+ function createImageRenderer() {
519
+ return new ImageRenderer();
520
+ }
521
+ var SvgRenderer = class extends BaseRenderer {
522
+ render(block, container) {
523
+ this.container = container;
524
+ this.renderContent(block);
525
+ }
526
+ update(block) {
527
+ if (!this.container) return;
528
+ this.container.innerHTML = "";
529
+ this.renderContent(block);
530
+ }
531
+ renderContent(block) {
532
+ const container = this.container;
533
+ const { svg, title } = block.data;
534
+ const wrapper = document.createElement("div");
535
+ wrapper.className = "blex-svg";
536
+ wrapper.setAttribute("data-testid", `blex-svg-${block.id}`);
537
+ if (title) {
538
+ const titleEl = document.createElement("div");
539
+ titleEl.className = "blex-svg__title";
540
+ titleEl.textContent = title;
541
+ wrapper.appendChild(titleEl);
542
+ }
543
+ const svgContainer = document.createElement("div");
544
+ svgContainer.className = "blex-svg__content";
545
+ svgContainer.setAttribute("data-testid", `blex-svg-content-${block.id}`);
546
+ svgContainer.innerHTML = DOMPurify.sanitize(svg, { USE_PROFILES: { svg: true } });
547
+ wrapper.appendChild(svgContainer);
548
+ const actions = document.createElement("div");
549
+ actions.className = "blex-svg__actions";
550
+ const downloadBtn = document.createElement("button");
551
+ downloadBtn.className = "blex-svg__btn";
552
+ downloadBtn.textContent = "Download SVG";
553
+ downloadBtn.setAttribute("data-testid", `blex-svg-download-${block.id}`);
554
+ this.addListener(downloadBtn, "click", () => {
555
+ const blob = new Blob([svg], { type: "image/svg+xml" });
556
+ const url = URL.createObjectURL(blob);
557
+ const a = document.createElement("a");
558
+ a.href = url;
559
+ a.download = `${title ?? "image"}.svg`;
560
+ a.click();
561
+ URL.revokeObjectURL(url);
562
+ this.emit({
563
+ blockId: block.id,
564
+ type: "click",
565
+ payload: { action: "download" },
566
+ serialized: `Downloaded SVG${title ? `: ${title}` : ""}`
567
+ });
568
+ });
569
+ actions.appendChild(downloadBtn);
570
+ const copyBtn = document.createElement("button");
571
+ copyBtn.className = "blex-svg__btn";
572
+ copyBtn.textContent = "Copy SVG";
573
+ copyBtn.setAttribute("data-testid", `blex-svg-copy-${block.id}`);
574
+ this.addListener(copyBtn, "click", () => {
575
+ navigator.clipboard?.writeText(svg);
576
+ this.emit({
577
+ blockId: block.id,
578
+ type: "click",
579
+ payload: { action: "copy" },
580
+ serialized: `Copied SVG${title ? `: ${title}` : ""}`
581
+ });
582
+ });
583
+ actions.appendChild(copyBtn);
584
+ wrapper.appendChild(actions);
585
+ container.appendChild(wrapper);
586
+ container.setAttribute("data-blex-ready", "true");
587
+ }
588
+ };
589
+ function createSvgRenderer() {
590
+ return new SvgRenderer();
591
+ }
592
+
593
+ // src/renderers/table.ts
594
+ var TableRenderer = class extends BaseRenderer {
595
+ constructor() {
596
+ super(...arguments);
597
+ this.selectedRows = /* @__PURE__ */ new Set();
598
+ this.sortColumn = null;
599
+ this.sortDirection = "asc";
600
+ this.currentBlock = null;
601
+ }
602
+ render(block, container) {
603
+ this.container = container;
604
+ this.currentBlock = block;
605
+ this._build(block);
606
+ container.setAttribute("data-blex-ready", "true");
607
+ }
608
+ update(block) {
609
+ if (!this.container) return;
610
+ this.currentBlock = block;
611
+ this.selectedRows.clear();
612
+ this.sortColumn = null;
613
+ this.sortDirection = "asc";
614
+ this.container.innerHTML = "";
615
+ this._build(block);
616
+ }
617
+ _getSortedRows(rows) {
618
+ const indexed = rows.map((row, i) => ({ row, originalIndex: i }));
619
+ if (!this.sortColumn) return indexed;
620
+ const col = this.sortColumn;
621
+ const dir = this.sortDirection;
622
+ return indexed.slice().sort((a, b) => {
623
+ const av = a.row[col] ?? "";
624
+ const bv = b.row[col] ?? "";
625
+ let cmp;
626
+ if (typeof av === "number" && typeof bv === "number") {
627
+ cmp = av - bv;
628
+ } else {
629
+ cmp = String(av).localeCompare(String(bv));
630
+ }
631
+ return dir === "asc" ? cmp : -cmp;
632
+ });
633
+ }
634
+ _build(block) {
635
+ const container = this.container;
636
+ const { columns, rows, sortable } = block.data;
637
+ const wrapper = document.createElement("div");
638
+ wrapper.className = "blex-table";
639
+ wrapper.setAttribute("data-testid", `blex-table-${block.id}`);
640
+ const table = document.createElement("table");
641
+ const thead = document.createElement("thead");
642
+ const headerRow = document.createElement("tr");
643
+ headerRow.className = "blex-table__header";
644
+ for (const col of columns) {
645
+ const th = document.createElement("th");
646
+ th.className = "blex-table__header-cell";
647
+ th.setAttribute("data-testid", `blex-table-header-${col}`);
648
+ th.textContent = col;
649
+ if (this.sortColumn === col) {
650
+ th.classList.add(
651
+ this.sortDirection === "asc" ? "blex-table__header-cell--sorted-asc" : "blex-table__header-cell--sorted-desc"
652
+ );
653
+ }
654
+ if (sortable) {
655
+ this.addListener(th, "click", () => {
656
+ if (this.sortColumn === col) {
657
+ this.sortDirection = this.sortDirection === "asc" ? "desc" : "asc";
658
+ } else {
659
+ this.sortColumn = col;
660
+ this.sortDirection = "asc";
661
+ }
662
+ container.innerHTML = "";
663
+ this._build(this.currentBlock);
664
+ });
665
+ }
666
+ headerRow.appendChild(th);
667
+ }
668
+ thead.appendChild(headerRow);
669
+ table.appendChild(thead);
670
+ const tbody = document.createElement("tbody");
671
+ const sortedRows = this._getSortedRows(rows);
672
+ for (const { row, originalIndex } of sortedRows) {
673
+ const tr = document.createElement("tr");
674
+ tr.className = "blex-table__row";
675
+ tr.setAttribute("data-testid", `blex-table-row-${originalIndex}`);
676
+ if (this.selectedRows.has(originalIndex)) {
677
+ tr.classList.add("blex-table__row--selected");
678
+ }
679
+ this.addListener(tr, "click", () => {
680
+ if (this.selectedRows.has(originalIndex)) {
681
+ this.selectedRows.delete(originalIndex);
682
+ tr.classList.remove("blex-table__row--selected");
683
+ } else {
684
+ this.selectedRows.add(originalIndex);
685
+ tr.classList.add("blex-table__row--selected");
686
+ }
687
+ this._emitSelection(block);
688
+ });
689
+ for (const col of columns) {
690
+ const td = document.createElement("td");
691
+ td.className = "blex-table__cell";
692
+ td.setAttribute("data-testid", `blex-table-cell-${originalIndex}-${col}`);
693
+ td.textContent = String(row[col] ?? "");
694
+ tr.appendChild(td);
695
+ }
696
+ tbody.appendChild(tr);
697
+ }
698
+ table.appendChild(tbody);
699
+ wrapper.appendChild(table);
700
+ container.appendChild(wrapper);
701
+ }
702
+ _emitSelection(block) {
703
+ const { columns, rows } = block.data;
704
+ const selectedIndices = Array.from(this.selectedRows).sort((a, b) => a - b);
705
+ const selectedRows = selectedIndices.map((i) => rows[i]);
706
+ const headerLine = `| ${columns.join(" | ")} |`;
707
+ const separatorLine = `| ${columns.map(() => "---").join(" | ")} |`;
708
+ const dataLines = selectedRows.map(
709
+ (row) => `| ${columns.map((col) => String(row[col] ?? "")).join(" | ")} |`
710
+ );
711
+ const serialized = [
712
+ "Selected from table:",
713
+ headerLine,
714
+ separatorLine,
715
+ ...dataLines
716
+ ].join("\n");
717
+ this.emit({
718
+ blockId: block.id,
719
+ type: "select",
720
+ payload: {
721
+ selectedRows: selectedIndices,
722
+ columns
723
+ },
724
+ serialized
725
+ });
726
+ }
727
+ };
728
+ function createTableRenderer() {
729
+ return new TableRenderer();
730
+ }
731
+
732
+ // src/renderers/code.ts
733
+ var CodeRenderer = class extends BaseRenderer {
734
+ constructor() {
735
+ super(...arguments);
736
+ this.selectedLines = /* @__PURE__ */ new Set();
737
+ this.lastClickedLine = null;
738
+ }
739
+ render(block, container) {
740
+ this.container = container;
741
+ this._build(block);
742
+ container.setAttribute("data-blex-ready", "true");
743
+ }
744
+ update(block) {
745
+ if (!this.container) return;
746
+ const lines = block.data.code.split("\n");
747
+ for (const lineNum of Array.from(this.selectedLines)) {
748
+ if (lineNum > lines.length) this.selectedLines.delete(lineNum);
749
+ }
750
+ this.container.innerHTML = "";
751
+ this._build(block);
752
+ }
753
+ _build(block) {
754
+ const container = this.container;
755
+ const { code, language, highlightLines = [] } = block.data;
756
+ const lineNumbersEnabled = block.data.lineNumbers !== false;
757
+ const lines = code.split("\n");
758
+ const pre = document.createElement("pre");
759
+ pre.className = "blex-code";
760
+ if (language) pre.setAttribute("data-language", language);
761
+ pre.setAttribute("data-testid", `blex-code-${block.id}`);
762
+ const copyBtn = document.createElement("button");
763
+ copyBtn.className = "blex-code__copy";
764
+ copyBtn.setAttribute("data-testid", `blex-code-copy-${block.id}`);
765
+ copyBtn.textContent = "Copy";
766
+ this.addListener(copyBtn, "click", () => {
767
+ navigator.clipboard.writeText(code);
768
+ });
769
+ pre.appendChild(copyBtn);
770
+ let gutter = null;
771
+ if (lineNumbersEnabled) {
772
+ gutter = document.createElement("div");
773
+ gutter.className = "blex-code__gutter";
774
+ pre.appendChild(gutter);
775
+ }
776
+ const codeEl = document.createElement("code");
777
+ codeEl.className = "blex-code__content";
778
+ if (language) codeEl.className += ` language-${language}`;
779
+ lines.forEach((lineText, i) => {
780
+ const lineNum = i + 1;
781
+ if (lineNumbersEnabled && gutter) {
782
+ const lineNumberEl = document.createElement("span");
783
+ lineNumberEl.className = "blex-code__line-number";
784
+ lineNumberEl.textContent = String(lineNum);
785
+ this.addListener(lineNumberEl, "click", (e) => {
786
+ const mouseEvent = e;
787
+ if (mouseEvent.shiftKey && this.lastClickedLine !== null) {
788
+ const start = Math.min(this.lastClickedLine, lineNum);
789
+ const end = Math.max(this.lastClickedLine, lineNum);
790
+ for (let l = start; l <= end; l++) {
791
+ this.selectedLines.add(l);
792
+ }
793
+ } else {
794
+ if (this.selectedLines.has(lineNum)) {
795
+ this.selectedLines.delete(lineNum);
796
+ } else {
797
+ this.selectedLines.add(lineNum);
798
+ }
799
+ this.lastClickedLine = lineNum;
800
+ }
801
+ this._updateSelectionClasses(codeEl, lines.length);
802
+ this._emitSelection(block, lines);
803
+ });
804
+ gutter.appendChild(lineNumberEl);
805
+ }
806
+ const lineEl = document.createElement("div");
807
+ lineEl.className = "blex-code__line";
808
+ lineEl.setAttribute("data-testid", `blex-code-line-${lineNum}`);
809
+ lineEl.textContent = lineText;
810
+ if (highlightLines.includes(lineNum)) {
811
+ lineEl.classList.add("blex-code__line--highlighted");
812
+ }
813
+ if (this.selectedLines.has(lineNum)) {
814
+ lineEl.classList.add("blex-code__line--selected");
815
+ }
816
+ codeEl.appendChild(lineEl);
817
+ });
818
+ pre.appendChild(codeEl);
819
+ container.appendChild(pre);
820
+ }
821
+ _updateSelectionClasses(codeEl, totalLines) {
822
+ for (let lineNum = 1; lineNum <= totalLines; lineNum++) {
823
+ const lineEl = codeEl.querySelector(`[data-testid="blex-code-line-${lineNum}"]`);
824
+ if (!lineEl) continue;
825
+ if (this.selectedLines.has(lineNum)) {
826
+ lineEl.classList.add("blex-code__line--selected");
827
+ } else {
828
+ lineEl.classList.remove("blex-code__line--selected");
829
+ }
830
+ }
831
+ }
832
+ _emitSelection(block, lines) {
833
+ const { language } = block.data;
834
+ const sortedLines = Array.from(this.selectedLines).sort((a, b) => a - b);
835
+ const selectedCode = sortedLines.map((lineNum) => lines[lineNum - 1]).join("\n");
836
+ const langTag = language ?? "";
837
+ const serialized = `\`\`\`${langTag}
838
+ ${selectedCode}
839
+ \`\`\``;
840
+ this.emit({
841
+ blockId: block.id,
842
+ type: "select",
843
+ payload: {
844
+ lines: sortedLines,
845
+ ...language !== void 0 && { language }
846
+ },
847
+ serialized
848
+ });
849
+ }
850
+ };
851
+ function createCodeRenderer() {
852
+ return new CodeRenderer();
853
+ }
854
+
855
+ // src/renderers/diff.ts
856
+ var DiffRenderer = class extends BaseRenderer {
857
+ constructor() {
858
+ super(...arguments);
859
+ this.viewMode = "unified";
860
+ this.selectedHunks = /* @__PURE__ */ new Set();
861
+ }
862
+ render(block, container) {
863
+ this.container = container;
864
+ this._build(block);
865
+ container.setAttribute("data-blex-ready", "true");
866
+ }
867
+ update(block) {
868
+ if (!this.container) return;
869
+ this.container.innerHTML = "";
870
+ this._build(block);
871
+ }
872
+ _build(block) {
873
+ const container = this.container;
874
+ const { hunks, filename } = block.data;
875
+ const wrapper = document.createElement("div");
876
+ wrapper.className = `blex-diff blex-diff--${this.viewMode}`;
877
+ wrapper.setAttribute("data-testid", `blex-diff-${block.id}`);
878
+ const header = document.createElement("div");
879
+ header.className = "blex-diff__header";
880
+ if (filename) {
881
+ header.textContent = filename;
882
+ }
883
+ wrapper.appendChild(header);
884
+ const hunksContainer = document.createElement("div");
885
+ hunksContainer.className = "blex-diff__hunks";
886
+ hunks.forEach((hunk, index) => {
887
+ const hunkEl = document.createElement("div");
888
+ hunkEl.className = "blex-diff__hunk";
889
+ if (this.selectedHunks.has(index)) {
890
+ hunkEl.classList.add("blex-diff__hunk--selected");
891
+ }
892
+ const hunkHeader = document.createElement("div");
893
+ hunkHeader.className = "blex-diff__hunk-header";
894
+ hunkHeader.setAttribute("data-testid", `blex-diff-hunk-${index}`);
895
+ hunkHeader.textContent = hunk.header;
896
+ this.addListener(hunkHeader, "click", () => {
897
+ if (this.selectedHunks.has(index)) {
898
+ this.selectedHunks.delete(index);
899
+ hunkEl.classList.remove("blex-diff__hunk--selected");
900
+ } else {
901
+ this.selectedHunks.add(index);
902
+ hunkEl.classList.add("blex-diff__hunk--selected");
903
+ }
904
+ });
905
+ hunkEl.appendChild(hunkHeader);
906
+ for (const line of hunk.lines) {
907
+ const lineEl = document.createElement("div");
908
+ lineEl.className = `blex-diff__line blex-diff__line--${line.type}`;
909
+ lineEl.textContent = line.content;
910
+ hunkEl.appendChild(lineEl);
911
+ }
912
+ hunksContainer.appendChild(hunkEl);
913
+ });
914
+ wrapper.appendChild(hunksContainer);
915
+ const actions = document.createElement("div");
916
+ actions.className = "blex-diff__actions";
917
+ const toggleBtn = document.createElement("button");
918
+ toggleBtn.className = "blex-diff__toggle";
919
+ toggleBtn.setAttribute("data-testid", `blex-diff-toggle-${block.id}`);
920
+ toggleBtn.textContent = this.viewMode === "unified" ? "Side by side" : "Unified";
921
+ this.addListener(toggleBtn, "click", () => {
922
+ this.viewMode = this.viewMode === "unified" ? "side-by-side" : "unified";
923
+ wrapper.className = `blex-diff blex-diff--${this.viewMode}`;
924
+ toggleBtn.textContent = this.viewMode === "unified" ? "Side by side" : "Unified";
925
+ });
926
+ actions.appendChild(toggleBtn);
927
+ const applyBtn = document.createElement("button");
928
+ applyBtn.className = "blex-diff__apply";
929
+ applyBtn.setAttribute("data-testid", `blex-diff-apply-${block.id}`);
930
+ applyBtn.textContent = "Apply";
931
+ this.addListener(applyBtn, "click", () => {
932
+ this.emit({
933
+ blockId: block.id,
934
+ type: "apply",
935
+ payload: { hunks },
936
+ serialized: `Applied diff to ${filename ?? "file"}`
937
+ });
938
+ });
939
+ actions.appendChild(applyBtn);
940
+ const rejectBtn = document.createElement("button");
941
+ rejectBtn.className = "blex-diff__reject";
942
+ rejectBtn.setAttribute("data-testid", `blex-diff-reject-${block.id}`);
943
+ rejectBtn.textContent = "Reject";
944
+ this.addListener(rejectBtn, "click", () => {
945
+ this.emit({
946
+ blockId: block.id,
947
+ type: "reject",
948
+ payload: { hunks },
949
+ serialized: `Rejected diff to ${filename ?? "file"}`
950
+ });
951
+ });
952
+ actions.appendChild(rejectBtn);
953
+ wrapper.appendChild(actions);
954
+ container.appendChild(wrapper);
955
+ }
956
+ };
957
+ function createDiffRenderer() {
958
+ return new DiffRenderer();
959
+ }
960
+
961
+ // src/renderers/file-tree.ts
962
+ var FileTreeRenderer = class extends BaseRenderer {
963
+ constructor() {
964
+ super(...arguments);
965
+ this.expandedPaths = /* @__PURE__ */ new Set();
966
+ this.selectedPaths = /* @__PURE__ */ new Set();
967
+ }
968
+ render(block, container) {
969
+ this.container = container;
970
+ if (block.data.expanded) {
971
+ for (const p of block.data.expanded) this.expandedPaths.add(p);
972
+ }
973
+ this.buildTree(block);
974
+ container.setAttribute("data-blex-ready", "true");
975
+ }
976
+ update(block) {
977
+ if (!this.container) return;
978
+ this.container.innerHTML = "";
979
+ this.buildTree(block);
980
+ }
981
+ buildTree(block) {
982
+ const container = this.container;
983
+ const wrapper = document.createElement("div");
984
+ wrapper.className = "blex-file-tree";
985
+ wrapper.setAttribute("data-testid", `blex-file-tree-${block.id}`);
986
+ const ul = this.buildNode(block.data.root, "", block);
987
+ wrapper.appendChild(ul);
988
+ container.appendChild(wrapper);
989
+ }
990
+ buildNode(node, parentPath, block) {
991
+ const path = parentPath ? `${parentPath}/${node.name}` : node.name;
992
+ const li = document.createElement("div");
993
+ li.className = `blex-file-tree__node blex-file-tree__node--${node.type}`;
994
+ li.setAttribute("data-testid", `blex-file-tree-node-${path.replace(/\//g, "-")}`);
995
+ if (this.selectedPaths.has(path)) {
996
+ li.classList.add("blex-file-tree__node--selected");
997
+ }
998
+ const label = document.createElement("span");
999
+ label.className = "blex-file-tree__label";
1000
+ label.textContent = node.name;
1001
+ if (node.type === "directory") {
1002
+ const isExpanded = this.expandedPaths.has(path);
1003
+ const toggle = document.createElement("span");
1004
+ toggle.className = "blex-file-tree__toggle";
1005
+ toggle.textContent = isExpanded ? "\u25BC" : "\u25B6";
1006
+ this.addListener(toggle, "click", (e) => {
1007
+ e.stopPropagation();
1008
+ if (this.expandedPaths.has(path)) {
1009
+ this.expandedPaths.delete(path);
1010
+ } else {
1011
+ this.expandedPaths.add(path);
1012
+ }
1013
+ this.container.innerHTML = "";
1014
+ this.buildTree(block);
1015
+ });
1016
+ li.appendChild(toggle);
1017
+ li.appendChild(label);
1018
+ if (isExpanded && node.children) {
1019
+ const childContainer = document.createElement("div");
1020
+ childContainer.className = "blex-file-tree__children";
1021
+ for (const child of node.children) {
1022
+ childContainer.appendChild(this.buildNode(child, path, block));
1023
+ }
1024
+ li.appendChild(childContainer);
1025
+ }
1026
+ } else {
1027
+ li.appendChild(label);
1028
+ if (node.size !== void 0) {
1029
+ const sizeEl = document.createElement("span");
1030
+ sizeEl.className = "blex-file-tree__size";
1031
+ sizeEl.textContent = this.formatSize(node.size);
1032
+ li.appendChild(sizeEl);
1033
+ }
1034
+ }
1035
+ this.addListener(label, "click", () => {
1036
+ if (this.selectedPaths.has(path)) {
1037
+ this.selectedPaths.delete(path);
1038
+ li.classList.remove("blex-file-tree__node--selected");
1039
+ } else {
1040
+ this.selectedPaths.add(path);
1041
+ li.classList.add("blex-file-tree__node--selected");
1042
+ }
1043
+ this.emitSelection(block);
1044
+ });
1045
+ return li;
1046
+ }
1047
+ emitSelection(block) {
1048
+ const paths = Array.from(this.selectedPaths).sort();
1049
+ this.emit({
1050
+ blockId: block.id,
1051
+ type: "select",
1052
+ payload: { paths },
1053
+ serialized: `Selected files:
1054
+ ${paths.join("\n")}`
1055
+ });
1056
+ }
1057
+ formatSize(bytes) {
1058
+ if (bytes < 1024) return `${bytes}B`;
1059
+ if (bytes < 1048576) return `${(bytes / 1024).toFixed(1)}KB`;
1060
+ return `${(bytes / 1048576).toFixed(1)}MB`;
1061
+ }
1062
+ };
1063
+ function createFileTreeRenderer() {
1064
+ return new FileTreeRenderer();
1065
+ }
1066
+
1067
+ // src/renderers/form.ts
1068
+ var FormRenderer = class extends BaseRenderer {
1069
+ constructor() {
1070
+ super(...arguments);
1071
+ this.values = {};
1072
+ this.errors = {};
1073
+ }
1074
+ render(block, container) {
1075
+ this.container = container;
1076
+ for (const field of block.data.fields) {
1077
+ if (field.defaultValue !== void 0) {
1078
+ this.values[field.name] = field.defaultValue;
1079
+ }
1080
+ }
1081
+ this.buildForm(block);
1082
+ container.setAttribute("data-blex-ready", "true");
1083
+ }
1084
+ update(block) {
1085
+ if (!this.container) return;
1086
+ this.container.innerHTML = "";
1087
+ this.buildForm(block);
1088
+ }
1089
+ buildForm(block) {
1090
+ const container = this.container;
1091
+ const { title, fields, submitLabel } = block.data;
1092
+ const form = document.createElement("form");
1093
+ form.className = "blex-form";
1094
+ form.setAttribute("data-testid", `blex-form-${block.id}`);
1095
+ this.addListener(form, "submit", (e) => {
1096
+ e.preventDefault();
1097
+ if (this.validate(fields)) {
1098
+ const serializedPairs = Object.entries(this.values).map(([k, v]) => `${k}: ${v}`).join("\n");
1099
+ this.emit({
1100
+ blockId: block.id,
1101
+ type: "submit",
1102
+ payload: { ...this.values },
1103
+ serialized: `Form submission${title ? ` (${title})` : ""}:
1104
+ ${serializedPairs}`
1105
+ });
1106
+ } else {
1107
+ this.container.innerHTML = "";
1108
+ this.buildForm(block);
1109
+ }
1110
+ });
1111
+ if (title) {
1112
+ const titleEl = document.createElement("div");
1113
+ titleEl.className = "blex-form__title";
1114
+ titleEl.textContent = title;
1115
+ form.appendChild(titleEl);
1116
+ }
1117
+ for (const field of fields) {
1118
+ const group = document.createElement("div");
1119
+ group.className = "blex-form__field";
1120
+ const label = document.createElement("label");
1121
+ label.className = "blex-form__label";
1122
+ label.textContent = field.label + (field.required ? " *" : "");
1123
+ group.appendChild(label);
1124
+ const input = this.createInput(field);
1125
+ group.appendChild(input);
1126
+ if (this.errors[field.name]) {
1127
+ const error = document.createElement("span");
1128
+ error.className = "blex-form__error";
1129
+ error.textContent = this.errors[field.name];
1130
+ group.appendChild(error);
1131
+ }
1132
+ form.appendChild(group);
1133
+ }
1134
+ const submit = document.createElement("button");
1135
+ submit.type = "submit";
1136
+ submit.className = "blex-form__submit";
1137
+ submit.textContent = submitLabel ?? "Submit";
1138
+ submit.setAttribute("data-testid", `blex-form-submit-${block.id}`);
1139
+ form.appendChild(submit);
1140
+ container.appendChild(form);
1141
+ }
1142
+ createInput(field) {
1143
+ const testId = `blex-form-field-${field.name}`;
1144
+ if (field.type === "textarea") {
1145
+ const textarea = document.createElement("textarea");
1146
+ textarea.className = "blex-form__input";
1147
+ textarea.name = field.name;
1148
+ textarea.placeholder = field.placeholder ?? "";
1149
+ textarea.required = field.required ?? false;
1150
+ textarea.value = String(this.values[field.name] ?? "");
1151
+ textarea.setAttribute("data-testid", testId);
1152
+ this.addListener(textarea, "input", () => {
1153
+ this.values[field.name] = textarea.value;
1154
+ });
1155
+ return textarea;
1156
+ }
1157
+ if (field.type === "select") {
1158
+ const select = document.createElement("select");
1159
+ select.className = "blex-form__input";
1160
+ select.name = field.name;
1161
+ select.required = field.required ?? false;
1162
+ select.setAttribute("data-testid", testId);
1163
+ const emptyOpt = document.createElement("option");
1164
+ emptyOpt.value = "";
1165
+ emptyOpt.textContent = field.placeholder ?? "Select...";
1166
+ select.appendChild(emptyOpt);
1167
+ for (const opt of field.options ?? []) {
1168
+ const optEl = document.createElement("option");
1169
+ optEl.value = opt;
1170
+ optEl.textContent = opt;
1171
+ if (this.values[field.name] === opt) optEl.selected = true;
1172
+ select.appendChild(optEl);
1173
+ }
1174
+ this.addListener(select, "change", () => {
1175
+ this.values[field.name] = select.value;
1176
+ });
1177
+ return select;
1178
+ }
1179
+ if (field.type === "checkbox") {
1180
+ const input2 = document.createElement("input");
1181
+ input2.type = "checkbox";
1182
+ input2.className = "blex-form__checkbox";
1183
+ input2.name = field.name;
1184
+ input2.checked = Boolean(this.values[field.name]);
1185
+ input2.setAttribute("data-testid", testId);
1186
+ this.addListener(input2, "change", () => {
1187
+ this.values[field.name] = input2.checked;
1188
+ });
1189
+ return input2;
1190
+ }
1191
+ const input = document.createElement("input");
1192
+ input.type = field.type;
1193
+ input.className = "blex-form__input";
1194
+ input.name = field.name;
1195
+ input.placeholder = field.placeholder ?? "";
1196
+ input.required = field.required ?? false;
1197
+ input.value = String(this.values[field.name] ?? "");
1198
+ input.setAttribute("data-testid", testId);
1199
+ this.addListener(input, "input", () => {
1200
+ this.values[field.name] = field.type === "number" ? Number(input.value) : input.value;
1201
+ });
1202
+ return input;
1203
+ }
1204
+ validate(fields) {
1205
+ this.errors = {};
1206
+ let valid = true;
1207
+ for (const field of fields) {
1208
+ if (field.required) {
1209
+ const val = this.values[field.name];
1210
+ if (val === void 0 || val === "" || val === null) {
1211
+ this.errors[field.name] = `${field.label} is required`;
1212
+ valid = false;
1213
+ }
1214
+ }
1215
+ }
1216
+ return valid;
1217
+ }
1218
+ };
1219
+ function createFormRenderer() {
1220
+ return new FormRenderer();
1221
+ }
1222
+
1223
+ // src/renderers/progress.ts
1224
+ var ProgressRenderer = class extends BaseRenderer {
1225
+ render(block, container) {
1226
+ this.container = container;
1227
+ this.renderContent(block);
1228
+ }
1229
+ update(block) {
1230
+ if (!this.container) return;
1231
+ this.container.innerHTML = "";
1232
+ this.renderContent(block);
1233
+ }
1234
+ renderContent(block) {
1235
+ const container = this.container;
1236
+ const { title, steps } = block.data;
1237
+ const wrapper = document.createElement("div");
1238
+ wrapper.className = "blex-progress";
1239
+ wrapper.setAttribute("data-testid", `blex-progress-${block.id}`);
1240
+ if (title) {
1241
+ const titleEl = document.createElement("div");
1242
+ titleEl.className = "blex-progress__title";
1243
+ titleEl.textContent = title;
1244
+ wrapper.appendChild(titleEl);
1245
+ }
1246
+ const stepsEl = document.createElement("div");
1247
+ stepsEl.className = "blex-progress__steps";
1248
+ steps.forEach((step, i) => {
1249
+ const stepEl = document.createElement("div");
1250
+ stepEl.className = `blex-progress__step blex-progress__step--${step.status}`;
1251
+ stepEl.setAttribute("data-testid", `blex-progress-step-${i}`);
1252
+ const indicator = document.createElement("span");
1253
+ indicator.className = "blex-progress__indicator";
1254
+ if (step.status === "completed") {
1255
+ indicator.textContent = "\u2713";
1256
+ } else if (step.status === "active") {
1257
+ indicator.textContent = "\u25CF";
1258
+ } else {
1259
+ indicator.textContent = "\u25CB";
1260
+ }
1261
+ stepEl.appendChild(indicator);
1262
+ const content = document.createElement("div");
1263
+ content.className = "blex-progress__content";
1264
+ const labelEl = document.createElement("span");
1265
+ labelEl.className = "blex-progress__label";
1266
+ labelEl.textContent = step.label;
1267
+ content.appendChild(labelEl);
1268
+ if (step.description) {
1269
+ const desc = document.createElement("span");
1270
+ desc.className = "blex-progress__description";
1271
+ desc.textContent = step.description;
1272
+ content.appendChild(desc);
1273
+ }
1274
+ stepEl.appendChild(content);
1275
+ stepsEl.appendChild(stepEl);
1276
+ });
1277
+ wrapper.appendChild(stepsEl);
1278
+ container.appendChild(wrapper);
1279
+ container.setAttribute("data-blex-ready", "true");
1280
+ }
1281
+ };
1282
+ function createProgressRenderer() {
1283
+ return new ProgressRenderer();
1284
+ }
1285
+
1286
+ // src/renderers/terminal.ts
1287
+ var ANSI_COLORS = {
1288
+ "30": "color: #1a1a1a",
1289
+ "31": "color: #ef4444",
1290
+ "32": "color: #22c55e",
1291
+ "33": "color: #f59e0b",
1292
+ "34": "color: #3b82f6",
1293
+ "35": "color: #a855f7",
1294
+ "36": "color: #06b6d4",
1295
+ "37": "color: #e5e5e5",
1296
+ "1": "font-weight: bold",
1297
+ "0": ""
1298
+ };
1299
+ var TerminalRenderer = class extends BaseRenderer {
1300
+ render(block, container) {
1301
+ this.container = container;
1302
+ this.renderContent(block);
1303
+ }
1304
+ update(block) {
1305
+ if (!this.container) return;
1306
+ this.container.innerHTML = "";
1307
+ this.renderContent(block);
1308
+ }
1309
+ renderContent(block) {
1310
+ const container = this.container;
1311
+ const { command, output, exitCode, collapsed } = block.data;
1312
+ const wrapper = document.createElement("div");
1313
+ wrapper.className = "blex-terminal";
1314
+ wrapper.setAttribute("data-testid", `blex-terminal-${block.id}`);
1315
+ if (exitCode !== void 0) {
1316
+ wrapper.setAttribute("data-exit-code", String(exitCode));
1317
+ }
1318
+ if (command) {
1319
+ const cmdEl = document.createElement("div");
1320
+ cmdEl.className = "blex-terminal__command";
1321
+ cmdEl.setAttribute("data-testid", `blex-terminal-command-${block.id}`);
1322
+ const prompt = document.createElement("span");
1323
+ prompt.className = "blex-terminal__prompt";
1324
+ prompt.textContent = "$ ";
1325
+ cmdEl.appendChild(prompt);
1326
+ const cmdText = document.createElement("span");
1327
+ cmdText.textContent = command;
1328
+ cmdEl.appendChild(cmdText);
1329
+ wrapper.appendChild(cmdEl);
1330
+ }
1331
+ const outputEl = document.createElement("pre");
1332
+ outputEl.className = "blex-terminal__output";
1333
+ outputEl.setAttribute("data-testid", `blex-terminal-output-${block.id}`);
1334
+ outputEl.innerHTML = this.parseAnsi(output);
1335
+ if (collapsed) {
1336
+ outputEl.style.display = "none";
1337
+ const toggleBtn = document.createElement("button");
1338
+ toggleBtn.className = "blex-terminal__toggle";
1339
+ toggleBtn.textContent = "Show output";
1340
+ toggleBtn.setAttribute("data-testid", `blex-terminal-toggle-${block.id}`);
1341
+ this.addListener(toggleBtn, "click", () => {
1342
+ const isHidden = outputEl.style.display === "none";
1343
+ outputEl.style.display = isHidden ? "block" : "none";
1344
+ toggleBtn.textContent = isHidden ? "Hide output" : "Show output";
1345
+ });
1346
+ wrapper.appendChild(toggleBtn);
1347
+ }
1348
+ wrapper.appendChild(outputEl);
1349
+ if (exitCode !== void 0) {
1350
+ const badge = document.createElement("span");
1351
+ badge.className = `blex-terminal__exit-code blex-terminal__exit-code--${exitCode === 0 ? "success" : "error"}`;
1352
+ badge.textContent = `exit ${exitCode}`;
1353
+ badge.setAttribute("data-testid", `blex-terminal-exit-${block.id}`);
1354
+ wrapper.appendChild(badge);
1355
+ }
1356
+ const copyBtn = document.createElement("button");
1357
+ copyBtn.className = "blex-terminal__copy";
1358
+ copyBtn.textContent = "Copy";
1359
+ copyBtn.setAttribute("data-testid", `blex-terminal-copy-${block.id}`);
1360
+ this.addListener(copyBtn, "click", () => {
1361
+ navigator.clipboard?.writeText(output);
1362
+ this.emit({
1363
+ blockId: block.id,
1364
+ type: "click",
1365
+ payload: { action: "copy" },
1366
+ serialized: `Copied terminal output${command ? ` from: ${command}` : ""}`
1367
+ });
1368
+ });
1369
+ wrapper.appendChild(copyBtn);
1370
+ container.appendChild(wrapper);
1371
+ container.setAttribute("data-blex-ready", "true");
1372
+ }
1373
+ parseAnsi(text) {
1374
+ return text.replace(/\x1b\[([0-9;]*)m/g, (_match, codes) => {
1375
+ if (codes === "0" || codes === "") return "</span>";
1376
+ const styles = codes.split(";").map((c) => ANSI_COLORS[c] || "").filter(Boolean).join("; ");
1377
+ return styles ? `<span style="${styles}">` : "";
1378
+ });
1379
+ }
1380
+ };
1381
+ function createTerminalRenderer() {
1382
+ return new TerminalRenderer();
1383
+ }
1384
+
1385
+ // src/renderers/timeline.ts
1386
+ var TimelineRenderer = class extends BaseRenderer {
1387
+ render(block, container) {
1388
+ this.container = container;
1389
+ this.renderContent(block);
1390
+ }
1391
+ update(block) {
1392
+ if (!this.container) return;
1393
+ this.container.innerHTML = "";
1394
+ this.renderContent(block);
1395
+ }
1396
+ renderContent(block) {
1397
+ const container = this.container;
1398
+ const { events, title } = block.data;
1399
+ const wrapper = document.createElement("div");
1400
+ wrapper.className = "blex-timeline";
1401
+ wrapper.setAttribute("data-testid", `blex-timeline-${block.id}`);
1402
+ if (title) {
1403
+ const titleEl = document.createElement("div");
1404
+ titleEl.className = "blex-timeline__title";
1405
+ titleEl.textContent = title;
1406
+ wrapper.appendChild(titleEl);
1407
+ }
1408
+ const list = document.createElement("div");
1409
+ list.className = "blex-timeline__list";
1410
+ events.forEach((event, i) => {
1411
+ const item = document.createElement("div");
1412
+ item.className = "blex-timeline__item";
1413
+ item.setAttribute("data-testid", `blex-timeline-item-${i}`);
1414
+ const dot = document.createElement("span");
1415
+ dot.className = "blex-timeline__dot";
1416
+ if (event.color) {
1417
+ dot.style.backgroundColor = event.color;
1418
+ }
1419
+ if (event.icon) {
1420
+ dot.textContent = event.icon;
1421
+ }
1422
+ item.appendChild(dot);
1423
+ const content = document.createElement("div");
1424
+ content.className = "blex-timeline__content";
1425
+ const time = document.createElement("time");
1426
+ time.className = "blex-timeline__time";
1427
+ time.textContent = event.timestamp;
1428
+ content.appendChild(time);
1429
+ const eventTitle = document.createElement("div");
1430
+ eventTitle.className = "blex-timeline__event-title";
1431
+ eventTitle.textContent = event.title;
1432
+ content.appendChild(eventTitle);
1433
+ if (event.description) {
1434
+ const desc = document.createElement("div");
1435
+ desc.className = "blex-timeline__description";
1436
+ desc.textContent = event.description;
1437
+ content.appendChild(desc);
1438
+ }
1439
+ item.appendChild(content);
1440
+ list.appendChild(item);
1441
+ });
1442
+ wrapper.appendChild(list);
1443
+ container.appendChild(wrapper);
1444
+ container.setAttribute("data-blex-ready", "true");
1445
+ }
1446
+ };
1447
+ function createTimelineRenderer() {
1448
+ return new TimelineRenderer();
1449
+ }
1450
+
1451
+ // src/renderers/layout.ts
1452
+ var LayoutRenderer = class extends BaseRenderer {
1453
+ constructor() {
1454
+ super(...arguments);
1455
+ this.childHandles = [];
1456
+ }
1457
+ render(block, container) {
1458
+ this.container = container;
1459
+ this.buildLayout(block);
1460
+ }
1461
+ update(block) {
1462
+ if (!this.container) return;
1463
+ for (const handle of this.childHandles) {
1464
+ handle.destroy();
1465
+ }
1466
+ this.childHandles = [];
1467
+ this.container.innerHTML = "";
1468
+ this.buildLayout(block);
1469
+ }
1470
+ async buildLayout(block) {
1471
+ const container = this.container;
1472
+ const { type, columns, gap, children } = block.data;
1473
+ const wrapper = document.createElement("div");
1474
+ wrapper.className = "blex-layout";
1475
+ wrapper.setAttribute("data-testid", `blex-layout-${block.id}`);
1476
+ if (type === "grid") {
1477
+ wrapper.style.display = "grid";
1478
+ wrapper.style.gridTemplateColumns = `repeat(${columns ?? 2}, 1fr)`;
1479
+ } else {
1480
+ wrapper.style.display = "flex";
1481
+ }
1482
+ if (gap) {
1483
+ wrapper.style.gap = gap;
1484
+ }
1485
+ container.appendChild(wrapper);
1486
+ for (const child of children) {
1487
+ const childContainer = document.createElement("div");
1488
+ childContainer.className = "blex-layout__child";
1489
+ wrapper.appendChild(childContainer);
1490
+ const handle = await renderBlock(child, childContainer);
1491
+ this.childHandles.push(handle);
1492
+ }
1493
+ container.setAttribute("data-blex-ready", "true");
1494
+ }
1495
+ destroy() {
1496
+ for (const handle of this.childHandles) {
1497
+ handle.destroy();
1498
+ }
1499
+ this.childHandles = [];
1500
+ super.destroy();
1501
+ }
1502
+ };
1503
+ function createLayoutRenderer() {
1504
+ return new LayoutRenderer();
1505
+ }
1506
+
1507
+ // src/defaults.ts
1508
+ function registerDefaults() {
1509
+ registerBlockType("confirm", createConfirmRenderer);
1510
+ registerBlockType("poll", createPollRenderer);
1511
+ registerBlockType("status", createStatusRenderer);
1512
+ registerBlockType("metric", createMetricRenderer);
1513
+ registerBlockType("image", createImageRenderer);
1514
+ registerBlockType("svg", createSvgRenderer);
1515
+ registerBlockType("table", createTableRenderer);
1516
+ registerBlockType("code", createCodeRenderer);
1517
+ registerBlockType("diff", createDiffRenderer);
1518
+ registerBlockType("file-tree", createFileTreeRenderer);
1519
+ registerBlockType("form", createFormRenderer);
1520
+ registerBlockType("progress", createProgressRenderer);
1521
+ registerBlockType("terminal", createTerminalRenderer);
1522
+ registerBlockType("timeline", createTimelineRenderer);
1523
+ registerBlockType("layout", createLayoutRenderer);
1524
+ registerLazyBlockType("mermaid", async () => {
1525
+ const { createMermaidRenderer } = await import('./mermaid-W3HX2CK2.js');
1526
+ return createMermaidRenderer;
1527
+ });
1528
+ registerLazyBlockType("chart", async () => {
1529
+ const { createChartRenderer } = await import('./chart-2QT47W6E.js');
1530
+ return createChartRenderer;
1531
+ });
1532
+ registerLazyBlockType("kanban", async () => {
1533
+ const { createKanbanRenderer } = await import('./kanban-XUXVTRX2.js');
1534
+ return createKanbanRenderer;
1535
+ });
1536
+ registerLazyBlockType("calendar", async () => {
1537
+ const { createCalendarRenderer } = await import('./calendar-HUZDQQN2.js');
1538
+ return createCalendarRenderer;
1539
+ });
1540
+ registerLazyBlockType("gallery", async () => {
1541
+ const { createGalleryRenderer } = await import('./gallery-ISM7FZA3.js');
1542
+ return createGalleryRenderer;
1543
+ });
1544
+ const builtIns = [
1545
+ "confirm",
1546
+ "poll",
1547
+ "status",
1548
+ "metric",
1549
+ "image",
1550
+ "svg",
1551
+ "table",
1552
+ "code",
1553
+ "diff",
1554
+ "file-tree",
1555
+ "form",
1556
+ "progress",
1557
+ "terminal",
1558
+ "timeline",
1559
+ "layout",
1560
+ "mermaid",
1561
+ "chart",
1562
+ "kanban",
1563
+ "calendar",
1564
+ "gallery"
1565
+ ];
1566
+ for (const type of builtIns) {
1567
+ markBuiltIn(type);
1568
+ }
1569
+ }
1570
+
1571
+ export { getRegisteredTypes, hasBlockType, isBuiltIn, registerBlockType, registerDefaults, registerLazyBlockType, renderBlock, unregisterBlockType };
1572
+ //# sourceMappingURL=chunk-ZKSJGHJI.js.map
1573
+ //# sourceMappingURL=chunk-ZKSJGHJI.js.map