grist-widget-sdk 0.2.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 (70) hide show
  1. package/CHANGELOG.md +730 -0
  2. package/LICENSE +15 -0
  3. package/README.md +249 -0
  4. package/dist/advanced.cjs +2749 -0
  5. package/dist/advanced.cjs.map +1 -0
  6. package/dist/advanced.d.cts +790 -0
  7. package/dist/advanced.d.ts +790 -0
  8. package/dist/advanced.js +825 -0
  9. package/dist/advanced.js.map +1 -0
  10. package/dist/chunk-64SVRWW7.js +758 -0
  11. package/dist/chunk-64SVRWW7.js.map +1 -0
  12. package/dist/chunk-BNBV24WM.js +479 -0
  13. package/dist/chunk-BNBV24WM.js.map +1 -0
  14. package/dist/chunk-ELGVOHFD.js +32 -0
  15. package/dist/chunk-ELGVOHFD.js.map +1 -0
  16. package/dist/chunk-GTTD5HPO.js +36 -0
  17. package/dist/chunk-GTTD5HPO.js.map +1 -0
  18. package/dist/chunk-JASMM2YC.js +243 -0
  19. package/dist/chunk-JASMM2YC.js.map +1 -0
  20. package/dist/chunk-PM3B4WYV.js +12 -0
  21. package/dist/chunk-PM3B4WYV.js.map +1 -0
  22. package/dist/chunk-QKXKZ27D.js +1189 -0
  23. package/dist/chunk-QKXKZ27D.js.map +1 -0
  24. package/dist/chunk-QZG7SNUG.js +463 -0
  25. package/dist/chunk-QZG7SNUG.js.map +1 -0
  26. package/dist/chunk-REV5AUXD.js +25 -0
  27. package/dist/chunk-REV5AUXD.js.map +1 -0
  28. package/dist/chunk-XE2SKNLH.js +1641 -0
  29. package/dist/chunk-XE2SKNLH.js.map +1 -0
  30. package/dist/create-grist-emulator-C_0I4wax.d.ts +80 -0
  31. package/dist/create-grist-emulator-DBS6gmiI.d.cts +80 -0
  32. package/dist/emulator/devtools.cjs +1367 -0
  33. package/dist/emulator/devtools.cjs.map +1 -0
  34. package/dist/emulator/devtools.d.cts +46 -0
  35. package/dist/emulator/devtools.d.ts +46 -0
  36. package/dist/emulator/devtools.js +480 -0
  37. package/dist/emulator/devtools.js.map +1 -0
  38. package/dist/emulator/testing.cjs +2061 -0
  39. package/dist/emulator/testing.cjs.map +1 -0
  40. package/dist/emulator/testing.d.cts +50 -0
  41. package/dist/emulator/testing.d.ts +50 -0
  42. package/dist/emulator/testing.js +124 -0
  43. package/dist/emulator/testing.js.map +1 -0
  44. package/dist/emulator/transports.cjs +1132 -0
  45. package/dist/emulator/transports.cjs.map +1 -0
  46. package/dist/emulator/transports.d.cts +37 -0
  47. package/dist/emulator/transports.d.ts +37 -0
  48. package/dist/emulator/transports.js +12 -0
  49. package/dist/emulator/transports.js.map +1 -0
  50. package/dist/emulator.cjs +1796 -0
  51. package/dist/emulator.cjs.map +1 -0
  52. package/dist/emulator.d.cts +107 -0
  53. package/dist/emulator.d.ts +107 -0
  54. package/dist/emulator.js +26 -0
  55. package/dist/emulator.js.map +1 -0
  56. package/dist/index.cjs +5511 -0
  57. package/dist/index.cjs.map +1 -0
  58. package/dist/index.d.cts +825 -0
  59. package/dist/index.d.ts +825 -0
  60. package/dist/index.js +2447 -0
  61. package/dist/index.js.map +1 -0
  62. package/dist/inline-CRwQQ-GW.d.cts +311 -0
  63. package/dist/inline-QitZwXKP.d.ts +311 -0
  64. package/dist/templates-BC7FoSdW.d.ts +24 -0
  65. package/dist/templates-DBq719O_.d.cts +24 -0
  66. package/dist/types-Fb2wplkv.d.cts +228 -0
  67. package/dist/types-Fb2wplkv.d.ts +228 -0
  68. package/dist/use-grist-widget-options-from-context-BFhQBGRY.d.ts +522 -0
  69. package/dist/use-grist-widget-options-from-context-qpFMdoBJ.d.cts +522 -0
  70. package/package.json +131 -0
@@ -0,0 +1,480 @@
1
+ import {
2
+ isGristNoiseColumn
3
+ } from "../chunk-REV5AUXD.js";
4
+ import {
5
+ materializeGristRowsFromColumnar,
6
+ safeParseRowsToDisplayRows
7
+ } from "../chunk-JASMM2YC.js";
8
+ import {
9
+ rowsToColumnar
10
+ } from "../chunk-ELGVOHFD.js";
11
+ import {
12
+ resolveMappings
13
+ } from "../chunk-PM3B4WYV.js";
14
+ import {
15
+ gristAddRecordAction,
16
+ gristRemoveRecordAction,
17
+ gristUpdateRecordAction
18
+ } from "../chunk-64SVRWW7.js";
19
+
20
+ // src/emulator/devtools/inspector.tsx
21
+ import { useState } from "react";
22
+
23
+ // src/emulator/devtools/use-emulator-state.ts
24
+ import { useSyncExternalStore } from "react";
25
+ function useEmulatorSnapshot(emulator) {
26
+ const subscribe = (notify) => {
27
+ return emulator.bus.on(() => notify());
28
+ };
29
+ const getSnapshot = () => snapshotKey(emulator);
30
+ useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
31
+ return {
32
+ state: emulator.state,
33
+ history: emulator.bus.history()
34
+ };
35
+ }
36
+ function snapshotKey(emulator) {
37
+ const history = emulator.bus.history();
38
+ const last = history[history.length - 1];
39
+ return `${history.length}:${eventTag(last)}`;
40
+ }
41
+ function eventTag(event) {
42
+ if (!event) return "empty";
43
+ switch (event.type) {
44
+ case "data-change":
45
+ return `data:${event.tableId}`;
46
+ case "cursor-change":
47
+ return `cursor:${event.tableId}:${String(event.rowId)}`;
48
+ case "options-change":
49
+ return `options:${Object.keys(event.options).length}`;
50
+ case "ready":
51
+ return "ready";
52
+ case "user-action":
53
+ return `action:${event.action[0] ?? "?"}`;
54
+ case "mappings-change":
55
+ return "mappings";
56
+ case "theme-change":
57
+ return "theme";
58
+ }
59
+ }
60
+
61
+ // src/emulator/devtools/inspector.tsx
62
+ import { jsx, jsxs } from "react/jsx-runtime";
63
+ function EmulatorInspector({ emulator, className, showTimeline = true }) {
64
+ const { state, history } = useEmulatorSnapshot(emulator);
65
+ const tableIds = [...state.tables.keys()];
66
+ const selectedTableId = state.selection.tableId;
67
+ const table = state.tables.get(selectedTableId);
68
+ const columnIds = table ? Object.keys(table.columns) : [];
69
+ const onSelectTable = (tableId) => emulator.selectTable(tableId);
70
+ const onSelectRow = (rowId) => emulator.selectRow(rowId);
71
+ const onAddRow = () => {
72
+ if (!table) return;
73
+ const fields = {};
74
+ for (const col of columnIds) fields[col] = "";
75
+ emulator.apply([gristAddRecordAction(selectedTableId, fields)]);
76
+ };
77
+ const onDeleteRow = (rowId) => {
78
+ emulator.apply([gristRemoveRecordAction(selectedTableId, rowId)]);
79
+ };
80
+ const onEditCell = (rowId, colId, value) => {
81
+ emulator.apply([gristUpdateRecordAction(selectedTableId, rowId, { [colId]: value })]);
82
+ };
83
+ return /* @__PURE__ */ jsxs("div", { className, style: baseStyle, children: [
84
+ /* @__PURE__ */ jsxs("div", { style: headerStyle, children: [
85
+ /* @__PURE__ */ jsx("span", { style: badgeStyle, children: "EMULATOR" }),
86
+ /* @__PURE__ */ jsx("strong", { children: state.docName }),
87
+ /* @__PURE__ */ jsxs("span", { style: mutedStyle, children: [
88
+ "\xB7 ",
89
+ tableIds.length,
90
+ " table",
91
+ tableIds.length === 1 ? "" : "s"
92
+ ] })
93
+ ] }),
94
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", gap: 6, padding: "8px 12px", flexWrap: "wrap" }, children: tableIds.map((id) => {
95
+ const t = state.tables.get(id);
96
+ const active = id === selectedTableId;
97
+ return /* @__PURE__ */ jsxs(
98
+ "button",
99
+ {
100
+ type: "button",
101
+ onClick: () => onSelectTable(id),
102
+ style: active ? tabActiveStyle : tabStyle,
103
+ children: [
104
+ t.label ?? id,
105
+ /* @__PURE__ */ jsxs("span", { style: mutedStyle, children: [
106
+ " \xB7 ",
107
+ t.rows.length
108
+ ] })
109
+ ]
110
+ },
111
+ id
112
+ );
113
+ }) }),
114
+ /* @__PURE__ */ jsx(Section, { title: "Rows", children: !table ? /* @__PURE__ */ jsx("p", { style: mutedStyle, children: "No table selected." }) : /* @__PURE__ */ jsxs("div", { children: [
115
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 6, marginBottom: 6 }, children: [
116
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: onAddRow, style: primaryBtnStyle, children: "+ Row" }),
117
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => onSelectRow("new"), style: ghostBtnStyle, children: "Cursor \u2192 new" }),
118
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => onSelectRow(null), style: ghostBtnStyle, children: "Cursor \u2192 none" })
119
+ ] }),
120
+ /* @__PURE__ */ jsx("div", { style: { overflowX: "auto" }, children: /* @__PURE__ */ jsxs("table", { style: tableStyle, children: [
121
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { style: { borderBottom: "1px solid #2a2f37" }, children: [
122
+ /* @__PURE__ */ jsx("th", { style: thStyle, children: "id" }),
123
+ columnIds.map((col) => /* @__PURE__ */ jsx("th", { style: thStyle, children: table.columns[col]?.label ?? col }, col)),
124
+ /* @__PURE__ */ jsx("th", { style: thStyle })
125
+ ] }) }),
126
+ /* @__PURE__ */ jsx("tbody", { children: table.rows.map((row) => {
127
+ const rowId = row.id;
128
+ const active = state.selection.rowId === rowId;
129
+ return /* @__PURE__ */ jsxs(
130
+ "tr",
131
+ {
132
+ style: active ? trActiveStyle : trStyle,
133
+ onClick: () => onSelectRow(rowId),
134
+ children: [
135
+ /* @__PURE__ */ jsx("td", { style: tdStyle, children: rowId }),
136
+ columnIds.map((col) => /* @__PURE__ */ jsx("td", { style: tdStyle, children: /* @__PURE__ */ jsx(
137
+ "input",
138
+ {
139
+ value: formatCell(row[col]),
140
+ style: inputStyle,
141
+ onClick: (event) => event.stopPropagation(),
142
+ onChange: (event) => onEditCell(rowId, col, event.target.value)
143
+ }
144
+ ) }, col)),
145
+ /* @__PURE__ */ jsx("td", { style: tdStyle, children: /* @__PURE__ */ jsx(
146
+ "button",
147
+ {
148
+ type: "button",
149
+ style: dangerBtnStyle,
150
+ onClick: (event) => {
151
+ event.stopPropagation();
152
+ onDeleteRow(rowId);
153
+ },
154
+ children: "Delete"
155
+ }
156
+ ) })
157
+ ]
158
+ },
159
+ rowId
160
+ );
161
+ }) })
162
+ ] }) })
163
+ ] }) }),
164
+ /* @__PURE__ */ jsx(Section, { title: "Selection / mappings", children: /* @__PURE__ */ jsxs("div", { style: kvStyle, children: [
165
+ /* @__PURE__ */ jsx(KV, { k: "tableId", v: state.selection.tableId }),
166
+ /* @__PURE__ */ jsx(KV, { k: "rowId", v: String(state.selection.rowId) }),
167
+ /* @__PURE__ */ jsx(KV, { k: "mappings", v: JSON.stringify(resolveMappings(state)) }),
168
+ /* @__PURE__ */ jsx(KV, { k: "configuration", v: JSON.stringify(state.configuration) })
169
+ ] }) }),
170
+ /* @__PURE__ */ jsxs(Section, { title: "Widget options", children: [
171
+ /* @__PURE__ */ jsx("pre", { style: preStyle, children: JSON.stringify(state.widgetOptions, null, 2) }),
172
+ /* @__PURE__ */ jsx(KV, { k: "interaction", v: JSON.stringify(state.widgetInteraction) })
173
+ ] }),
174
+ showTimeline && /* @__PURE__ */ jsx(Section, { title: `Event timeline (${history.length})`, children: /* @__PURE__ */ jsxs("div", { style: { maxHeight: 200, overflow: "auto", fontFamily: "monospace", fontSize: 11 }, children: [
175
+ history.slice(-50).reverse().map((event, idx) => /* @__PURE__ */ jsxs("div", { style: timelineRowStyle, children: [
176
+ /* @__PURE__ */ jsx("span", { style: typeBadgeStyle(event.type), children: event.type }),
177
+ /* @__PURE__ */ jsx("span", { style: mutedStyle, children: summariseEvent(event) })
178
+ ] }, idx)),
179
+ history.length === 0 && /* @__PURE__ */ jsx("p", { style: mutedStyle, children: "No events yet." })
180
+ ] }) })
181
+ ] });
182
+ }
183
+ function Section({ title, children }) {
184
+ const [open, setOpen] = useState(true);
185
+ return /* @__PURE__ */ jsxs("div", { style: { borderTop: "1px solid #2a2f37" }, children: [
186
+ /* @__PURE__ */ jsxs("button", { type: "button", style: sectionHeaderStyle, onClick: () => setOpen((v) => !v), children: [
187
+ /* @__PURE__ */ jsx("span", { children: open ? "\u25BE" : "\u25B8" }),
188
+ /* @__PURE__ */ jsx("strong", { children: title })
189
+ ] }),
190
+ open && /* @__PURE__ */ jsx("div", { style: { padding: "0 12px 12px" }, children })
191
+ ] });
192
+ }
193
+ function KV({ k, v }) {
194
+ return /* @__PURE__ */ jsxs("div", { style: kvRowStyle, children: [
195
+ /* @__PURE__ */ jsx("span", { style: mutedStyle, children: k }),
196
+ /* @__PURE__ */ jsx("code", { style: { fontFamily: "monospace", fontSize: 11 }, children: v })
197
+ ] });
198
+ }
199
+ function summariseEvent(event) {
200
+ switch (event.type) {
201
+ case "user-action":
202
+ return JSON.stringify(event.action);
203
+ case "data-change":
204
+ return `tableId=${String(event.tableId)}`;
205
+ case "cursor-change":
206
+ return `tableId=${String(event.tableId)} rowId=${String(event.rowId)}`;
207
+ case "options-change":
208
+ return JSON.stringify(event.options);
209
+ case "ready":
210
+ return JSON.stringify(event.configuration);
211
+ case "theme-change":
212
+ return JSON.stringify(event.message);
213
+ case "mappings-change":
214
+ return JSON.stringify(event.mappings);
215
+ default:
216
+ return "";
217
+ }
218
+ }
219
+ function formatCell(value) {
220
+ if (value === null || value === void 0) return "";
221
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return String(value);
222
+ return JSON.stringify(value);
223
+ }
224
+ var baseStyle = {
225
+ background: "#15171c",
226
+ color: "#e6e6e6",
227
+ fontFamily: "system-ui, sans-serif",
228
+ fontSize: 13,
229
+ border: "1px solid #2a2f37",
230
+ borderRadius: 8,
231
+ overflow: "hidden"
232
+ };
233
+ var headerStyle = {
234
+ display: "flex",
235
+ alignItems: "center",
236
+ gap: 8,
237
+ padding: "10px 12px",
238
+ background: "#0f1115",
239
+ borderBottom: "1px solid #2a2f37"
240
+ };
241
+ var badgeStyle = {
242
+ background: "#3a8e57",
243
+ color: "#fff",
244
+ padding: "1px 6px",
245
+ borderRadius: 4,
246
+ fontSize: 10,
247
+ letterSpacing: 0.5
248
+ };
249
+ var mutedStyle = { color: "#9ba1ad" };
250
+ var sectionHeaderStyle = {
251
+ display: "flex",
252
+ alignItems: "center",
253
+ gap: 6,
254
+ width: "100%",
255
+ background: "transparent",
256
+ color: "inherit",
257
+ border: "none",
258
+ padding: "10px 12px",
259
+ textAlign: "left",
260
+ cursor: "pointer"
261
+ };
262
+ var tabStyle = {
263
+ background: "#1c1f26",
264
+ color: "#cfd2d8",
265
+ border: "1px solid #2a2f37",
266
+ borderRadius: 6,
267
+ padding: "4px 10px",
268
+ cursor: "pointer"
269
+ };
270
+ var tabActiveStyle = { ...tabStyle, background: "#27313f", borderColor: "#3a4f6e", color: "#fff" };
271
+ var primaryBtnStyle = {
272
+ background: "#3a8e57",
273
+ color: "#fff",
274
+ border: "none",
275
+ borderRadius: 6,
276
+ padding: "4px 10px",
277
+ cursor: "pointer"
278
+ };
279
+ var ghostBtnStyle = {
280
+ background: "transparent",
281
+ color: "#cfd2d8",
282
+ border: "1px solid #2a2f37",
283
+ borderRadius: 6,
284
+ padding: "4px 10px",
285
+ cursor: "pointer"
286
+ };
287
+ var dangerBtnStyle = {
288
+ background: "transparent",
289
+ color: "#e58f8f",
290
+ border: "1px solid #4a2226",
291
+ borderRadius: 6,
292
+ padding: "2px 8px",
293
+ cursor: "pointer"
294
+ };
295
+ var tableStyle = { width: "100%", borderCollapse: "collapse", fontSize: 12 };
296
+ var thStyle = { textAlign: "left", padding: "4px 6px", color: "#9ba1ad", fontWeight: 500 };
297
+ var trStyle = { borderBottom: "1px solid #1f232b" };
298
+ var trActiveStyle = { ...trStyle, background: "#1d2733" };
299
+ var tdStyle = { padding: "4px 6px" };
300
+ var inputStyle = {
301
+ width: "100%",
302
+ background: "#0f1115",
303
+ color: "#e6e6e6",
304
+ border: "1px solid #2a2f37",
305
+ borderRadius: 4,
306
+ padding: "2px 4px",
307
+ fontSize: 12,
308
+ fontFamily: "monospace"
309
+ };
310
+ var preStyle = {
311
+ background: "#0f1115",
312
+ border: "1px solid #2a2f37",
313
+ borderRadius: 4,
314
+ padding: 8,
315
+ fontSize: 11,
316
+ fontFamily: "monospace",
317
+ margin: 0,
318
+ whiteSpace: "pre-wrap"
319
+ };
320
+ var kvStyle = { display: "flex", flexDirection: "column", gap: 4 };
321
+ var kvRowStyle = { display: "flex", gap: 8 };
322
+ var timelineRowStyle = {
323
+ display: "flex",
324
+ gap: 8,
325
+ padding: "2px 0",
326
+ borderBottom: "1px solid #1f232b"
327
+ };
328
+ function typeBadgeStyle(type) {
329
+ const colour = {
330
+ "user-action": "#a06bff",
331
+ "data-change": "#3a8e57",
332
+ "cursor-change": "#3a87b8",
333
+ "options-change": "#b8893a",
334
+ ready: "#888",
335
+ "theme-change": "#888",
336
+ "mappings-change": "#888"
337
+ }[type] ?? "#888";
338
+ return {
339
+ background: colour,
340
+ color: "#fff",
341
+ padding: "1px 6px",
342
+ borderRadius: 4,
343
+ fontSize: 10,
344
+ flexShrink: 0
345
+ };
346
+ }
347
+
348
+ // src/emulator/devtools/use-rows.ts
349
+ import { useEffect, useState as useState2 } from "react";
350
+ function fetchEmulatorRows(emulator, tableId) {
351
+ const table = emulator.state.tables.get(tableId);
352
+ if (!table) {
353
+ return { rows: [], invalidCellKeys: /* @__PURE__ */ new Set() };
354
+ }
355
+ let cellMetaByKey = {};
356
+ const data = rowsToColumnar(table, table.rows);
357
+ const parsedRows = materializeGristRowsFromColumnar(data, {
358
+ columns: table.columns,
359
+ order: "grist",
360
+ safeParse: {
361
+ refMode: "detailed"
362
+ },
363
+ onSafeParseCellMetaByKey: (metaByKey) => {
364
+ cellMetaByKey = metaByKey;
365
+ }
366
+ });
367
+ const rows = safeParseRowsToDisplayRows(parsedRows);
368
+ const invalidCellKeys = /* @__PURE__ */ new Set();
369
+ for (const [cellKey, meta] of Object.entries(cellMetaByKey)) {
370
+ const hasIssue = meta.issues.some(
371
+ (issue) => issue.code === "type_mismatch" || issue.code === "invalid_format"
372
+ );
373
+ if (hasIssue) invalidCellKeys.add(cellKey);
374
+ }
375
+ return { rows, invalidCellKeys };
376
+ }
377
+ function useEmulatorRows(emulator, tableId) {
378
+ const { history } = useEmulatorSnapshot(emulator);
379
+ const [result, setResult] = useState2({
380
+ rows: [],
381
+ invalidCellKeys: /* @__PURE__ */ new Set()
382
+ });
383
+ useEffect(() => {
384
+ let cancelled = false;
385
+ if (!tableId) {
386
+ queueMicrotask(() => {
387
+ if (!cancelled) setResult({ rows: [], invalidCellKeys: /* @__PURE__ */ new Set() });
388
+ });
389
+ return () => {
390
+ cancelled = true;
391
+ };
392
+ }
393
+ try {
394
+ const next = fetchEmulatorRows(emulator, tableId);
395
+ if (!cancelled) setResult(next);
396
+ } catch {
397
+ const table = emulator.state.tables.get(tableId);
398
+ if (!cancelled) {
399
+ setResult({
400
+ rows: table?.rows ?? [],
401
+ invalidCellKeys: /* @__PURE__ */ new Set()
402
+ });
403
+ }
404
+ }
405
+ return () => {
406
+ cancelled = true;
407
+ };
408
+ }, [emulator, tableId, history.length]);
409
+ return result;
410
+ }
411
+
412
+ // src/emulator/devtools/use-columns.ts
413
+ import { useMemo } from "react";
414
+ function useEmulatorColumns(emulator) {
415
+ const { state } = useEmulatorSnapshot(emulator);
416
+ const requestedTableId = state.selection.tableId;
417
+ const document = useMemo(() => {
418
+ const tables = {};
419
+ for (const [tableId, table2] of state.tables.entries()) {
420
+ const filteredColumns = Object.fromEntries(
421
+ Object.entries(table2.columns).filter(([colId, col]) => {
422
+ return !isGristNoiseColumn(colId, col, {
423
+ excludeId: true,
424
+ excludeGristHelpers: true,
425
+ excludeLoggingColumns: true,
426
+ excludeManualSort: true
427
+ });
428
+ })
429
+ );
430
+ tables[tableId] = {
431
+ label: table2.label,
432
+ columns: filteredColumns,
433
+ rows: table2.rows.map((row) => ({ ...row })),
434
+ rowCount: table2.rows.length
435
+ };
436
+ }
437
+ return {
438
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
439
+ docName: state.docName,
440
+ mode: "schema+data",
441
+ source: "emulator-devtools",
442
+ tables
443
+ };
444
+ }, [state]);
445
+ const table = useMemo(() => {
446
+ if (!requestedTableId) return null;
447
+ const slice = document.tables[requestedTableId];
448
+ if (!slice) return null;
449
+ return { tableId: requestedTableId, ...slice };
450
+ }, [document, requestedTableId]);
451
+ const isNoiseColumnId = useMemo(
452
+ () => (colId, col) => isGristNoiseColumn(colId, col, {
453
+ excludeId: true,
454
+ excludeGristHelpers: true,
455
+ excludeLoggingColumns: true,
456
+ excludeManualSort: true
457
+ }),
458
+ []
459
+ );
460
+ const sortColumnIds = useMemo(
461
+ () => (colIds, columns) => {
462
+ return [...colIds].sort((a, b) => {
463
+ const la = (columns[a]?.label || a).toLowerCase();
464
+ const lb = (columns[b]?.label || b).toLowerCase();
465
+ if (la !== lb) return la.localeCompare(lb);
466
+ return a.localeCompare(b);
467
+ });
468
+ },
469
+ []
470
+ );
471
+ return { document, table, isNoiseColumnId, sortColumnIds };
472
+ }
473
+ export {
474
+ EmulatorInspector,
475
+ fetchEmulatorRows,
476
+ useEmulatorColumns,
477
+ useEmulatorRows,
478
+ useEmulatorSnapshot
479
+ };
480
+ //# sourceMappingURL=devtools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/emulator/devtools/inspector.tsx","../../src/emulator/devtools/use-emulator-state.ts","../../src/emulator/devtools/use-rows.ts","../../src/emulator/devtools/use-columns.ts"],"sourcesContent":["/**\n * `<EmulatorInspector />` — drop-in DevTools for the playground / IDE.\n *\n * Capabilities:\n * - Multi-table picker with row count + label\n * - Inline row editor (Add / Update / Delete) routed through the emulator's\n * action engine — every edit produces real Grist user actions on the bus.\n * - Cursor selector that drives `onRecord` for the widget under test.\n * - Widget options & mappings panel.\n * - Live event timeline (last 50 events) with pretty formatting.\n *\n * The component owns no state of its own beyond UI accordion toggles —\n * everything is read off the emulator and re-renders via {@link\n * useEmulatorSnapshot}.\n */\n\nimport type { CSSProperties, ReactNode } from \"react\"\nimport { useState } from \"react\"\n\nimport { gristAddRecordAction, gristRemoveRecordAction, gristUpdateRecordAction } from \"../../sdk/helpers/grist-user-actions\"\nimport type { GristEmulator } from \"../create-grist-emulator\"\nimport { resolveMappings } from \"../core/mappings\"\nimport { useEmulatorSnapshot } from \"./use-emulator-state\"\n\nexport type EmulatorInspectorProps = {\n emulator: GristEmulator\n /** Override visual style. */\n className?: string\n /** Default `true`. Set to `false` to render only the toolbar. */\n showTimeline?: boolean\n}\n\nexport function EmulatorInspector({ emulator, className, showTimeline = true }: EmulatorInspectorProps) {\n const { state, history } = useEmulatorSnapshot(emulator)\n const tableIds = [...state.tables.keys()]\n const selectedTableId = state.selection.tableId\n const table = state.tables.get(selectedTableId)\n const columnIds = table ? Object.keys(table.columns) : []\n\n const onSelectTable = (tableId: string) => emulator.selectTable(tableId)\n const onSelectRow = (rowId: number | \"new\" | null) => emulator.selectRow(rowId)\n const onAddRow = () => {\n if (!table) return\n const fields: Record<string, unknown> = {}\n for (const col of columnIds) fields[col] = \"\"\n emulator.apply([gristAddRecordAction(selectedTableId, fields)])\n }\n const onDeleteRow = (rowId: number) => {\n emulator.apply([gristRemoveRecordAction(selectedTableId, rowId)])\n }\n const onEditCell = (rowId: number, colId: string, value: string) => {\n emulator.apply([gristUpdateRecordAction(selectedTableId, rowId, { [colId]: value })])\n }\n\n return (\n <div className={className} style={baseStyle}>\n <div style={headerStyle}>\n <span style={badgeStyle}>EMULATOR</span>\n <strong>{state.docName}</strong>\n <span style={mutedStyle}>· {tableIds.length} table{tableIds.length === 1 ? \"\" : \"s\"}</span>\n </div>\n\n <div style={{ display: \"flex\", gap: 6, padding: \"8px 12px\", flexWrap: \"wrap\" }}>\n {tableIds.map((id) => {\n const t = state.tables.get(id)!\n const active = id === selectedTableId\n return (\n <button\n key={id}\n type=\"button\"\n onClick={() => onSelectTable(id)}\n style={active ? tabActiveStyle : tabStyle}\n >\n {t.label ?? id}\n <span style={mutedStyle}> · {t.rows.length}</span>\n </button>\n )\n })}\n </div>\n\n <Section title=\"Rows\">\n {!table ? (\n <p style={mutedStyle}>No table selected.</p>\n ) : (\n <div>\n <div style={{ display: \"flex\", gap: 6, marginBottom: 6 }}>\n <button type=\"button\" onClick={onAddRow} style={primaryBtnStyle}>+ Row</button>\n <button type=\"button\" onClick={() => onSelectRow(\"new\")} style={ghostBtnStyle}>Cursor → new</button>\n <button type=\"button\" onClick={() => onSelectRow(null)} style={ghostBtnStyle}>Cursor → none</button>\n </div>\n <div style={{ overflowX: \"auto\" }}>\n <table style={tableStyle}>\n <thead>\n <tr style={{ borderBottom: \"1px solid #2a2f37\" }}>\n <th style={thStyle}>id</th>\n {columnIds.map((col) => (\n <th key={col} style={thStyle}>\n {table.columns[col]?.label ?? col}\n </th>\n ))}\n <th style={thStyle}></th>\n </tr>\n </thead>\n <tbody>\n {table.rows.map((row) => {\n const rowId = row.id\n const active = state.selection.rowId === rowId\n return (\n <tr\n key={rowId}\n style={active ? trActiveStyle : trStyle}\n onClick={() => onSelectRow(rowId)}\n >\n <td style={tdStyle}>{rowId}</td>\n {columnIds.map((col) => (\n <td key={col} style={tdStyle}>\n <input\n value={formatCell(row[col])}\n style={inputStyle}\n onClick={(event) => event.stopPropagation()}\n onChange={(event) => onEditCell(rowId, col, event.target.value)}\n />\n </td>\n ))}\n <td style={tdStyle}>\n <button\n type=\"button\"\n style={dangerBtnStyle}\n onClick={(event) => {\n event.stopPropagation()\n onDeleteRow(rowId)\n }}\n >\n Delete\n </button>\n </td>\n </tr>\n )\n })}\n </tbody>\n </table>\n </div>\n </div>\n )}\n </Section>\n\n <Section title=\"Selection / mappings\">\n <div style={kvStyle}>\n <KV k=\"tableId\" v={state.selection.tableId} />\n <KV k=\"rowId\" v={String(state.selection.rowId)} />\n <KV k=\"mappings\" v={JSON.stringify(resolveMappings(state))} />\n <KV k=\"configuration\" v={JSON.stringify(state.configuration)} />\n </div>\n </Section>\n\n <Section title=\"Widget options\">\n <pre style={preStyle}>{JSON.stringify(state.widgetOptions, null, 2)}</pre>\n <KV k=\"interaction\" v={JSON.stringify(state.widgetInteraction)} />\n </Section>\n\n {showTimeline && (\n <Section title={`Event timeline (${history.length})`}>\n <div style={{ maxHeight: 200, overflow: \"auto\", fontFamily: \"monospace\", fontSize: 11 }}>\n {history.slice(-50).reverse().map((event, idx) => (\n <div key={idx} style={timelineRowStyle}>\n <span style={typeBadgeStyle(event.type)}>{event.type}</span>\n <span style={mutedStyle}>{summariseEvent(event)}</span>\n </div>\n ))}\n {history.length === 0 && <p style={mutedStyle}>No events yet.</p>}\n </div>\n </Section>\n )}\n </div>\n )\n}\n\nfunction Section({ title, children }: { title: string; children: ReactNode }) {\n const [open, setOpen] = useState(true)\n return (\n <div style={{ borderTop: \"1px solid #2a2f37\" }}>\n <button type=\"button\" style={sectionHeaderStyle} onClick={() => setOpen((v) => !v)}>\n <span>{open ? \"▾\" : \"▸\"}</span>\n <strong>{title}</strong>\n </button>\n {open && <div style={{ padding: \"0 12px 12px\" }}>{children}</div>}\n </div>\n )\n}\n\nfunction KV({ k, v }: { k: string; v: ReactNode }) {\n return (\n <div style={kvRowStyle}>\n <span style={mutedStyle}>{k}</span>\n <code style={{ fontFamily: \"monospace\", fontSize: 11 }}>{v}</code>\n </div>\n )\n}\n\nfunction summariseEvent(event: { type: string } & Record<string, unknown>): string {\n switch (event.type) {\n case \"user-action\":\n return JSON.stringify(event.action)\n case \"data-change\":\n return `tableId=${String(event.tableId)}`\n case \"cursor-change\":\n return `tableId=${String(event.tableId)} rowId=${String(event.rowId)}`\n case \"options-change\":\n return JSON.stringify(event.options)\n case \"ready\":\n return JSON.stringify(event.configuration)\n case \"theme-change\":\n return JSON.stringify(event.message)\n case \"mappings-change\":\n return JSON.stringify(event.mappings)\n default:\n return \"\"\n }\n}\n\nfunction formatCell(value: unknown): string {\n if (value === null || value === undefined) return \"\"\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") return String(value)\n return JSON.stringify(value)\n}\n\n// --- styles -----------------------------------------------------------------\n\nconst baseStyle: CSSProperties = {\n background: \"#15171c\",\n color: \"#e6e6e6\",\n fontFamily: \"system-ui, sans-serif\",\n fontSize: 13,\n border: \"1px solid #2a2f37\",\n borderRadius: 8,\n overflow: \"hidden\",\n}\nconst headerStyle: CSSProperties = {\n display: \"flex\",\n alignItems: \"center\",\n gap: 8,\n padding: \"10px 12px\",\n background: \"#0f1115\",\n borderBottom: \"1px solid #2a2f37\",\n}\nconst badgeStyle: CSSProperties = {\n background: \"#3a8e57\",\n color: \"#fff\",\n padding: \"1px 6px\",\n borderRadius: 4,\n fontSize: 10,\n letterSpacing: 0.5,\n}\nconst mutedStyle: CSSProperties = { color: \"#9ba1ad\" }\nconst sectionHeaderStyle: CSSProperties = {\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n width: \"100%\",\n background: \"transparent\",\n color: \"inherit\",\n border: \"none\",\n padding: \"10px 12px\",\n textAlign: \"left\" as const,\n cursor: \"pointer\",\n}\nconst tabStyle: CSSProperties = {\n background: \"#1c1f26\",\n color: \"#cfd2d8\",\n border: \"1px solid #2a2f37\",\n borderRadius: 6,\n padding: \"4px 10px\",\n cursor: \"pointer\",\n}\nconst tabActiveStyle: CSSProperties = { ...tabStyle, background: \"#27313f\", borderColor: \"#3a4f6e\", color: \"#fff\" }\nconst primaryBtnStyle: CSSProperties = {\n background: \"#3a8e57\",\n color: \"#fff\",\n border: \"none\",\n borderRadius: 6,\n padding: \"4px 10px\",\n cursor: \"pointer\",\n}\nconst ghostBtnStyle: CSSProperties = {\n background: \"transparent\",\n color: \"#cfd2d8\",\n border: \"1px solid #2a2f37\",\n borderRadius: 6,\n padding: \"4px 10px\",\n cursor: \"pointer\",\n}\nconst dangerBtnStyle: CSSProperties = {\n background: \"transparent\",\n color: \"#e58f8f\",\n border: \"1px solid #4a2226\",\n borderRadius: 6,\n padding: \"2px 8px\",\n cursor: \"pointer\",\n}\nconst tableStyle: CSSProperties = { width: \"100%\", borderCollapse: \"collapse\" as const, fontSize: 12 }\nconst thStyle: CSSProperties = { textAlign: \"left\" as const, padding: \"4px 6px\", color: \"#9ba1ad\", fontWeight: 500 }\nconst trStyle: CSSProperties = { borderBottom: \"1px solid #1f232b\" }\nconst trActiveStyle: CSSProperties = { ...trStyle, background: \"#1d2733\" }\nconst tdStyle: CSSProperties = { padding: \"4px 6px\" }\nconst inputStyle: CSSProperties = {\n width: \"100%\",\n background: \"#0f1115\",\n color: \"#e6e6e6\",\n border: \"1px solid #2a2f37\",\n borderRadius: 4,\n padding: \"2px 4px\",\n fontSize: 12,\n fontFamily: \"monospace\",\n}\nconst preStyle: CSSProperties = {\n background: \"#0f1115\",\n border: \"1px solid #2a2f37\",\n borderRadius: 4,\n padding: 8,\n fontSize: 11,\n fontFamily: \"monospace\",\n margin: 0,\n whiteSpace: \"pre-wrap\",\n}\nconst kvStyle: CSSProperties = { display: \"flex\", flexDirection: \"column\" as const, gap: 4 }\nconst kvRowStyle: CSSProperties = { display: \"flex\", gap: 8 }\nconst timelineRowStyle: CSSProperties = {\n display: \"flex\",\n gap: 8,\n padding: \"2px 0\",\n borderBottom: \"1px solid #1f232b\",\n}\nfunction typeBadgeStyle(type: string): CSSProperties {\n const colour = ({\n \"user-action\": \"#a06bff\",\n \"data-change\": \"#3a8e57\",\n \"cursor-change\": \"#3a87b8\",\n \"options-change\": \"#b8893a\",\n ready: \"#888\",\n \"theme-change\": \"#888\",\n \"mappings-change\": \"#888\",\n } as Record<string, string>)[type] ?? \"#888\"\n return {\n background: colour,\n color: \"#fff\",\n padding: \"1px 6px\",\n borderRadius: 4,\n fontSize: 10,\n flexShrink: 0,\n }\n}\n","import { useSyncExternalStore } from \"react\"\n\nimport type { GristEmulator } from \"../create-grist-emulator\"\nimport type { EmulatorEvent } from \"../core/event-bus\"\n\n/**\n * React-friendly snapshot of the emulator state. Re-renders whenever the\n * event bus fires (so the inspector stays in lock-step with widget actions).\n */\nexport function useEmulatorSnapshot(emulator: GristEmulator) {\n const subscribe = (notify: () => void) => {\n return emulator.bus.on(() => notify())\n }\n const getSnapshot = () => snapshotKey(emulator)\n useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n return {\n state: emulator.state,\n history: emulator.bus.history(),\n }\n}\n\n/**\n * A monotonic-ish key that changes on every event. We tag each event with\n * its index in the history so React detects changes cheaply.\n */\nfunction snapshotKey(emulator: GristEmulator): string {\n const history = emulator.bus.history()\n const last = history[history.length - 1]\n return `${history.length}:${eventTag(last)}`\n}\n\nfunction eventTag(event: EmulatorEvent | undefined): string {\n if (!event) return \"empty\"\n switch (event.type) {\n case \"data-change\":\n return `data:${event.tableId}`\n case \"cursor-change\":\n return `cursor:${event.tableId}:${String(event.rowId)}`\n case \"options-change\":\n return `options:${Object.keys(event.options).length}`\n case \"ready\":\n return \"ready\"\n case \"user-action\":\n return `action:${(event.action[0] as string | undefined) ?? \"?\"}`\n case \"mappings-change\":\n return \"mappings\"\n case \"theme-change\":\n return \"theme\"\n }\n}\n","import { useEffect, useState } from \"react\"\n\nimport {\n materializeGristRowsFromColumnar,\n safeParseRowsToDisplayRows,\n} from \"../../sdk/helpers/grist-table-data\"\nimport type { GristRowRecord } from \"../../sdk/types\"\nimport type { GristEmulator } from \"../create-grist-emulator\"\nimport { rowsToColumnar } from \"../core/columnar\"\nimport { useEmulatorSnapshot } from \"./use-emulator-state\"\n\nexport type UseEmulatorRowsResult<T extends Record<string, unknown> = Record<string, unknown>> = {\n rows: GristRowRecord<T>[]\n invalidCellKeys: Set<string>\n}\n\n/**\n * Build display-ready rows from emulator in-memory state (same parse pipeline as\n * {@link fetchGristTableRows}, without `docApi.fetchTable`).\n */\nexport function fetchEmulatorRows<T extends Record<string, unknown> = Record<string, unknown>>(\n emulator: GristEmulator,\n tableId: string\n): UseEmulatorRowsResult<T> {\n const table = emulator.state.tables.get(tableId)\n if (!table) {\n return { rows: [], invalidCellKeys: new Set() }\n }\n\n let cellMetaByKey: Record<string, { issues: Array<{ code: string }> }> = {}\n const data = rowsToColumnar(table, table.rows)\n const parsedRows = materializeGristRowsFromColumnar<T>(data, {\n columns: table.columns,\n order: \"grist\",\n safeParse: {\n refMode: \"detailed\",\n },\n onSafeParseCellMetaByKey: (metaByKey) => {\n cellMetaByKey = metaByKey as Record<string, { issues: Array<{ code: string }> }>\n },\n })\n const rows = safeParseRowsToDisplayRows(parsedRows) as GristRowRecord<T>[]\n const invalidCellKeys = new Set<string>()\n for (const [cellKey, meta] of Object.entries(cellMetaByKey)) {\n const hasIssue = meta.issues.some(\n (issue) => issue.code === \"type_mismatch\" || issue.code === \"invalid_format\"\n )\n if (hasIssue) invalidCellKeys.add(cellKey)\n }\n return { rows, invalidCellKeys }\n}\n\nexport function useEmulatorRows<T extends Record<string, unknown> = Record<string, unknown>>(\n emulator: GristEmulator,\n tableId: string | undefined | null\n): UseEmulatorRowsResult<T> {\n const { history } = useEmulatorSnapshot(emulator)\n const [result, setResult] = useState<UseEmulatorRowsResult<T>>({\n rows: [],\n invalidCellKeys: new Set(),\n })\n\n useEffect(() => {\n let cancelled = false\n if (!tableId) {\n queueMicrotask(() => {\n if (!cancelled) setResult({ rows: [], invalidCellKeys: new Set() })\n })\n return () => {\n cancelled = true\n }\n }\n\n try {\n const next = fetchEmulatorRows<T>(emulator, tableId)\n if (!cancelled) setResult(next)\n } catch {\n const table = emulator.state.tables.get(tableId)\n if (!cancelled) {\n setResult({\n rows: (table?.rows ?? []) as GristRowRecord<T>[],\n invalidCellKeys: new Set(),\n })\n }\n }\n\n return () => {\n cancelled = true\n }\n }, [emulator, tableId, history.length])\n\n return result\n}\n","import { useMemo } from \"react\"\n\nimport type { GristReplicaColumn, GristReplicaDocument, GristReplicaTable } from \"../../sdk/replica-document\"\nimport { isGristNoiseColumn } from \"../../sdk/helpers/grist-columns-filters\"\nimport type { GristEmulator } from \"../create-grist-emulator\"\nimport { useEmulatorSnapshot } from \"./use-emulator-state\"\n\nexport type EmulatorColumnsTableView = GristReplicaTable & { tableId: string }\n\nexport type UseEmulatorColumnsResult = {\n document: GristReplicaDocument\n table: EmulatorColumnsTableView | null\n isNoiseColumnId: (colId: string, col?: GristReplicaColumn) => boolean\n sortColumnIds: (colIds: string[], columns: Record<string, GristReplicaColumn>) => string[]\n}\n\nexport function useEmulatorColumns(emulator: GristEmulator): UseEmulatorColumnsResult {\n const { state } = useEmulatorSnapshot(emulator)\n const requestedTableId = state.selection.tableId\n\n const document = useMemo<GristReplicaDocument>(() => {\n const tables: Record<string, GristReplicaTable> = {}\n for (const [tableId, table] of state.tables.entries()) {\n const filteredColumns = Object.fromEntries(\n Object.entries(table.columns).filter(([colId, col]) => {\n return !isGristNoiseColumn(colId, col, {\n excludeId: true,\n excludeGristHelpers: true,\n excludeLoggingColumns: true,\n excludeManualSort: true,\n })\n })\n )\n tables[tableId] = {\n label: table.label,\n columns: filteredColumns,\n rows: table.rows.map((row) => ({ ...row })),\n rowCount: table.rows.length,\n }\n }\n return {\n generatedAt: new Date().toISOString(),\n docName: state.docName,\n mode: \"schema+data\",\n source: \"emulator-devtools\",\n tables,\n }\n }, [state])\n\n const table = useMemo<EmulatorColumnsTableView | null>(() => {\n if (!requestedTableId) return null\n const slice = document.tables[requestedTableId]\n if (!slice) return null\n return { tableId: requestedTableId, ...slice }\n }, [document, requestedTableId])\n\n const isNoiseColumnId = useMemo(\n () =>\n (colId: string, col?: GristReplicaColumn): boolean =>\n isGristNoiseColumn(colId, col, {\n excludeId: true,\n excludeGristHelpers: true,\n excludeLoggingColumns: true,\n excludeManualSort: true,\n }),\n []\n )\n\n const sortColumnIds = useMemo(\n () => (colIds: string[], columns: Record<string, GristReplicaColumn>): string[] => {\n return [...colIds].sort((a, b) => {\n const la = (columns[a]?.label || a).toLowerCase()\n const lb = (columns[b]?.label || b).toLowerCase()\n if (la !== lb) return la.localeCompare(lb)\n return a.localeCompare(b)\n })\n },\n []\n )\n\n return { document, table, isNoiseColumnId, sortColumnIds }\n}\n"],"mappings":"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","names":["useState","useState","table"]}