grist-widget-sdk 0.4.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +47 -0
- package/README.md +79 -208
- package/dist/app.cjs +186 -65
- package/dist/app.cjs.map +1 -1
- package/dist/app.d.cts +5 -100
- package/dist/app.d.ts +5 -100
- package/dist/app.js +4 -2
- package/dist/{chunk-O7NY46QY.js → chunk-MAPAWVQC.js} +88 -20
- package/dist/chunk-MAPAWVQC.js.map +1 -0
- package/dist/{chunk-B5ZZNLVS.js → chunk-OXA2VITC.js} +5 -1
- package/dist/chunk-OXA2VITC.js.map +1 -0
- package/dist/{chunk-P6VTEKWO.js → chunk-P5I5MRC6.js} +86 -10
- package/dist/chunk-P5I5MRC6.js.map +1 -0
- package/dist/{use-grist-BK0eke9K.d.cts → define-widget-B1FIvI-h.d.cts} +179 -104
- package/dist/{use-grist-C5DMZ3wU.d.ts → define-widget-B9gEtJP0.d.ts} +179 -104
- package/dist/emulator/testing.cjs +2393 -2243
- package/dist/emulator/testing.cjs.map +1 -1
- package/dist/emulator/testing.d.cts +27 -9
- package/dist/emulator/testing.d.ts +27 -9
- package/dist/emulator/testing.js +75 -55
- package/dist/emulator/testing.js.map +1 -1
- package/dist/emulator.cjs +4 -0
- package/dist/emulator.cjs.map +1 -1
- package/dist/emulator.d.cts +3 -3
- package/dist/emulator.d.ts +3 -3
- package/dist/emulator.js +1 -1
- package/dist/index.cjs +133 -67
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +5 -1
- package/dist/mount-grist-widget-CkB-3iG_.d.ts +137 -0
- package/dist/mount-grist-widget-Dtelqao_.d.cts +137 -0
- package/package.json +1 -1
- package/dist/chunk-B5ZZNLVS.js.map +0 -1
- package/dist/chunk-O7NY46QY.js.map +0 -1
- package/dist/chunk-P6VTEKWO.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/emulator/core/mappings.ts","../src/emulator/core/display-helpers.ts","../src/emulator/core/document.ts","../src/emulator/core/action-engine.ts","../src/emulator/validators.ts","../src/emulator/api/command-api.ts","../src/emulator/api/custom-section-api.ts","../src/emulator/api/grist-api.ts","../src/emulator/core/columnar.ts","../src/emulator/api/grist-doc-api.ts","../src/emulator/api/grist-view.ts","../src/emulator/api/widget-api.ts","../src/emulator/api/index.ts","../src/emulator/core/event-bus.ts","../src/emulator/theme-message.ts","../src/emulator/transports/inline.ts","../src/emulator/create-grist-emulator.ts","../src/emulator/templates.ts"],"sourcesContent":["/**\n * Resolves the `mappings` payload that `CustomSectionAPI.mappings()` returns.\n *\n * The emulator does **not** infer logical → real columns from names, as\n * real Grist doesn't: mappings come only from `state.selection.mappings`\n * (a test's `emulator.setColumnMappings(...)`). When unset, returns `null`.\n */\n\nimport type { GristWidgetColumnMap } from \"../../sdk/types\"\nimport type { EmulatorDocumentState } from \"./types\"\n\nexport function resolveMappings(state: EmulatorDocumentState): GristWidgetColumnMap | null {\n if (state.selection.mappings !== undefined && state.selection.mappings !== null) {\n return state.selection.mappings\n }\n return null\n}\n","import type { GristReplicaColumn } from \"../../sdk/types\"\n\n/** Ref / RefList column → the gristHelper_ column holding its display values. */\nexport function inferDisplayHelpersByRef(\n columns: Record<string, GristReplicaColumn>\n): Record<string, string> {\n const out: Record<string, string> = {}\n const helperColumns = Object.entries(columns).filter(([colId]) =>\n colId.startsWith(\"gristHelper_\")\n )\n const usedHelpers = new Set<string>()\n const colRefToColId = new Map<number, string>()\n for (const [colId, col] of Object.entries(columns)) {\n if (typeof col?.colRef === \"number\" && Number.isFinite(col.colRef)) {\n colRefToColId.set(col.colRef, colId)\n }\n }\n for (const [colId, col] of Object.entries(columns)) {\n const type = col?.type\n if (typeof type !== \"string\" || (!type.startsWith(\"Ref:\") && !type.startsWith(\"RefList:\"))) {\n continue\n }\n if (typeof col.displayColRef === \"number\" && Number.isFinite(col.displayColRef)) {\n const helperColId = colRefToColId.get(col.displayColRef)\n if (helperColId) {\n out[colId] = helperColId\n usedHelpers.add(helperColId)\n continue\n }\n }\n const match = helperColumns.find(([, helper]) => {\n const formula = helper?.formula\n return typeof formula === \"string\" && (formula.includes(`$${colId}.`) || formula.includes(`$${colId}`))\n })\n if (match) {\n out[colId] = match[0]\n usedHelpers.add(match[0])\n }\n }\n\n // Secondary fallback for schemas where helper formulas are unavailable:\n // pair unresolved Ref/RefList columns with nearest following gristHelper_*.\n const unresolvedRefs = Object.entries(columns)\n .filter(([colId, col]) => {\n const type = col?.type\n return (\n !out[colId] &&\n typeof type === \"string\" &&\n (type.startsWith(\"Ref:\") || type.startsWith(\"RefList:\"))\n )\n })\n .sort((a, b) => (a[1]?.parentPos ?? Number.MAX_SAFE_INTEGER) - (b[1]?.parentPos ?? Number.MAX_SAFE_INTEGER))\n const helperByPos = helperColumns\n .filter(([helperId]) => !usedHelpers.has(helperId))\n .sort((a, b) => (a[1]?.parentPos ?? Number.MAX_SAFE_INTEGER) - (b[1]?.parentPos ?? Number.MAX_SAFE_INTEGER))\n for (const [refId, refCol] of unresolvedRefs) {\n const refPos = refCol?.parentPos ?? Number.MAX_SAFE_INTEGER\n const candidate = helperByPos.find(([, helperCol]) => {\n const helperPos = helperCol?.parentPos ?? Number.MAX_SAFE_INTEGER\n return helperPos > refPos\n })\n if (!candidate) continue\n out[refId] = candidate[0]\n usedHelpers.add(candidate[0])\n }\n // If multiple unresolved refs remain, greedily map by order.\n for (const [refId] of unresolvedRefs) {\n if (out[refId]) continue\n const candidate = helperByPos.find(([helperId]) => !usedHelpers.has(helperId))\n if (!candidate) continue\n out[refId] = candidate[0]\n usedHelpers.add(candidate[0])\n }\n return out\n}\n","import { inferDisplayHelpersByRef } from \"./display-helpers\"\nimport { normalizeReplicaDocumentInput } from \"../../sdk/helpers/replica-normalize\"\nimport { coerceGristDocApiRefRowId } from \"../../sdk/helpers/grist-value-codec\"\nimport type { GristReplicaDocument, GristReplicaTable } from \"../../sdk/replica-document\"\nimport type { GristRowRecord } from \"../../sdk/types\"\nimport type { EmulatorColumn, EmulatorDocumentState, EmulatorTable } from \"./types\"\n\nconst SYSTEM_COLUMN = \"id\"\n\nconst EMULATOR_JS_FORMULA_PLACEHOLDER = \"(emulator JavaScript formula)\"\n\n/** Replica table for {@link createDocument}; columns may include `formulaFn` / `inferredFormula` (emulator-only). */\nexport type CreateDocumentTableInput = Omit<GristReplicaTable, \"columns\"> & {\n columns?: Record<string, EmulatorColumn>\n}\n\n/** Replica document for {@link createDocument}; widens table columns to {@link EmulatorColumn}. */\nexport type CreateDocumentInput = Omit<GristReplicaDocument, \"tables\"> & {\n tables: Record<string, CreateDocumentTableInput>\n}\n\n/**\n * Ensure `formula` (original) and `inferredFormula` strings exist alongside optional `formulaFn`.\n */\nexport function enrichEmulatorColumnMetadata(col: EmulatorColumn): EmulatorColumn {\n const originalTrimmed = col.formula?.trim() ?? \"\"\n const explicitInferred = col.inferredFormula?.trim() ?? \"\"\n\n if (col.formulaFn) {\n const inferredFormula =\n explicitInferred || originalTrimmed || EMULATOR_JS_FORMULA_PLACEHOLDER\n return {\n ...col,\n ...(originalTrimmed ? { formula: col.formula } : {}),\n inferredFormula,\n }\n }\n\n if (explicitInferred || originalTrimmed) {\n return {\n ...col,\n inferredFormula: explicitInferred || originalTrimmed || undefined,\n }\n }\n\n return col\n}\n\n/** Order merged column metadata for stable `fetchTable` / RDG column order. */\nexport function sortEmulatorColumnsByParentPos(columns: Record<string, EmulatorColumn>): Record<string, EmulatorColumn> {\n const entries = Object.entries(columns)\n entries.sort(([ka, a], [kb, b]) => {\n const pa = a.parentPos\n const pb = b.parentPos\n if (pa !== undefined && pb !== undefined && pa !== pb) return pa - pb\n if (pa !== undefined && pb === undefined) return -1\n if (pa === undefined && pb !== undefined) return 1\n return ka.localeCompare(kb)\n })\n return Object.fromEntries(entries)\n}\n\nfunction inferColumnsFromRows(rows: GristRowRecord[]): Record<string, EmulatorColumn> {\n const columns: Record<string, EmulatorColumn> = {}\n for (const row of rows) {\n for (const key of Object.keys(row)) {\n if (key === SYSTEM_COLUMN) continue\n if (!columns[key]) columns[key] = inferColumnType(row[key])\n }\n }\n return columns\n}\n\nfunction inferColumnType(sample: unknown): EmulatorColumn {\n switch (typeof sample) {\n case \"number\":\n return { type: \"Numeric\" }\n case \"boolean\":\n return { type: \"Bool\" }\n case \"string\":\n return { type: \"Text\" }\n default:\n return { type: \"Any\" }\n }\n}\n\nfunction buildTable(tableId: string, input: CreateDocumentTableInput): EmulatorTable {\n const rows = input.rows ?? []\n const inferred = inferColumnsFromRows(rows)\n const merged: Record<string, EmulatorColumn> = {}\n for (const [colId, col] of Object.entries({ ...inferred, ...(input.columns ?? {}) })) {\n merged[colId] = enrichEmulatorColumnMetadata(col)\n }\n const columns = sortEmulatorColumnsByParentPos(merged)\n return {\n tableId,\n label: input.label,\n columns,\n rows: rows.map((row) => ({ ...row })),\n }\n}\n\n/**\n * Build an immutable initial document state from a user-provided\n * {@link GristReplicaDocument}. The state is **not** frozen — the action\n * engine mutates it in place under deterministic event diffusion.\n */\nexport function createDocument(input: CreateDocumentInput): EmulatorDocumentState {\n if (!input.tables || Object.keys(input.tables).length === 0) {\n throw new Error(\"createDocument: at least one table is required\")\n }\n\n const normalized = normalizeReplicaDocumentInput(input)\n\n const tables = new Map<string, EmulatorTable>()\n for (const [tableId, tableInput] of Object.entries(normalized.tables)) {\n tables.set(tableId, buildTable(tableId, tableInput))\n }\n\n const firstTableId = tables.keys().next().value as string\n const requestedTableId = normalized.selection?.tableId\n const selectedTableId =\n requestedTableId && tables.has(requestedTableId) ? requestedTableId : firstTableId\n const selectedTable = tables.get(selectedTableId)!\n const fallbackRowId =\n typeof selectedTable.rows[0]?.id === \"number\" ? selectedTable.rows[0].id : null\n const selection = {\n tableId: selectedTableId,\n rowId: normalized.selection?.rowId ?? fallbackRowId,\n mappings: normalized.selection?.mappings,\n cursor: normalized.selection?.cursor,\n } as EmulatorDocumentState[\"selection\"]\n\n return {\n docName: normalized.docName ?? \"Untitled emulator document\",\n tables,\n selection,\n widgetOptions: { ...(normalized.widgetOptions ?? {}) },\n widgetInteraction: { ...(normalized.widgetInteraction ?? {}) },\n configuration: normalized.configuration ?? null,\n accessToken: normalized.accessToken ?? null,\n }\n}\n\nexport function getTable(state: EmulatorDocumentState, tableId: string): EmulatorTable {\n const table = state.tables.get(tableId)\n if (!table) throw new Error(`Unknown table: ${tableId}`)\n return table\n}\n\nexport function getSelectedTable(state: EmulatorDocumentState): EmulatorTable {\n return getTable(state, state.selection.tableId)\n}\n\nexport function nextRowId(table: EmulatorTable): number {\n let max = 0\n for (const row of table.rows) {\n if (typeof row.id === \"number\" && row.id > max) max = row.id\n }\n return max + 1\n}\n\nexport function findRow(table: EmulatorTable, rowId: number): GristRowRecord | undefined {\n return table.rows.find((r) => r.id === rowId)\n}\n\nexport function findRowIndex(table: EmulatorTable, rowId: number): number {\n return table.rows.findIndex((r) => r.id === rowId)\n}\n\n/**\n * Re-evaluate every formula column for a given row in-place. Called by the\n * action engine after Add/Update operations.\n */\nexport function evaluateRowFormulas(\n state: EmulatorDocumentState,\n table: EmulatorTable,\n row: GristRowRecord\n): void {\n for (const [colId, col] of Object.entries(table.columns)) {\n if (col.formulaFn) {\n try {\n row[colId] = col.formulaFn(row, { table, document: state })\n } catch (err) {\n row[colId] = formulaError(err)\n }\n }\n }\n}\n\nfunction escapeRegExp(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")\n}\n\n/** Pull stored row ids from a `RefList` cell (`[\"L\", ...]` or legacy shapes). */\nfunction extractRefListIdsFromWire(raw: unknown): number[] {\n if (raw == null) return []\n if (!Array.isArray(raw)) return []\n const items = raw[0] === \"L\" ? raw.slice(1) : raw\n const out: number[] = []\n for (const item of items) {\n if (typeof item === \"number\" && Number.isFinite(item) && item > 0) {\n out.push(Math.trunc(item))\n continue\n }\n if (item && typeof item === \"object\" && \"rowId\" in item) {\n const r = (item as { rowId: unknown }).rowId\n if (typeof r === \"number\" && Number.isFinite(r) && r > 0) {\n out.push(Math.trunc(r))\n continue\n }\n }\n const t = coerceGristDocApiRefRowId(item)\n if (t !== undefined && t > 0) out.push(Math.trunc(t))\n }\n return Array.from(new Set(out))\n}\n\nfunction fieldFromRefListHelperFormula(formula: string | undefined, refColId: string): string | null {\n if (!formula) return null\n const re = new RegExp(`\\\\$${escapeRegExp(refColId)}\\\\.([A-Za-z_]\\\\w*)`)\n const m = formula.match(re)\n return m?.[1] ?? null\n}\n\nfunction firstTextLikeColumnId(columns: Record<string, EmulatorColumn>): string | null {\n let best: { id: string; pos: number } | null = null\n for (const [colId, col] of Object.entries(columns)) {\n if (colId === \"id\" || colId.startsWith(\"gristHelper_\")) continue\n const t = col.type\n if (t !== \"Text\" && t !== \"Choice\") continue\n const pos = col.parentPos ?? 99999\n if (!best || pos < best.pos) best = { id: colId, pos }\n }\n return best?.id ?? null\n}\n\nfunction formatLabelFromCell(value: unknown): string {\n if (value == null) return \"\"\n if (typeof value === \"string\") return value.trim()\n if (typeof value === \"number\" || typeof value === \"boolean\") return String(value)\n if (value instanceof Date) return value.toISOString()\n if (Array.isArray(value) && value[0] === \"E\") return \"\"\n if (typeof value === \"object\" && value && \"__ref\" in value) {\n const r = (value as { rowId?: unknown }).rowId\n return typeof r === \"number\" && Number.isFinite(r) ? String(r) : \"\"\n }\n return \"\"\n}\n\n/**\n * Keep `gristHelper_*` display columns aligned with `RefList:*` ids after writes.\n *\n * Real Grist evaluates helper formulas (`$multiref.Nom`); replica JSON only\n * carries the formula string (no `formulaFn`), so helpers would stay stale and\n * a widget reading them would see empty labels.\n *\n * Skips helpers that define `formulaFn` so custom JS formulas keep ownership.\n */\nexport function syncRefListDisplayHelpers(\n state: EmulatorDocumentState,\n table: EmulatorTable,\n row: GristRowRecord\n): void {\n const displayHelpersByRef = inferDisplayHelpersByRef(table.columns)\n for (const [colId, col] of Object.entries(table.columns)) {\n const type = col.type\n if (typeof type !== \"string\" || !type.startsWith(\"RefList:\")) continue\n const helperColId = displayHelpersByRef[colId]\n if (!helperColId) continue\n const helperMeta = table.columns[helperColId]\n if (!helperMeta || helperMeta.formulaFn) continue\n\n const targetTableId = type.slice(\"RefList:\".length)\n const targetTable = state.tables.get(targetTableId)\n if (!targetTable) continue\n\n const ids = extractRefListIdsFromWire(row[colId])\n if (ids.length === 0) {\n row[helperColId] = []\n continue\n }\n\n const fieldId =\n fieldFromRefListHelperFormula(helperMeta.formula, colId) ??\n firstTextLikeColumnId(targetTable.columns)\n\n const labels = ids.map((rid) => {\n if (!fieldId) return String(rid)\n const trow = findRow(targetTable, rid)\n if (!trow) return String(rid)\n const lbl = formatLabelFromCell(trow[fieldId])\n return lbl !== \"\" ? lbl : String(rid)\n })\n row[helperColId] = labels\n }\n}\n\nfunction formulaError(err: unknown): unknown {\n // Match Grist's encoded error format: [\"E\", code, message]\n const message = err instanceof Error ? err.message : String(err)\n return [\"E\", \"Error\", message]\n}\n\n/**\n * Synthesise `_grist_Tables` metadata from the emulator's in-memory tables.\n * Returns Grist's columnar wire shape.\n */\nexport function synthesizeTablesMeta(state: EmulatorDocumentState): Record<string, unknown[]> {\n const ids: number[] = []\n const tableIds: string[] = []\n const labels: (string | null)[] = []\n\n let nextId = 1\n for (const [tableId, table] of state.tables.entries()) {\n ids.push(nextId)\n tableIds.push(tableId)\n labels.push(table.label ?? null)\n nextId += 1\n }\n\n return {\n id: ids,\n tableId: tableIds,\n // Optional human-readable label; real Grist keeps more fields, but these\n // are sufficient for `buildReplicaDocumentFromDocApi` to resolve table ids.\n label: labels,\n }\n}\n\n/**\n * Synthesise `_grist_Tables_column` metadata from emulator tables/columns.\n * Mirrors the subset of fields consumed by `buildReplicaDocumentFromDocApi`.\n */\nexport function synthesizeTablesColumnMeta(state: EmulatorDocumentState): Record<string, unknown[]> {\n const parentIds: number[] = []\n const colIds: string[] = []\n const columnIds: number[] = []\n const types: (string | null)[] = []\n const labels: (string | null)[] = []\n const parentPos: (number | null)[] = []\n const isFormula: boolean[] = []\n const formulas: (string | null)[] = []\n const descriptions: (string | null)[] = []\n const widgetOptions: unknown[] = []\n const displayCol: (number | null)[] = []\n const visibleCol: (number | null)[] = []\n\n // Mirror the synthetic table ids from `synthesizeTablesMeta`.\n const tableIdToInternalId = new Map<string, number>()\n {\n let nextId = 1\n for (const [tableId] of state.tables.entries()) {\n tableIdToInternalId.set(tableId, nextId)\n nextId += 1\n }\n }\n\n for (const [tableId, table] of state.tables.entries()) {\n const parentInternalId = tableIdToInternalId.get(tableId)\n if (parentInternalId === undefined) continue\n\n for (const [colId, col] of Object.entries(table.columns)) {\n parentIds.push(parentInternalId)\n colIds.push(colId)\n // Prefer explicit `colRef` when present; fall back to 1-based index of insertion.\n const ref = typeof col.colRef === \"number\" ? col.colRef : columnIds.length + 1\n columnIds.push(ref)\n types.push(col.type ?? null)\n labels.push(col.label ?? null)\n parentPos.push(col.parentPos ?? null)\n isFormula.push(Boolean(col.isFormula))\n const formula = typeof col.formula === \"string\" ? col.formula : null\n formulas.push(formula)\n descriptions.push(col.description ?? null)\n widgetOptions.push(col.widgetOptions ?? null)\n displayCol.push(typeof col.displayColRef === \"number\" ? col.displayColRef : null)\n visibleCol.push(typeof col.visibleColRef === \"number\" ? col.visibleColRef : null)\n }\n }\n\n return {\n parentId: parentIds,\n colId: colIds,\n id: columnIds,\n type: types,\n label: labels,\n parentPos,\n isFormula,\n formula: formulas,\n description: descriptions,\n // Also expose legacy `descr` for robustness.\n descr: descriptions,\n widgetOptions,\n displayCol,\n visibleCol,\n }\n}\n","/**\n * Pure action engine: applies Grist user actions to an\n * {@link EmulatorDocumentState} and emits the resulting events on the bus.\n *\n * This is the single place where state mutates. Every API impl ultimately\n * routes through `applyUserActions` so behaviour is consistent regardless of\n * the surface (`grist.docApi.applyUserActions`, `selectedTable.create`,\n * `setCursorPos`, etc.).\n *\n * Supported user actions:\n * - AddRecord, BulkAddRecord\n * - UpdateRecord, BulkUpdateRecord\n * - RemoveRecord, BulkRemoveRecord\n * - AddColumn, RemoveColumn, RenameColumn, ModifyColumn\n * - AddTable, RemoveTable, RenameTable\n *\n * Unknown actions throw a structured error instead of silently succeeding,\n * which surfaces protocol gaps loudly during widget development.\n */\n\nimport { coerceGristDocApiRefRowId } from \"../../sdk/helpers/grist-value-codec\"\nimport {\n evaluateRowFormulas,\n findRow,\n findRowIndex,\n getTable,\n nextRowId,\n syncRefListDisplayHelpers,\n} from \"./document\"\nimport type { EventBus } from \"./event-bus\"\nimport type { EmulatorColumn, EmulatorDocumentState, EmulatorTable } from \"./types\"\n\nexport class EmulatorActionError extends Error {\n constructor(\n public readonly action: unknown,\n message: string\n ) {\n super(message)\n this.name = \"EmulatorActionError\"\n }\n}\n\nexport type ApplyUserActionResult = {\n /** Result mirroring Grist's `applyUserActions`: per-action retValues. */\n retValues: unknown[]\n /** Tables that received row-level changes (de-duped). */\n changedTableIds: string[]\n}\n\nexport function applyUserActions(\n state: EmulatorDocumentState,\n bus: EventBus,\n actions: unknown[][]\n): ApplyUserActionResult {\n const retValues: unknown[] = []\n const changed = new Set<string>()\n\n for (const action of actions) {\n bus.emit({ type: \"user-action\", action })\n const ret = applySingle(state, action, changed)\n retValues.push(ret)\n }\n\n for (const tableId of changed) {\n bus.emit({ type: \"data-change\", tableId })\n }\n\n return { retValues, changedTableIds: [...changed] }\n}\n\nfunction applySingle(\n state: EmulatorDocumentState,\n action: unknown[],\n changed: Set<string>\n): unknown {\n const [name, ...args] = action\n switch (name) {\n case \"AddRecord\":\n return addRecord(state, args, changed)\n case \"BulkAddRecord\":\n return bulkAddRecord(state, args, changed)\n case \"UpdateRecord\":\n return updateRecord(state, args, changed)\n case \"BulkUpdateRecord\":\n return bulkUpdateRecord(state, args, changed)\n case \"RemoveRecord\":\n return removeRecord(state, args, changed)\n case \"BulkRemoveRecord\":\n return bulkRemoveRecord(state, args, changed)\n case \"AddColumn\":\n return addColumn(state, args)\n case \"AddVisibleColumn\":\n // The emulator has no concept of section view fields, so the \"visible\"\n // part of `AddVisibleColumn` is a no-op here. We still create the\n // column so widgets that issue this user action (the higher-level form\n // recommended by Grist for \"add a column to the active view\") work\n // identically against the emulator.\n return addColumn(state, args)\n case \"RemoveColumn\":\n return removeColumn(state, args, changed)\n case \"RenameColumn\":\n return renameColumn(state, args, changed)\n case \"ModifyColumn\":\n return modifyColumn(state, args, changed)\n case \"AddTable\":\n return addTable(state, args)\n case \"RemoveTable\":\n return removeTable(state, args)\n case \"RenameTable\":\n return renameTable(state, args)\n default:\n throw new EmulatorActionError(action, `Unsupported user action: ${String(name)}`)\n }\n}\n\n// ---------- row ops ----------\n\nfunction addRecord(\n state: EmulatorDocumentState,\n [tableId, rowId, values]: unknown[],\n changed: Set<string>\n): number {\n const table = getTable(state, requireString(tableId, \"AddRecord.tableId\"))\n const id = typeof rowId === \"number\" ? rowId : nextRowId(table)\n const normalizedValues = normalizeValuesForTable(\n table,\n (values as Record<string, unknown>) ?? {}\n )\n const row = { id, ...normalizedValues }\n ensureColumns(table, normalizedValues)\n evaluateRowFormulas(state, table, row)\n syncRefListDisplayHelpers(state, table, row)\n table.rows.push(row)\n changed.add(table.tableId)\n return id\n}\n\nfunction bulkAddRecord(\n state: EmulatorDocumentState,\n [tableId, rowIds, columnar]: unknown[],\n changed: Set<string>\n): number[] {\n const table = getTable(state, requireString(tableId, \"BulkAddRecord.tableId\"))\n const cols = normalizeColumnarForTable(\n table,\n (columnar as Record<string, unknown[]>) ?? {}\n )\n const ids = Array.isArray(rowIds) ? rowIds : []\n const length = ids.length || lengthOf(cols)\n const out: number[] = []\n ensureColumns(table, cols, true)\n for (let i = 0; i < length; i++) {\n const id = typeof ids[i] === \"number\" ? (ids[i] as number) : nextRowId(table)\n const row: Record<string, unknown> & { id: number } = { id }\n for (const colId of Object.keys(cols)) row[colId] = cols[colId][i]\n evaluateRowFormulas(state, table, row)\n syncRefListDisplayHelpers(state, table, row)\n table.rows.push(row)\n out.push(id)\n }\n changed.add(table.tableId)\n return out\n}\n\nfunction updateRecord(\n state: EmulatorDocumentState,\n [tableId, rowId, values]: unknown[],\n changed: Set<string>\n): null {\n const table = getTable(state, requireString(tableId, \"UpdateRecord.tableId\"))\n const id = requireNumber(rowId, \"UpdateRecord.rowId\")\n const row = findRow(table, id)\n if (!row) throw new EmulatorActionError([\"UpdateRecord\", tableId, rowId, values], `Row ${id} not found in ${table.tableId}`)\n const normalizedValues = normalizeValuesForTable(\n table,\n (values as Record<string, unknown>) ?? {}\n )\n ensureColumns(table, normalizedValues)\n Object.assign(row, normalizedValues)\n evaluateRowFormulas(state, table, row)\n syncRefListDisplayHelpers(state, table, row)\n changed.add(table.tableId)\n return null\n}\n\nfunction bulkUpdateRecord(\n state: EmulatorDocumentState,\n [tableId, rowIds, columnar]: unknown[],\n changed: Set<string>\n): null {\n const table = getTable(state, requireString(tableId, \"BulkUpdateRecord.tableId\"))\n const ids = rowIds as number[]\n const cols = normalizeColumnarForTable(\n table,\n (columnar as Record<string, unknown[]>) ?? {}\n )\n ensureColumns(table, cols, true)\n ids.forEach((id, idx) => {\n const row = findRow(table, id)\n if (!row) throw new EmulatorActionError([\"BulkUpdateRecord\", tableId, ids, cols], `Row ${id} not found in ${table.tableId}`)\n for (const colId of Object.keys(cols)) row[colId] = cols[colId][idx]\n evaluateRowFormulas(state, table, row)\n syncRefListDisplayHelpers(state, table, row)\n })\n changed.add(table.tableId)\n return null\n}\n\nfunction removeRecord(\n state: EmulatorDocumentState,\n [tableId, rowId]: unknown[],\n changed: Set<string>\n): null {\n const table = getTable(state, requireString(tableId, \"RemoveRecord.tableId\"))\n const id = requireNumber(rowId, \"RemoveRecord.rowId\")\n const idx = findRowIndex(table, id)\n if (idx >= 0) table.rows.splice(idx, 1)\n if (state.selection.tableId === table.tableId && state.selection.rowId === id) {\n state.selection.rowId = table.rows[0]?.id ?? null\n }\n changed.add(table.tableId)\n return null\n}\n\nfunction bulkRemoveRecord(\n state: EmulatorDocumentState,\n [tableId, rowIds]: unknown[],\n changed: Set<string>\n): null {\n const table = getTable(state, requireString(tableId, \"BulkRemoveRecord.tableId\"))\n const ids = new Set(rowIds as number[])\n table.rows = table.rows.filter((r) => !ids.has(r.id))\n if (state.selection.tableId === table.tableId && typeof state.selection.rowId === \"number\" && ids.has(state.selection.rowId)) {\n state.selection.rowId = table.rows[0]?.id ?? null\n }\n changed.add(table.tableId)\n return null\n}\n\n// ---------- column ops ----------\n\nfunction addColumn(\n state: EmulatorDocumentState,\n [tableId, colId, info]: unknown[]\n): null {\n const table = getTable(state, requireString(tableId, \"AddColumn.tableId\"))\n const col = requireString(colId, \"AddColumn.colId\")\n if (table.columns[col]) throw new EmulatorActionError([\"AddColumn\", tableId, colId], `Column ${col} already exists`)\n table.columns[col] = (info as EmulatorColumn) ?? {}\n for (const row of table.rows) {\n if (!(col in row)) row[col] = null\n }\n return null\n}\n\nfunction removeColumn(\n state: EmulatorDocumentState,\n [tableId, colId]: unknown[],\n changed: Set<string>\n): null {\n const table = getTable(state, requireString(tableId, \"RemoveColumn.tableId\"))\n const col = requireString(colId, \"RemoveColumn.colId\")\n delete table.columns[col]\n for (const row of table.rows) delete row[col]\n changed.add(table.tableId)\n return null\n}\n\nfunction renameColumn(\n state: EmulatorDocumentState,\n [tableId, colId, newColId]: unknown[],\n changed: Set<string>\n): null {\n const table = getTable(state, requireString(tableId, \"RenameColumn.tableId\"))\n const from = requireString(colId, \"RenameColumn.colId\")\n const to = requireString(newColId, \"RenameColumn.newColId\")\n if (!table.columns[from]) throw new EmulatorActionError([\"RenameColumn\", tableId, from, to], `Column ${from} not found`)\n if (from === to) return null\n table.columns[to] = table.columns[from]\n delete table.columns[from]\n for (const row of table.rows) {\n if (from in row) {\n row[to] = row[from]\n delete row[from]\n }\n }\n changed.add(table.tableId)\n return null\n}\n\nfunction modifyColumn(\n state: EmulatorDocumentState,\n [tableId, colId, info]: unknown[],\n changed: Set<string>\n): null {\n const table = getTable(state, requireString(tableId, \"ModifyColumn.tableId\"))\n const col = requireString(colId, \"ModifyColumn.colId\")\n if (!table.columns[col]) throw new EmulatorActionError([\"ModifyColumn\", tableId, colId], `Column ${col} not found`)\n table.columns[col] = { ...table.columns[col], ...(info as EmulatorColumn) }\n changed.add(table.tableId)\n return null\n}\n\n// ---------- table ops ----------\n\nfunction addTable(state: EmulatorDocumentState, [tableId, columns]: unknown[]): string {\n const id = requireString(tableId, \"AddTable.tableId\")\n if (state.tables.has(id)) throw new EmulatorActionError([\"AddTable\", tableId], `Table ${id} already exists`)\n const cols: Record<string, EmulatorColumn> = {}\n for (const c of (columns as Array<{ id: string } & EmulatorColumn>) ?? []) {\n cols[c.id] = { ...c }\n }\n state.tables.set(id, { tableId: id, columns: cols, rows: [] })\n return id\n}\n\nfunction removeTable(state: EmulatorDocumentState, [tableId]: unknown[]): null {\n const id = requireString(tableId, \"RemoveTable.tableId\")\n state.tables.delete(id)\n if (state.selection.tableId === id) {\n const fallback = state.tables.keys().next().value as string | undefined\n if (fallback) {\n state.selection.tableId = fallback\n state.selection.rowId = null\n }\n }\n return null\n}\n\nfunction renameTable(state: EmulatorDocumentState, [from, to]: unknown[]): null {\n const fromId = requireString(from, \"RenameTable.from\")\n const toId = requireString(to, \"RenameTable.to\")\n const table = state.tables.get(fromId)\n if (!table) throw new EmulatorActionError([\"RenameTable\", fromId], `Table ${fromId} not found`)\n state.tables.delete(fromId)\n table.tableId = toId\n state.tables.set(toId, table)\n if (state.selection.tableId === fromId) state.selection.tableId = toId\n return null\n}\n\n// ---------- helpers ----------\n\nfunction ensureColumns(\n table: EmulatorTable,\n values: Record<string, unknown> | Record<string, unknown[]>,\n bulk = false\n): void {\n for (const col of Object.keys(values)) {\n if (!table.columns[col]) {\n const sample = bulk ? (values as Record<string, unknown[]>)[col]?.[0] : (values as Record<string, unknown>)[col]\n table.columns[col] = inferType(sample)\n }\n }\n}\n\nfunction inferType(sample: unknown): EmulatorColumn {\n switch (typeof sample) {\n case \"number\":\n return { type: \"Numeric\" }\n case \"boolean\":\n return { type: \"Bool\" }\n case \"string\":\n return { type: \"Text\" }\n default:\n return { type: \"Any\" }\n }\n}\n\nfunction lengthOf(cols: Record<string, unknown[]>): number {\n for (const arr of Object.values(cols)) if (Array.isArray(arr)) return arr.length\n return 0\n}\n\nfunction requireString(value: unknown, name: string): string {\n if (typeof value !== \"string\" || !value) throw new Error(`Expected non-empty string for ${name}`)\n return value\n}\n\nfunction requireNumber(value: unknown, name: string): number {\n if (typeof value !== \"number\" || Number.isNaN(value)) throw new Error(`Expected number for ${name}`)\n return value\n}\n\nfunction normalizeValuesForTable(\n table: EmulatorTable,\n values: Record<string, unknown>\n): Record<string, unknown> {\n const out: Record<string, unknown> = {}\n for (const [colId, value] of Object.entries(values)) {\n out[colId] = normalizeCellValueForType(value, table.columns[colId]?.type)\n }\n return out\n}\n\nfunction normalizeColumnarForTable(\n table: EmulatorTable,\n columns: Record<string, unknown[]>\n): Record<string, unknown[]> {\n const out: Record<string, unknown[]> = {}\n for (const [colId, values] of Object.entries(columns)) {\n const type = table.columns[colId]?.type\n out[colId] = Array.isArray(values)\n ? values.map((value) => normalizeCellValueForType(value, type))\n : []\n }\n return out\n}\n\nfunction normalizeCellValueForType(value: unknown, type: string | undefined): unknown {\n if (value === null || value === undefined || typeof type !== \"string\") return value\n\n // As Grist does (checked in 1.7.22): a list column takes `[\"L\", ...]`; a\n // bare array written to it is stored as an error cell, not as the list.\n if (isListColumnType(type) && Array.isArray(value) && value[0] !== \"L\") return [\"E\", \"KeyError\"]\n if (type.startsWith(\"Ref:\")) return normalizeRefValue(value)\n if (type.startsWith(\"RefList:\")) return normalizeRefListValue(value)\n return value\n}\n\n/**\n * Canonical ref row id for emulator storage (`Ref:*` columns).\n * Accepts bare ids, `\"12\"`, Grist tuples `[\"r\", id]` / `[\"R\", tableId, id]`,\n * and detailed-ref shapes `{ rowId }` (decoded `Reference` values, grid edits).\n */\nfunction extractRefRowId(value: unknown): number | null {\n if (value === null || value === undefined) return null\n if (value && typeof value === \"object\" && \"__ref\" in value) {\n const inner = (value as { rowId?: unknown }).rowId\n return extractRefRowId(inner)\n }\n if (value && typeof value === \"object\" && \"rowId\" in value) {\n return extractRefRowId((value as { rowId: unknown }).rowId)\n }\n const fromTuple = coerceGristDocApiRefRowId(value)\n if (fromTuple !== undefined && fromTuple > 0) return Math.trunc(fromTuple)\n return toPositiveInt(value)\n}\n\nfunction isListColumnType(type: string): boolean {\n return type === \"ChoiceList\" || type === \"Attachments\" || type.startsWith(\"RefList:\")\n}\n\nfunction normalizeRefValue(value: unknown): number | null {\n return extractRefRowId(value)\n}\n\nfunction normalizeRefListValue(value: unknown): unknown[] {\n const toIdList = (items: unknown[]): number[] =>\n Array.from(\n new Set(items.map((item) => extractRefRowId(item)).filter((item): item is number => item !== null))\n )\n\n // Grist tuple form: [\"L\", ...ids]\n if (Array.isArray(value) && value[0] === \"L\") {\n return [\"L\", ...toIdList(value.slice(1))]\n }\n if (Array.isArray(value)) {\n return [\"L\", ...toIdList(value)]\n }\n if (typeof value === \"string\") {\n const tokens = value.split(\",\").map((t) => t.trim()).filter(Boolean)\n return [\"L\", ...toIdList(tokens)]\n }\n if (value && typeof value === \"object\" && Array.isArray((value as { rowIds?: unknown }).rowIds)) {\n return [\"L\", ...toIdList((value as { rowIds: unknown[] }).rowIds)]\n }\n return [\"L\"]\n}\n\nfunction toPositiveInt(value: unknown): number | null {\n if (typeof value === \"number\" && Number.isFinite(value) && value > 0) return Math.trunc(value)\n if (typeof value === \"string\") {\n const n = Number.parseInt(value.trim(), 10)\n if (Number.isFinite(n) && n > 0) return n\n }\n return null\n}\n","import { z } from \"zod\"\n\nimport type { GristReplicaDocument } from \"../sdk/replica-document\"\n\nconst emulatorRowSchema = z\n .object({ id: z.number() })\n .catchall(z.unknown())\n\nconst formulaKindSchema = z.enum([\"computed\", \"trigger\", \"none\", \"empty_slot\"])\n\nconst replicaColumnSchema = z\n .object({\n colRef: z.number().optional(),\n type: z.string().optional(),\n label: z.string().optional(),\n parentPos: z.number().optional(),\n isFormula: z.boolean().optional(),\n formulaKind: formulaKindSchema.optional(),\n formula: z.string().optional(),\n description: z.string().optional(),\n widgetOptions: z.record(z.string(), z.unknown()).optional(),\n displayColRef: z.number().optional(),\n visibleColRef: z.number().optional(),\n })\n .strict()\n\nconst replicaTableSchema = z\n .object({\n label: z.string().optional(),\n columns: z.record(z.string(), replicaColumnSchema).optional(),\n rows: z.array(emulatorRowSchema).optional(),\n rowCount: z.number().optional(),\n dataOmitted: z.boolean().optional(),\n dataOmittedReason: z.string().optional(),\n error: z.string().optional(),\n })\n .strict()\n\nconst replicaSelectionSchema = z\n .object({\n tableId: z.string().optional(),\n rowId: z.union([z.number(), z.literal(\"new\"), z.null()]).optional(),\n mappings: z.unknown().nullable().optional(),\n cursor: z.unknown().optional(),\n })\n .strict()\n\nconst replicaWidgetConfigurationSchema = z\n .object({\n requiredAccess: z.string().optional(),\n columns: z.unknown().optional(),\n allowSelectBy: z.boolean().optional(),\n hasCustomOptions: z.boolean().optional(),\n })\n .strict()\n\nconst replicaAccessTokenSchema = z\n .object({\n token: z.string(),\n baseUrl: z.string(),\n ttlMsecs: z.number(),\n })\n .strict()\n\nconst replicaDocumentSchema = z\n .object({\n generatedAt: z.string(),\n source: z.string().optional(),\n docName: z.string().optional(),\n mode: z.enum([\"schema-only\", \"schema+samples\", \"schema+data\"]).optional(),\n tables: z.record(z.string(), replicaTableSchema),\n selection: replicaSelectionSchema.optional(),\n widgetOptions: z.record(z.string(), z.unknown()).optional(),\n widgetInteraction: z.unknown().optional(),\n configuration: replicaWidgetConfigurationSchema.optional(),\n accessToken: replicaAccessTokenSchema.nullable().optional(),\n })\n .strict()\n .refine((value) => Object.keys(value.tables).length > 0, {\n message: \"at least one table is required\",\n path: [\"tables\"],\n })\n\nfunction formatZodError(prefix: string, error: z.ZodError): Error {\n const details = error.issues\n .map((issue) => {\n const where = issue.path.length > 0 ? issue.path.join(\".\") : \"<root>\"\n return `${where}: ${issue.message}`\n })\n .join(\"; \")\n return new Error(`${prefix}: ${details}`)\n}\n\nexport function safeParseDocument(input: unknown) {\n return replicaDocumentSchema.safeParse(input)\n}\n\nexport function parseDocument(input: unknown): GristReplicaDocument {\n const result = safeParseDocument(input)\n if (!result.success) {\n throw formatZodError(\"parseDocument\", result.error)\n }\n return result.data as GristReplicaDocument\n}\n","import type { EventBus } from \"../core/event-bus\"\nimport type { CommandApiImpl } from \"./types\"\n\n/**\n * `CommandAPI` host implementation. The widget's \"Edit Options\" gear and a\n * few keyboard shortcuts call into this. We forward the call name on the bus\n * so the inspector and tests can observe it; useful to assert\n * `onEditOptions` flows.\n */\nexport function createCommandApiImpl(bus: EventBus): CommandApiImpl {\n return {\n async run(name) {\n bus.emit({ type: \"user-action\", action: [\"RunCommand\", name] })\n },\n }\n}\n","import { resolveMappings } from \"../core/mappings\"\nimport type { EventBus } from \"../core/event-bus\"\nimport type { GristWidgetConfiguration } from \"../../sdk/types\"\nimport type { EmulatorDocumentState } from \"../core/types\"\nimport type { CustomSectionApiImpl } from \"./types\"\n\n/**\n * `CustomSectionAPI` host implementation, called by `grist-plugin-api.js`\n * after `grist.ready()` to hand the host the widget's preferences:\n * required access, declared columns, allowSelectBy, hasCustomOptions, etc.\n *\n * Implementation:\n * - persists the configuration onto `state.configuration`,\n * - emits a `ready` event so the transport knows it is safe to push\n * initial cursor / data / options messages,\n * - re-emits a `mappings-change` so the inspector and tests can react.\n */\nexport function createCustomSectionApiImpl(\n state: EmulatorDocumentState,\n bus: EventBus\n): CustomSectionApiImpl {\n return {\n async configure(settings) {\n const config: GristWidgetConfiguration = {\n requiredAccess: settings.requiredAccess as GristWidgetConfiguration[\"requiredAccess\"],\n columns: settings.columns as GristWidgetConfiguration[\"columns\"],\n allowSelectBy: settings.allowSelectBy as boolean | undefined,\n hasCustomOptions: settings.hasCustomOptions as boolean | undefined,\n }\n state.configuration = config\n bus.emit({ type: \"ready\", configuration: config })\n bus.emit({ type: \"mappings-change\", mappings: resolveMappings(state) })\n },\n\n async mappings() {\n return resolveMappings(state)\n },\n }\n}\n","import type { GristApiImpl } from \"./types\"\n\n/** `_grist_api` host implementation. Minimal v1 — extend as needed. */\nexport function createGristApiImpl(): GristApiImpl {\n return {\n async ping() {\n return \"pong\"\n },\n }\n}\n","/**\n * Helpers to project an {@link EmulatorTable}'s row-array storage into Grist's\n * columnar wire format expected by `fetchTable` / `fetchSelectedTable`:\n *\n * { id: number[], colA: unknown[], colB: unknown[], ... }\n *\n * When `keepEncoded` is `false` (Grist's default for these APIs), values are\n * passed through as-is — JS-native primitives (string / number / boolean /\n * Date / arrays) are valid Grist plugin values. When `keepEncoded` is `true`,\n * Date columns are emitted in tuple form (`[\"d\", epoch]`) so callers can\n * round-trip them.\n */\n\nimport type { GristRowRecord } from \"../../sdk/types\"\nimport type { EmulatorTable } from \"./types\"\n\nexport type ColumnarTable = Record<string, unknown[]>\n\nexport type ToColumnarOptions = {\n keepEncoded?: boolean\n}\n\nexport function rowsToColumnar(\n table: EmulatorTable,\n rows: readonly GristRowRecord[],\n options: ToColumnarOptions = {}\n): ColumnarTable {\n const cols = Object.keys(table.columns)\n const out: ColumnarTable = { id: rows.map((r) => r.id) }\n for (const col of cols) {\n out[col] = rows.map((r) => encodeForWire(r[col], table.columns[col]?.type, options.keepEncoded))\n }\n return out\n}\n\nexport function rowToRecord(\n table: EmulatorTable,\n row: GristRowRecord,\n options: ToColumnarOptions = {}\n): Record<string, unknown> {\n const out: Record<string, unknown> = { id: row.id }\n for (const col of Object.keys(table.columns)) {\n out[col] = encodeForWire(row[col], table.columns[col]?.type, options.keepEncoded)\n }\n return out\n}\n\nfunction encodeForWire(value: unknown, type: string | undefined, keepEncoded: boolean | undefined): unknown {\n if (value instanceof Date) {\n const epoch = Math.floor(value.getTime() / 1000)\n if (keepEncoded) {\n return type && type.startsWith(\"DateTime\") ? [\"D\", epoch, \"UTC\"] : [\"d\", epoch]\n }\n return epoch\n }\n return value\n}\n","import { applyUserActions } from \"../core/action-engine\"\nimport { rowsToColumnar } from \"../core/columnar\"\nimport { getTable, synthesizeTablesColumnMeta, synthesizeTablesMeta } from \"../core/document\"\nimport type { EventBus } from \"../core/event-bus\"\nimport type { EmulatorDocumentState } from \"../core/types\"\nimport type { GristDocApiImpl } from \"./types\"\n\n/**\n * `GristDocAPI` host implementation. Backs `grist.docApi.*` methods such as\n * `getDocName`, `listTables`, `fetchTable`, `applyUserActions` and\n * `getAccessToken`.\n *\n * `applyUserActions` is the only mutation entry point — every widget write\n * lands here, so tests can listen on the bus for `user-action` events to\n * assert exactly which actions a UI flow generated.\n */\nexport function createGristDocApiImpl(state: EmulatorDocumentState, bus: EventBus): GristDocApiImpl {\n return {\n async getDocName() {\n return state.docName\n },\n\n async listTables() {\n return [...state.tables.keys()]\n },\n\n async fetchTable(tableId) {\n if (tableId === \"_grist_Tables\") {\n return synthesizeTablesMeta(state)\n }\n if (tableId === \"_grist_Tables_column\") {\n return synthesizeTablesColumnMeta(state)\n }\n const table = getTable(state, tableId)\n return rowsToColumnar(table, table.rows)\n },\n\n async applyUserActions(actions) {\n const result = applyUserActions(state, bus, actions)\n return { retValues: result.retValues }\n },\n\n async getAccessToken() {\n if (!state.accessToken) {\n const err = new Error(\"getAccessToken not available (no token configured on emulator)\")\n // Mirror Grist's protocol: rejected stub call.\n throw err\n }\n return { ...state.accessToken }\n },\n }\n}\n","import { rowToRecord, rowsToColumnar } from \"../core/columnar\"\nimport { findRow, getSelectedTable } from \"../core/document\"\nimport type { EventBus } from \"../core/event-bus\"\nimport type { EmulatorDocumentState } from \"../core/types\"\nimport type { GristViewImpl } from \"./types\"\n\n/**\n * `GristView` host implementation.\n *\n * Exposes the section-scoped data API the widget uses through\n * `grist.docApi.fetchSelectedTable()`, `fetchSelectedRecord()` and\n * `setCursorPos()`. Reads from the emulator state, writes to the same state\n * via the action engine where applicable, and emits events on the bus so\n * subscribers (transports, inspector, tests) stay in sync.\n *\n * IMPORTANT: `fetchSelectedTable` always returns Grist's **columnar** wire\n * shape. The production `grist-plugin-api.js` wrapper (which the iframe\n * transport talks to) expects the raw RPC stub to return columnar and does\n * the `format: \"rows\"` transposition + `keepEncoded: false` decoding itself.\n * Returning rows here used to crash the wrapper's `mapValues(data, col =>\n * col.map(decodeObject))` pass — `data` was an array, `col` was a row object\n * with no `.map` method — so widgets observed `records === null` forever.\n * The inline transport mirrors the same wrapper semantics in\n * `transports/inline.ts` so widget code sees identical results in both modes.\n */\nexport function createGristViewImpl(state: EmulatorDocumentState, bus: EventBus): GristViewImpl {\n return {\n async fetchSelectedTable(options) {\n const table = getSelectedTable(state)\n return rowsToColumnar(table, table.rows, { keepEncoded: options?.keepEncoded })\n },\n\n async fetchSelectedRecord(rowId, options) {\n const table = getSelectedTable(state)\n const row = findRow(table, rowId)\n if (!row) throw new Error(`No row ${rowId} in ${table.tableId}`)\n return rowToRecord(table, row, { keepEncoded: options?.keepEncoded })\n },\n\n async allowSelectBy() {\n return state.configuration?.allowSelectBy ?? false\n },\n\n async setSelectedRows(rowIds) {\n if (!rowIds || rowIds.length === 0) {\n state.selection.rowId = null\n } else {\n state.selection.rowId = rowIds[0]\n }\n bus.emit({\n type: \"cursor-change\",\n tableId: state.selection.tableId,\n rowId: state.selection.rowId,\n })\n },\n\n async setCursorPos(cursor) {\n const tableId = state.selection.tableId\n if (typeof cursor.rowId === \"number\") state.selection.rowId = cursor.rowId\n state.selection.cursor = { ...state.selection.cursor, ...cursor }\n bus.emit({\n type: \"cursor-change\",\n tableId,\n rowId: state.selection.rowId,\n cursor: state.selection.cursor,\n })\n },\n }\n}\n","import type { EventBus } from \"../core/event-bus\"\nimport type { EmulatorDocumentState } from \"../core/types\"\nimport type { WidgetApiImpl } from \"./types\"\n\n/**\n * `WidgetAPI` host implementation, backing `grist.widgetApi.*`. Reads and\n * writes the per-widget options bag persisted on the emulator state. Each\n * mutation triggers an `options-change` event so subscribers (the transport\n * pushes an `onOptions` message; tests/inspector update accordingly) stay in\n * lock-step with the document.\n */\nexport function createWidgetApiImpl(state: EmulatorDocumentState, bus: EventBus): WidgetApiImpl {\n function emit() {\n bus.emit({\n type: \"options-change\",\n options: { ...state.widgetOptions },\n interaction: { ...state.widgetInteraction },\n })\n }\n\n return {\n async getOption(key) {\n return state.widgetOptions[key]\n },\n\n async setOption(key, value) {\n state.widgetOptions[key] = value\n emit()\n },\n\n async getOptions() {\n return Object.keys(state.widgetOptions).length > 0 ? { ...state.widgetOptions } : null\n },\n\n // Replaces every option, as Grist's WidgetAPI.setOptions does.\n async setOptions(options) {\n state.widgetOptions = { ...options }\n emit()\n },\n\n async clearOptions() {\n state.widgetOptions = {}\n emit()\n },\n }\n}\n","/**\n * Bundles the six host-side Grist API implementations into one record so\n * inline transport can wire them up.\n */\n\nimport type { EventBus } from \"../core/event-bus\"\nimport type { EmulatorDocumentState } from \"../core/types\"\nimport { createCommandApiImpl } from \"./command-api\"\nimport { createCustomSectionApiImpl } from \"./custom-section-api\"\nimport { createGristApiImpl } from \"./grist-api\"\nimport { createGristDocApiImpl } from \"./grist-doc-api\"\nimport { createGristViewImpl } from \"./grist-view\"\nimport type {\n CommandApiImpl,\n CustomSectionApiImpl,\n GristApiImpl,\n GristDocApiImpl,\n GristViewImpl,\n WidgetApiImpl,\n} from \"./types\"\nimport { createWidgetApiImpl } from \"./widget-api\"\n\nexport type EmulatorApiBundle = {\n GristView: GristViewImpl\n GristDocAPI: GristDocApiImpl\n WidgetAPI: WidgetApiImpl\n CustomSectionAPI: CustomSectionApiImpl\n GristAPI: GristApiImpl\n CommandAPI: CommandApiImpl\n}\n\n/**\n * Build the implementations bound to a given document state and event bus.\n * Cheap to call — every method delegates to the (mutable) `state`.\n */\nexport function createApiBundle(state: EmulatorDocumentState, bus: EventBus): EmulatorApiBundle {\n return {\n GristView: createGristViewImpl(state, bus),\n GristDocAPI: createGristDocApiImpl(state, bus),\n WidgetAPI: createWidgetApiImpl(state, bus),\n CustomSectionAPI: createCustomSectionApiImpl(state, bus),\n GristAPI: createGristApiImpl(),\n CommandAPI: createCommandApiImpl(bus),\n }\n}\n\nexport type {\n CommandApiImpl,\n CustomSectionApiImpl,\n GristApiImpl,\n GristDocApiImpl,\n GristViewImpl,\n WidgetApiImpl,\n} from \"./types\"\n","/**\n * Tiny pub-sub used to broadcast every emulator state change to:\n * - the transports (which translate events into protocol messages),\n * - the React DevTools inspector (timeline view),\n * - the testing harness (assertions on emitted events).\n */\n\nimport type { GristCursorPos, GristWidgetColumnMap, GristWidgetInteraction } from \"../../sdk/types\"\n\nexport type EmulatorEvent =\n | { type: \"data-change\"; tableId: string }\n | { type: \"cursor-change\"; tableId: string; rowId: number | \"new\" | null; cursor?: GristCursorPos }\n | { type: \"options-change\"; options: Record<string, unknown>; interaction: GristWidgetInteraction }\n | { type: \"theme-change\"; message: Record<string, unknown> }\n | { type: \"ready\"; configuration: unknown }\n | { type: \"user-action\"; action: unknown[] }\n | { type: \"mappings-change\"; mappings: GristWidgetColumnMap | null }\n\nexport type EmulatorEventListener = (event: EmulatorEvent) => void\n\nexport type EventBus = {\n emit: (event: EmulatorEvent) => void\n on: (listener: EmulatorEventListener) => () => void\n history: () => readonly EmulatorEvent[]\n clear: () => void\n}\n\nexport type EventBusOptions = {\n /** Cap on history length (DevTools / tests). Defaults to 200. */\n historyLimit?: number\n}\n\nexport function createEventBus(options: EventBusOptions = {}): EventBus {\n const limit = options.historyLimit ?? 200\n const listeners = new Set<EmulatorEventListener>()\n const history: EmulatorEvent[] = []\n\n return {\n emit(event) {\n history.push(event)\n if (history.length > limit) history.shift()\n for (const fn of [...listeners]) {\n try {\n fn(event)\n } catch (err) {\n console.error(\"[grist-emulator] event listener threw:\", err)\n }\n }\n },\n on(listener) {\n listeners.add(listener)\n return () => {\n listeners.delete(listener)\n }\n },\n history() {\n return history\n },\n clear() {\n history.length = 0\n },\n }\n}\n","export type GristThemeAppearance = \"light\" | \"dark\"\n\n/** Host → widget postMessage shape used by `grist-plugin-api.js` (`onThemeChange`). */\nexport type GristThemeHostMessage = {\n theme: {\n appearance: GristThemeAppearance\n name: string\n colors: Record<string, string>\n }\n fromReady?: boolean\n}\n\nexport function buildGristThemeHostMessage(\n appearance: GristThemeAppearance,\n options?: { fromReady?: boolean }\n): GristThemeHostMessage {\n return {\n theme: {\n appearance,\n name: appearance,\n colors: {},\n },\n ...(options?.fromReady ? { fromReady: true } : {}),\n }\n}\n","/**\n * Inline transport — synthesises a `window.grist` global wired directly to\n * the emulator state. No iframe, no postMessage, no serialization.\n *\n * Used for:\n * - SDK unit tests in jsdom (`renderWithGrist(...)`),\n * - IDE-style live previews where widget code lives in the same window\n * as the emulator host.\n *\n * The synthesised `grist` object exposes the **same** typed surface as the\n * production `grist-plugin-api.js` (see `hooks/grist-global.d.ts`). Hooks\n * call `grist.docApi.fetchTable(...)` etc. and get the answer directly from\n * the action engine.\n */\n\nimport type {\n GristCursorPos,\n GristFetchSelectedOptions,\n GristMinimalRecord,\n GristReadyOptions,\n GristTableOpOptions,\n GristTableOperations,\n GristTableUpdateRecord,\n GristTableUpsertOptions,\n GristTableUpsertRecord,\n GristWidgetColumnMap,\n GristWidgetInteraction,\n} from \"../../sdk/types\"\nimport {\n gristAddRecordAction,\n gristBulkAddRecordAction,\n gristBulkRemoveRecordAction,\n gristBulkUpdateRecordAction,\n gristRemoveRecordAction,\n gristUpdateRecordAction,\n} from \"../../sdk/helpers/grist-user-actions\"\nimport { applyUserActions } from \"../core/action-engine\"\nimport type { EmulatorEvent } from \"../core/event-bus\"\nimport { findRow, getTable } from \"../core/document\"\nimport { resolveMappings } from \"../core/mappings\"\nimport { buildGristThemeHostMessage } from \"../theme-message\"\nimport type { EmulatorTransport, TransportContext } from \"./types\"\n\n/**\n * Shape of the synthesised global. Matches `globalThis.grist` from\n * `grist-global.d.ts`.\n */\nexport type InlineGristGlobal = {\n ready: (options?: GristReadyOptions) => Promise<void>\n onRecord: (\n cb: (record: Record<string, unknown> | null, mappings?: GristWidgetColumnMap | null) => void,\n options?: GristFetchSelectedOptions\n ) => void\n onRecords: (\n cb: (records: Record<string, unknown>[], mappings?: GristWidgetColumnMap | null) => void,\n options?: GristFetchSelectedOptions\n ) => void\n onOptions: (cb: (options: Record<string, unknown> | null, interaction: GristWidgetInteraction) => void) => void\n onNewRecord: (cb: (mappings: GristWidgetColumnMap | null) => void) => void\n mapColumnNames: (data: Record<string, unknown>) => Record<string, unknown> | null\n mapColumnNamesBack: (data: Record<string, unknown>) => Record<string, unknown>\n getOptions: () => Promise<Record<string, unknown> | null>\n getOption: (key: string) => Promise<unknown>\n setOption: (key: string, value: unknown) => Promise<void>\n setOptions: (options: Record<string, unknown>) => Promise<void>\n clearOptions: () => Promise<void>\n setCursorPos: (pos: GristCursorPos) => Promise<void>\n setSelectedRows: (rowIds: number[] | null) => Promise<void>\n fetchSelectedTable: (options?: GristFetchSelectedOptions) => Promise<Record<string, unknown[]>>\n fetchSelectedRecord: (rowId: number, options?: GristFetchSelectedOptions) => Promise<Record<string, unknown>>\n docApi: {\n getDocName: () => Promise<string>\n listTables: () => Promise<string[]>\n fetchTable: (tableId: string) => Promise<Record<string, unknown[]>>\n applyUserActions: (actions: unknown[][], options?: { desc?: string }) => Promise<{ retValues: unknown[] }>\n getAccessToken?: (options?: { readOnly?: boolean }) => Promise<{ token: string; baseUrl: string }>\n fetchSelectedTable: (options?: GristFetchSelectedOptions) => Promise<Record<string, unknown[]>>\n fetchSelectedRecord: (rowId: number, options?: GristFetchSelectedOptions) => Promise<Record<string, unknown>>\n }\n selectedTable: GristTableOperations\n getTable: (tableId?: string) => GristTableOperations\n sectionApi: {\n configure: (settings: GristReadyOptions) => Promise<void>\n mappings: () => Promise<GristWidgetColumnMap | null>\n }\n on: (eventName: string, listener: (...args: unknown[]) => void) => () => void\n}\n\nexport type InlineTransportOptions = TransportContext & {\n /**\n * Where to mount the synthesised `grist` global.\n * Defaults to the current window. Pass a different target (e.g. an iframe's\n * `contentWindow`) to install it in another realm.\n */\n target?: Window & typeof globalThis\n}\n\n/**\n * Returns an {@link EmulatorTransport} **and** the synthesised `grist`\n * object. `target.grist = global` is set as a side-effect for parity with\n * the production runtime.\n */\nexport function createInlineTransport(\n options: InlineTransportOptions\n): EmulatorTransport & { grist: InlineGristGlobal } {\n const { state, bus, api } = options\n const target = options.target ?? (globalThis as unknown as Window & typeof globalThis)\n\n // The SDK's `useGristAvailability` checks `window.self !== window.top`.\n // The inline transport runs in a top-level window where that's false. We\n // shim `top` so widget code thinks it's embedded — production doesn't use\n // this transport so there's no risk of leaking the shim.\n installFakeIframeContext(target)\n\n type RecordCb = (record: Record<string, unknown> | null, mappings?: GristWidgetColumnMap | null) => void\n type RecordsCb = (records: Record<string, unknown>[], mappings?: GristWidgetColumnMap | null) => void\n type OptionsCb = (options: Record<string, unknown> | null, interaction: GristWidgetInteraction) => void\n type NewRecordCb = (mappings: GristWidgetColumnMap | null) => void\n\n const recordCbs = new Map<RecordCb, GristFetchSelectedOptions | undefined>()\n const recordsCbs = new Map<RecordsCb, GristFetchSelectedOptions | undefined>()\n const optionsCbs = new Set<OptionsCb>()\n const newRecordCbs = new Set<NewRecordCb>()\n const generic = new Map<string, Set<(...args: unknown[]) => void>>()\n\n // Replay caches — production `grist-plugin-api.js` immediately delivers the\n // latest record / records / options to a freshly-subscribed listener, so\n // hooks that subscribe **after** `grist.ready()` still get the initial\n // payload. We mirror that behaviour here.\n type LastRecord = { record: Record<string, unknown> | null; mappings: GristWidgetColumnMap | null }\n type LastRecords = { records: Record<string, unknown>[]; mappings: GristWidgetColumnMap | null }\n type LastOptions = { options: Record<string, unknown> | null; interaction: GristWidgetInteraction }\n let lastRecord: LastRecord | null = null\n let lastRecords: LastRecords | null = null\n let lastOptions: LastOptions | null = null\n let lastNewRecord: GristWidgetColumnMap | null | undefined = undefined\n\n const buildInteraction = options.buildInteraction ?? (() => ({\n access_level: state.configuration?.requiredAccess ?? \"read table\",\n ...state.widgetInteraction,\n }))\n\n async function pushRecord(rowId: number | \"new\" | null) {\n const mappings = resolveMappings(state)\n if (rowId === \"new\") {\n // Grist's onRecord ignores the add-row (rowId \"new\"): only onNewRecord fires.\n lastNewRecord = mappings\n for (const cb of newRecordCbs) {\n try { cb(mappings) } catch (err) { logErr(err) }\n }\n return\n }\n if (rowId === null) {\n lastRecord = { record: null, mappings }\n for (const [cb] of recordCbs) {\n try { cb(null, mappings) } catch (err) { logErr(err) }\n }\n return\n }\n let record: Record<string, unknown> | null = null\n try {\n record = await api.GristView.fetchSelectedRecord(rowId)\n } catch (err) {\n logErr(err)\n }\n lastRecord = { record, mappings }\n for (const [cb, opts] of recordCbs) {\n try {\n const r = opts?.keepEncoded\n ? await api.GristView.fetchSelectedRecord(rowId, { keepEncoded: true })\n : record\n cb(r, mappings)\n } catch (err) {\n logErr(err)\n }\n }\n }\n\n async function pushRecords() {\n const mappings = resolveMappings(state)\n let baseRows: Record<string, unknown>[] = []\n try {\n const columnar = await api.GristView.fetchSelectedTable({})\n baseRows = columnsToRows(columnar)\n } catch (err) {\n logErr(err)\n }\n lastRecords = { records: baseRows, mappings }\n for (const [cb, opts] of recordsCbs) {\n try {\n const fetchOptions = coerceFetchOptions(opts)\n // Re-fetch only when the subscriber asked for a different shape\n // (e.g. `keepEncoded: true`). Otherwise reuse the decoded rows we\n // already have to avoid extra work and to match production where\n // the same fetch is broadcast to every listener.\n const rows = fetchOptions?.keepEncoded\n ? columnsToRows(await api.GristView.fetchSelectedTable({ keepEncoded: true }))\n : baseRows\n cb(rows, mappings)\n } catch (err) {\n logErr(err)\n }\n }\n }\n\n /**\n * Mirror what `viewApi.fetchSelectedTable` does inside `grist-plugin-api.js`:\n * the host RPC stub always returns columnar; the wrapper applies the\n * `format: \"rows\"` transpose (and would decode encoded values when\n * `keepEncoded: false` — a no-op here because our `rowsToColumnar` already\n * emits JS-native primitives in that case).\n *\n * Keeping this logic on the inline side guarantees that widgets see the\n * same result whether they go through the iframe transport (real plugin\n * wrapper) or the inline transport (this wrapper).\n */\n async function fetchSelectedTableShaped(\n opts: GristFetchSelectedOptions | undefined\n ): Promise<Record<string, unknown[]> | Record<string, unknown>[]> {\n const fetchOptions = coerceFetchOptions(opts)\n const columnar = (await api.GristView.fetchSelectedTable(\n fetchOptions ? { keepEncoded: fetchOptions.keepEncoded } : {}\n )) as Record<string, unknown[]>\n if (fetchOptions?.format === \"rows\") return columnsToRows(columnar)\n return columnar\n }\n\n function pushOptions() {\n const opts = Object.keys(state.widgetOptions).length > 0 ? { ...state.widgetOptions } : null\n const interaction = buildInteraction()\n lastOptions = { options: opts, interaction }\n for (const cb of optionsCbs) {\n try { cb(opts, interaction) } catch (err) { logErr(err) }\n }\n }\n\n const offBus = bus.on(async (event: EmulatorEvent) => {\n switch (event.type) {\n case \"data-change\":\n await pushRecords()\n await pushRecord(state.selection.rowId)\n break\n case \"cursor-change\":\n await pushRecord(event.rowId)\n break\n case \"options-change\":\n pushOptions()\n break\n case \"ready\":\n pushOptions()\n if (options.initialTheme) {\n notify(\"message\", buildGristThemeHostMessage(options.initialTheme, { fromReady: true }))\n }\n await pushRecords()\n await pushRecord(state.selection.rowId)\n break\n case \"mappings-change\":\n await pushRecords()\n await pushRecord(state.selection.rowId)\n break\n case \"theme-change\":\n notify(\"message\", event.message)\n break\n }\n })\n\n function makeTableOps(tableId: string): GristTableOperations {\n return {\n async getTableId() { return tableId },\n async create(records, options) {\n const list = Array.isArray(records) ? records : [records]\n const ids: GristMinimalRecord[] = []\n for (const r of list) {\n const result = applyUserActions(state, bus, [\n gristAddRecordAction(tableId, parseFields(r.fields, options)),\n ])\n ids.push({ id: result.retValues[0] as number })\n }\n return Array.isArray(records) ? ids : ids[0]\n },\n async update(records: GristTableUpdateRecord | GristTableUpdateRecord[], options?: GristTableOpOptions) {\n const list = Array.isArray(records) ? records : [records]\n const actions = list.map((r) => gristUpdateRecordAction(tableId, r.id, parseFields(r.fields, options)))\n applyUserActions(state, bus, actions)\n },\n async upsert(records: GristTableUpsertRecord | GristTableUpsertRecord[], options?: GristTableUpsertOptions) {\n const list = Array.isArray(records) ? records : [records]\n const allowAdd = options?.add !== false\n const allowUpdate = options?.update !== false\n const table = getTable(state, tableId)\n const actions: unknown[][] = []\n for (const r of list) {\n const matches = table.rows.filter((row) =>\n Object.entries(r.require).every(([k, v]) => row[k] === v)\n )\n if (matches.length > 0) {\n if (!allowUpdate) continue\n const fields = parseFields(r.fields ?? {}, options)\n for (const m of matches) actions.push(gristUpdateRecordAction(tableId, m.id, fields))\n } else if (allowAdd) {\n actions.push(gristAddRecordAction(tableId, { ...r.require, ...parseFields(r.fields ?? {}, options) }))\n }\n }\n if (actions.length > 0) applyUserActions(state, bus, actions)\n },\n async destroy(recordIds: number | number[]) {\n if (Array.isArray(recordIds)) {\n applyUserActions(state, bus, [gristBulkRemoveRecordAction(tableId, recordIds)])\n } else {\n applyUserActions(state, bus, [gristRemoveRecordAction(tableId, recordIds)])\n }\n // touch the unused bulk-add reference for tree-shaking parity, no-op\n void gristBulkAddRecordAction\n void gristBulkUpdateRecordAction\n },\n }\n }\n\n function notify(event: string, ...args: unknown[]) {\n const set = generic.get(event)\n if (!set) return\n for (const fn of set) {\n try { fn(...args) } catch (err) { logErr(err) }\n }\n }\n\n const grist: InlineGristGlobal = {\n async ready(opts) {\n await api.CustomSectionAPI.configure(opts ? { ...opts, onEditOptions: undefined } as unknown as Record<string, unknown> : {})\n },\n\n onRecord(cb, opts) {\n recordCbs.set(cb, opts)\n // Replay last value so late subscribers don't miss the initial event.\n if (lastRecord) {\n try { cb(lastRecord.record, lastRecord.mappings) } catch (err) { logErr(err) }\n }\n },\n onRecords(cb, opts) {\n recordsCbs.set(cb, opts)\n if (lastRecords) {\n try { cb(lastRecords.records, lastRecords.mappings) } catch (err) { logErr(err) }\n }\n },\n onOptions(cb) {\n optionsCbs.add(cb)\n if (lastOptions) {\n try { cb(lastOptions.options, lastOptions.interaction) } catch (err) { logErr(err) }\n }\n },\n onNewRecord(cb) {\n newRecordCbs.add(cb)\n if (lastNewRecord !== undefined) {\n try { cb(lastNewRecord) } catch (err) { logErr(err) }\n }\n },\n\n mapColumnNames(data) {\n const mappings = resolveMappings(state)\n if (!mappings) return null\n const out: Record<string, unknown> = {}\n let allMapped = true\n for (const [logical, real] of Object.entries(mappings)) {\n if (Array.isArray(real)) {\n out[logical] = real.map((r) => data[r])\n } else if (typeof real === \"string\") {\n out[logical] = data[real]\n } else {\n allMapped = false\n }\n }\n return allMapped ? out : null\n },\n mapColumnNamesBack(data) {\n const mappings = resolveMappings(state)\n if (!mappings) return data\n const out: Record<string, unknown> = {}\n for (const [logical, real] of Object.entries(mappings)) {\n if (typeof real === \"string\" && logical in data) {\n out[real] = data[logical]\n }\n }\n return out\n },\n\n getOption: (k) => api.WidgetAPI.getOption(k),\n setOption: (k, v) => api.WidgetAPI.setOption(k, v),\n getOptions: () => api.WidgetAPI.getOptions(),\n setOptions: (o) => api.WidgetAPI.setOptions(o),\n clearOptions: () => api.WidgetAPI.clearOptions(),\n\n setCursorPos: (pos) => api.GristView.setCursorPos(pos),\n setSelectedRows: (rowIds) => api.GristView.setSelectedRows(rowIds),\n fetchSelectedTable: (opts) =>\n fetchSelectedTableShaped(opts) as Promise<Record<string, unknown[]>>,\n fetchSelectedRecord: (rowId, opts) => api.GristView.fetchSelectedRecord(rowId, coerceFetchOptions(opts)),\n\n docApi: {\n getDocName: () => api.GristDocAPI.getDocName(),\n listTables: () => api.GristDocAPI.listTables(),\n fetchTable: (id) => api.GristDocAPI.fetchTable(id),\n applyUserActions: (actions, options) => api.GristDocAPI.applyUserActions(actions, options),\n getAccessToken: (opts) => api.GristDocAPI.getAccessToken(opts),\n fetchSelectedTable: (opts) =>\n fetchSelectedTableShaped(opts) as Promise<Record<string, unknown[]>>,\n fetchSelectedRecord: (rowId, opts) =>\n api.GristView.fetchSelectedRecord(rowId, coerceFetchOptions(opts)),\n },\n\n get selectedTable() {\n return makeTableOps(state.selection.tableId)\n },\n\n getTable(tableId) {\n return makeTableOps(tableId ?? state.selection.tableId)\n },\n\n sectionApi: {\n configure: (settings) => api.CustomSectionAPI.configure(settings as unknown as Record<string, unknown>),\n mappings: () => api.CustomSectionAPI.mappings(),\n },\n\n on(eventName, listener) {\n let set = generic.get(eventName)\n if (!set) generic.set(eventName, (set = new Set()))\n set.add(listener)\n return () => set!.delete(listener)\n },\n }\n\n ;(target as unknown as { grist: InlineGristGlobal }).grist = grist\n\n return {\n grist,\n dispose() {\n offBus()\n // Restore the global (only if we still own it).\n const t = target as unknown as { grist?: unknown }\n if (t.grist === grist) delete t.grist\n recordCbs.clear()\n recordsCbs.clear()\n optionsCbs.clear()\n newRecordCbs.clear()\n generic.clear()\n lastRecord = null\n lastRecords = null\n lastOptions = null\n lastNewRecord = undefined\n },\n fireDataChange(tableId) {\n bus.emit({ type: \"data-change\", tableId: tableId ?? state.selection.tableId })\n },\n fireCursor(rowId) {\n const id = rowId === undefined ? state.selection.rowId : rowId\n bus.emit({ type: \"cursor-change\", tableId: state.selection.tableId, rowId: id })\n },\n fireOptions() {\n pushOptions()\n },\n fireTheme(message) {\n bus.emit({ type: \"theme-change\", message })\n },\n emitInitialState() {\n pushOptions()\n void pushRecords().then(() => pushRecord(state.selection.rowId))\n },\n }\n}\n\nfunction columnsToRows(columnar: Record<string, unknown[]>): Record<string, unknown>[] {\n const cols = Object.keys(columnar)\n if (cols.length === 0) return []\n const length = (columnar[cols[0]] ?? []).length\n const rows: Record<string, unknown>[] = []\n for (let i = 0; i < length; i++) {\n const row: Record<string, unknown> = {}\n for (const c of cols) row[c] = columnar[c][i]\n rows.push(row)\n }\n return rows\n}\n\nfunction parseFields(fields: Record<string, unknown>, _options?: GristTableOpOptions): Record<string, unknown> {\n // The emulator currently doesn't implement string-parsing; pass-through.\n // Hook into here to add date/number parsing when we surface that toggle.\n return { ...fields }\n}\n\nfunction coerceFetchOptions(\n opts: GristFetchSelectedOptions | undefined\n): { keepEncoded?: boolean; format?: \"rows\" | \"columns\" } | undefined {\n if (!opts) return undefined\n const format = opts.format === \"rows\" || opts.format === \"columns\" ? opts.format : undefined\n return { keepEncoded: opts.keepEncoded, format }\n}\n\nfunction logErr(err: unknown) {\n console.error(\"[grist-emulator/inline]\", err)\n}\n\n// Touch helpers to keep them tree-shake-friendly even if unused in current scope.\nvoid findRow\n\n/**\n * Make `window.self !== window.top` evaluate to `true`. The SDK uses this\n * exact comparison in `useGristAvailability` to detect an iframe environment.\n *\n * Inline transports run inside the host window (tests, IDE preview) and would\n * otherwise be flagged as \"not embedded\" — this shim is the same trick we use\n * in the testing harness and is safe because the inline transport is never\n * shipped to production.\n */\nfunction installFakeIframeContext(target: Window & typeof globalThis) {\n try {\n if (target.self !== target.top) return\n Object.defineProperty(target, \"top\", {\n configurable: true,\n get: () => ({}),\n })\n } catch {\n // Some environments lock these globals; ignore silently.\n }\n}\n","/**\n * Top-level emulator factory. Produces a fully-wired emulator instance:\n *\n * - typed in-memory document state,\n * - shared event bus,\n * - the six host API impls,\n * - the inline transport, which installs `grist` on the page,\n * - imperative helpers (`mutate`, `apply`, `selectRow`, `selectTable`)\n * that drive the document via the action engine and emit corresponding\n * events.\n *\n * The instance is multi-instance friendly: nothing is stored on `window`.\n */\n\nimport { createApiBundle } from \"./api\"\nimport type { EmulatorApiBundle } from \"./api\"\nimport { applyUserActions } from \"./core/action-engine\"\nimport { createDocument } from \"./core/document\"\nimport { createEventBus } from \"./core/event-bus\"\nimport type { EventBus } from \"./core/event-bus\"\nimport { resolveMappings } from \"./core/mappings\"\nimport type { EmulatorDocumentState } from \"./core/types\"\nimport type { GristReplicaDocument } from \"../sdk/replica-document\"\nimport type { GristWidgetColumnMap } from \"../sdk/types\"\nimport { buildGristThemeHostMessage } from \"./theme-message\"\nimport { createInlineTransport } from \"./transports\"\nimport type { EmulatorTransport, InlineGristGlobal } from \"./transports\"\nimport { parseDocument } from \"./validators\"\n\nexport type CreateGristEmulatorOptions = {\n /** The starting document (must satisfy {@link parseDocument}). */\n document: GristReplicaDocument\n /** Installs `grist` on `target` (default: the global object). */\n transport?: { kind: \"inline\"; target?: Window & typeof globalThis }\n /** Initial widget options exposed via `WidgetAPI`. */\n widgetOptions?: Record<string, unknown>\n /**\n * Initial widget interaction info (`access_level` and friends) sent\n * alongside `onOptions`. Without an `access_level`, Grist grants the access\n * the widget requests in `grist.ready()`.\n */\n widgetInteraction?: Record<string, unknown>\n /** Initial document theme replayed on widget ready (host `message` channel). */\n initialTheme?: \"light\" | \"dark\"\n}\n\nexport type GristEmulator = {\n /** Underlying mutable document. Treat as read-only outside of `mutate(...)`. */\n state: EmulatorDocumentState\n bus: EventBus\n api: EmulatorApiBundle\n transport: EmulatorTransport\n /** Synthesised `grist` global (only for the inline transport). */\n grist?: InlineGristGlobal\n\n /** Apply a list of Grist user actions; emits the matching events. */\n apply: (actions: unknown[][]) => { retValues: unknown[] }\n /** Convenience helpers for tests and demos. */\n mutate: {\n addRow: (tableId: string, fields: Record<string, unknown>) => number\n updateRow: (tableId: string, rowId: number, fields: Record<string, unknown>) => void\n removeRow: (tableId: string, rowId: number) => void\n }\n selectRow: (rowId: number | \"new\" | null) => void\n selectTable: (tableId: string) => void\n /**\n * Set logical→real column mappings, as a user mapping columns in Grist would.\n * Pass `undefined` to clear — `mappings()` becomes `null` until set again.\n */\n setColumnMappings: (mappings: GristWidgetColumnMap | undefined) => void\n setOptions: (options: Record<string, unknown>) => Promise<void>\n setInteraction: (interaction: Record<string, unknown>) => void\n /** Host theme controls (`grist.on(\"message\")` / `msg.theme`). */\n theme: {\n set: (theme: \"light\" | \"dark\") => void\n }\n /** Tear down the emulator. Idempotent. */\n dispose: () => void\n}\n\nexport function createGristEmulator(options: CreateGristEmulatorOptions): GristEmulator {\n const validatedDocument = parseDocument(options.document)\n const state = createDocument({\n ...validatedDocument,\n widgetOptions: options.widgetOptions ?? validatedDocument.widgetOptions,\n // No access_level by default: the emulator then grants the access the\n // widget asks for in grist.ready(), as a user accepting it in Grist would.\n widgetInteraction: options.widgetInteraction ?? validatedDocument.widgetInteraction ?? {},\n })\n const bus = createEventBus()\n const api = createApiBundle(state, bus)\n\n const inline = createInlineTransport({\n state,\n bus,\n api,\n initialTheme: options.initialTheme,\n target: options.transport?.target,\n })\n const transport: EmulatorTransport = inline\n const grist: InlineGristGlobal | undefined = inline.grist\n\n function apply(actions: unknown[][]) {\n return applyUserActions(state, bus, actions)\n }\n\n return {\n state,\n bus,\n api,\n transport,\n grist,\n apply,\n mutate: {\n addRow: (tableId, fields) => apply([[\"AddRecord\", tableId, null, fields]]).retValues[0] as number,\n updateRow: (tableId, rowId, fields) => {\n apply([[\"UpdateRecord\", tableId, rowId, fields]])\n },\n removeRow: (tableId, rowId) => {\n apply([[\"RemoveRecord\", tableId, rowId]])\n },\n },\n selectRow(rowId) {\n state.selection.rowId = rowId\n bus.emit({ type: \"cursor-change\", tableId: state.selection.tableId, rowId })\n },\n selectTable(tableId) {\n if (!state.tables.has(tableId)) throw new Error(`Unknown table: ${tableId}`)\n state.selection.tableId = tableId\n const first = state.tables.get(tableId)!.rows[0]?.id ?? null\n state.selection.rowId = first\n bus.emit({ type: \"data-change\", tableId })\n bus.emit({ type: \"cursor-change\", tableId, rowId: first })\n },\n setColumnMappings(mappings) {\n if (mappings === undefined) {\n delete state.selection.mappings\n } else {\n state.selection.mappings = mappings\n }\n bus.emit({ type: \"mappings-change\", mappings: resolveMappings(state) })\n },\n async setOptions(opts) {\n await api.WidgetAPI.setOptions(opts)\n },\n setInteraction(interaction) {\n state.widgetInteraction = { ...interaction }\n bus.emit({ type: \"options-change\", options: { ...state.widgetOptions }, interaction: { ...interaction } })\n },\n theme: {\n set(next) {\n bus.emit({ type: \"theme-change\", message: buildGristThemeHostMessage(next) })\n },\n },\n dispose() {\n transport.dispose()\n bus.clear()\n },\n }\n}\n","/**\n * Document templates exposed at the top of the emulator API.\n *\n * Templates return plain data — they don't allocate state, the caller passes\n * the returned value into `createGristEmulator(...)` which performs the allocation.\n */\n\nimport type { GristReplicaDocument } from \"../sdk/replica-document\"\n\nconst PRESET_GENERATED_AT = \"1970-01-01T00:00:00.000Z\"\n\nfunction replicaBase(overrides: Omit<GristReplicaDocument, \"generatedAt\">): GristReplicaDocument {\n return {\n generatedAt: PRESET_GENERATED_AT,\n ...overrides,\n }\n}\n\n/**\n * Useful templates for quick demos and tests.\n */\nexport const presets = {\n /**\n * Default starter fixture for demos / sandboxes that need a neutral document\n * without choosing a domain-specific preset.\n */\n defaultTemplate(): GristReplicaDocument {\n return replicaBase({\n docName: \"Default\",\n tables: {\n Table1: {\n label: \"Table1\",\n rows: [\n { id: 1, Name: \"Alice\" },\n { id: 2, Name: \"Bob\" },\n ],\n },\n },\n })\n },\n blank(): GristReplicaDocument {\n return replicaBase({\n docName: \"Blank\",\n tables: {\n Table1: { rows: [{ id: 1 }] },\n },\n })\n },\n todoList(): GristReplicaDocument {\n return replicaBase({\n docName: \"Todo list\",\n mode: \"schema+data\",\n tables: {\n Tasks: {\n label: \"Tasks\",\n columns: {\n title: { type: \"Text\", label: \"Title\" },\n done: { type: \"Bool\", label: \"Done\" },\n priority: { type: \"Choice\", label: \"Priority\" },\n },\n rows: [\n { id: 1, title: \"Buy milk\", done: false, priority: \"high\" },\n { id: 2, title: \"Write the SOTA emulator\", done: true, priority: \"high\" },\n { id: 3, title: \"Ship it\", done: false, priority: \"medium\" },\n ],\n },\n },\n })\n },\n contacts(): GristReplicaDocument {\n return replicaBase({\n docName: \"Contacts\",\n mode: \"schema+data\",\n tables: {\n Contacts: {\n label: \"Contacts\",\n columns: {\n firstName: { type: \"Text\" },\n lastName: { type: \"Text\" },\n email: { type: \"Text\" },\n company: { type: \"Text\" },\n },\n rows: [\n { id: 1, firstName: \"Ada\", lastName: \"Lovelace\", email: \"ada@analytical.engine\", company: \"British Crown\" },\n { id: 2, firstName: \"Linus\", lastName: \"Torvalds\", email: \"linus@kernel.org\", company: \"Linux Foundation\" },\n { id: 3, firstName: \"Margaret\", lastName: \"Hamilton\", email: \"margaret@apollo.nasa\", company: \"NASA\" },\n ],\n },\n },\n })\n },\n}\n"],"mappings":"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","names":["options"]}
|
|
@@ -4,9 +4,11 @@ import {
|
|
|
4
4
|
deriveColumnMappingStatus,
|
|
5
5
|
deriveStatus,
|
|
6
6
|
isAccessInsufficientError,
|
|
7
|
+
isGristWidget,
|
|
7
8
|
parseGristWidgetLinkingInfo,
|
|
8
|
-
useNearestGristState
|
|
9
|
-
|
|
9
|
+
useNearestGristState,
|
|
10
|
+
useWidgetMetadata
|
|
11
|
+
} from "./chunk-MAPAWVQC.js";
|
|
10
12
|
|
|
11
13
|
// src/app/deploy-path.ts
|
|
12
14
|
var VERSION_SEGMENT = /^v(\d+\.\d+\.\d+(?:-[\w.]+)?)$/;
|
|
@@ -178,6 +180,9 @@ function noop() {
|
|
|
178
180
|
import { StrictMode, Suspense } from "react";
|
|
179
181
|
import { createRoot } from "react-dom/client";
|
|
180
182
|
|
|
183
|
+
// src/app/chrome/local-dev-page.tsx
|
|
184
|
+
import { useEffect as useEffect3, useState as useState3 } from "react";
|
|
185
|
+
|
|
181
186
|
// src/app/chrome/tokens.ts
|
|
182
187
|
var token = (name, fallback) => `var(--${name}, ${fallback})`;
|
|
183
188
|
var tokens = {
|
|
@@ -258,7 +263,20 @@ function widgetTitle() {
|
|
|
258
263
|
|
|
259
264
|
// src/app/chrome/local-dev-page.tsx
|
|
260
265
|
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
266
|
+
function useHasDemo() {
|
|
267
|
+
const [has, setHas] = useState3(null);
|
|
268
|
+
useEffect3(() => {
|
|
269
|
+
if (typeof fetch !== "function") return;
|
|
270
|
+
let live = true;
|
|
271
|
+
fetch("demo/demo.grist", { method: "HEAD" }).then((res) => live && setHas(res.ok)).catch(() => live && setHas(false));
|
|
272
|
+
return () => {
|
|
273
|
+
live = false;
|
|
274
|
+
};
|
|
275
|
+
}, []);
|
|
276
|
+
return has;
|
|
277
|
+
}
|
|
261
278
|
function LocalDevPage() {
|
|
279
|
+
const hasDemo = useHasDemo();
|
|
262
280
|
return /* @__PURE__ */ jsxs("main", { style: pageStyle, children: [
|
|
263
281
|
/* @__PURE__ */ jsxs("p", { style: eyebrowStyle, children: [
|
|
264
282
|
widgetTitle(),
|
|
@@ -266,6 +284,29 @@ function LocalDevPage() {
|
|
|
266
284
|
] }),
|
|
267
285
|
/* @__PURE__ */ jsx2("h1", { style: headingStyle, children: "Not embedded in Grist" }),
|
|
268
286
|
/* @__PURE__ */ jsx2("p", { style: leadStyle, children: "This is the local dev server: there's no Grist here to render the widget against." }),
|
|
287
|
+
/* @__PURE__ */ jsxs("section", { style: cardStyle, children: [
|
|
288
|
+
/* @__PURE__ */ jsx2("h2", { style: cardTitleStyle, children: "Open it in Grist, in this browser" }),
|
|
289
|
+
hasDemo === false ? /* @__PURE__ */ jsxs("p", { style: cardTextStyle, children: [
|
|
290
|
+
"Run ",
|
|
291
|
+
/* @__PURE__ */ jsx2("code", { style: codeStyle, children: "pnpm demo --save" }),
|
|
292
|
+
" once (it needs Docker): it writes",
|
|
293
|
+
" ",
|
|
294
|
+
/* @__PURE__ */ jsx2("code", { style: codeStyle, children: "public/demo/" }),
|
|
295
|
+
", a document for this widget. Then",
|
|
296
|
+
" ",
|
|
297
|
+
/* @__PURE__ */ jsx2("a", { href: "demo/index.html", children: "demo/index.html" }),
|
|
298
|
+
" opens it in real Grist, running in the browser, on this dev server's widget: edits reload in place."
|
|
299
|
+
] }) : /* @__PURE__ */ jsxs("p", { style: cardTextStyle, children: [
|
|
300
|
+
/* @__PURE__ */ jsx2("a", { href: "demo/index.html", children: "Open demo/index.html" }),
|
|
301
|
+
": real Grist running in the browser (no server, nothing saved), with this dev server's widget, so edits reload in place. Its document is",
|
|
302
|
+
" ",
|
|
303
|
+
/* @__PURE__ */ jsx2("code", { style: codeStyle, children: "public/demo/demo.grist" }),
|
|
304
|
+
": after changing the declared columns, run",
|
|
305
|
+
" ",
|
|
306
|
+
/* @__PURE__ */ jsx2("code", { style: codeStyle, children: "pnpm demo --save" }),
|
|
307
|
+
" (Docker) to regenerate it."
|
|
308
|
+
] })
|
|
309
|
+
] }),
|
|
269
310
|
/* @__PURE__ */ jsxs("section", { style: cardStyle, children: [
|
|
270
311
|
/* @__PURE__ */ jsx2("h2", { style: cardTitleStyle, children: "Check it against real Grist" }),
|
|
271
312
|
/* @__PURE__ */ jsxs("p", { style: cardTextStyle, children: [
|
|
@@ -293,7 +334,7 @@ function LocalDevPage() {
|
|
|
293
334
|
}
|
|
294
335
|
|
|
295
336
|
// src/app/chrome/release-page.tsx
|
|
296
|
-
import { useState as
|
|
337
|
+
import { useState as useState4 } from "react";
|
|
297
338
|
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
298
339
|
function ReleasePage({ channel }) {
|
|
299
340
|
const label = deployChannelLabel(channel);
|
|
@@ -352,7 +393,7 @@ function ChannelLink({
|
|
|
352
393
|
}
|
|
353
394
|
function InstallUrl() {
|
|
354
395
|
const url = window.location.href;
|
|
355
|
-
const [copied, setCopied] =
|
|
396
|
+
const [copied, setCopied] = useState4(false);
|
|
356
397
|
function copy() {
|
|
357
398
|
void navigator.clipboard?.writeText(url).then(() => {
|
|
358
399
|
setCopied(true);
|
|
@@ -571,9 +612,31 @@ function LinkIcon() {
|
|
|
571
612
|
}
|
|
572
613
|
|
|
573
614
|
// src/app/mount-grist-widget.tsx
|
|
574
|
-
import { Fragment as Fragment2, jsx as jsx5 } from "react/jsx-runtime";
|
|
575
|
-
function
|
|
576
|
-
|
|
615
|
+
import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
616
|
+
function isGristWidgetEntry(value) {
|
|
617
|
+
return "default" in value && value.default != null;
|
|
618
|
+
}
|
|
619
|
+
function entryProps(entry, dev = false) {
|
|
620
|
+
const widget = isGristWidget(entry.widget) ? entry.widget : void 0;
|
|
621
|
+
const options = widget?.options ?? entry.GRIST_OPTIONS;
|
|
622
|
+
if (!options) {
|
|
623
|
+
throw new Error(
|
|
624
|
+
"mountGristWidget: src/app/App.tsx exports neither `widget` (defineGristWidget) nor `GRIST_OPTIONS`."
|
|
625
|
+
);
|
|
626
|
+
}
|
|
627
|
+
const props = {
|
|
628
|
+
App: entry.default,
|
|
629
|
+
options,
|
|
630
|
+
metadata: widget?.metadata ?? entry.WIDGET_METADATA,
|
|
631
|
+
dev
|
|
632
|
+
};
|
|
633
|
+
if ("Alerts" in entry) props.Alerts = entry.Alerts;
|
|
634
|
+
if (entry.LocalDevPage) props.LocalDevPage = entry.LocalDevPage;
|
|
635
|
+
if (entry.ReleasePage) props.ReleasePage = entry.ReleasePage;
|
|
636
|
+
return props;
|
|
637
|
+
}
|
|
638
|
+
function mountGristWidget(config, entryOptions = {}) {
|
|
639
|
+
const { root = "#root", ...props } = isGristWidgetEntry(config) ? { ...entryProps(config, entryOptions.dev), root: entryOptions.root } : config;
|
|
577
640
|
const container = typeof root === "string" ? document.querySelector(root) : root;
|
|
578
641
|
if (!container) {
|
|
579
642
|
throw new Error(`mountGristWidget: no element matches "${String(root)}" to render the widget into.`);
|
|
@@ -587,6 +650,7 @@ function mountGristWidget(config) {
|
|
|
587
650
|
function GristWidgetApp({
|
|
588
651
|
App,
|
|
589
652
|
options,
|
|
653
|
+
metadata,
|
|
590
654
|
dev = false,
|
|
591
655
|
Alerts = WidgetAlerts,
|
|
592
656
|
LocalDevPage: LocalDevPage2 = LocalDevPage,
|
|
@@ -594,15 +658,25 @@ function GristWidgetApp({
|
|
|
594
658
|
}) {
|
|
595
659
|
const Wrap = Alerts ?? PassThrough;
|
|
596
660
|
if (isEmbedded()) {
|
|
597
|
-
return /* @__PURE__ */
|
|
661
|
+
return /* @__PURE__ */ jsxs4(GristWidgetProvider, { options, children: [
|
|
662
|
+
/* @__PURE__ */ jsx5(PageMetadata, { metadata }),
|
|
663
|
+
/* @__PURE__ */ jsx5(EmbeddedThemeProvider, { children: /* @__PURE__ */ jsx5(GristBoundary, { children: /* @__PURE__ */ jsx5("div", { style: FILL, children: /* @__PURE__ */ jsx5(Wrap, { children: /* @__PURE__ */ jsx5(Suspense, { fallback: null, children: /* @__PURE__ */ jsx5(App, {}) }) }) }) }) })
|
|
664
|
+
] });
|
|
598
665
|
}
|
|
599
666
|
const channel = parseDeployPath(window.location.pathname).channel;
|
|
600
|
-
return /* @__PURE__ */
|
|
667
|
+
return /* @__PURE__ */ jsxs4(StandaloneThemeProvider, { children: [
|
|
668
|
+
/* @__PURE__ */ jsx5(PageMetadata, { metadata }),
|
|
669
|
+
/* @__PURE__ */ jsx5("div", { style: FILL, children: dev ? /* @__PURE__ */ jsx5(LocalDevPage2, {}) : /* @__PURE__ */ jsx5(ReleasePage2, { channel }) })
|
|
670
|
+
] });
|
|
601
671
|
}
|
|
602
672
|
var FILL = { minHeight: "100%", width: "100%" };
|
|
603
673
|
function isEmbedded() {
|
|
604
674
|
return typeof window !== "undefined" && window.self !== window.top;
|
|
605
675
|
}
|
|
676
|
+
function PageMetadata({ metadata }) {
|
|
677
|
+
useWidgetMetadata(metadata?.title ? { title: metadata.title, description: metadata.description ?? "" } : null);
|
|
678
|
+
return null;
|
|
679
|
+
}
|
|
606
680
|
function PassThrough({ children }) {
|
|
607
681
|
return /* @__PURE__ */ jsx5(Fragment2, { children });
|
|
608
682
|
}
|
|
@@ -612,7 +686,9 @@ export {
|
|
|
612
686
|
deployChannelLabel,
|
|
613
687
|
useReleasedVersions,
|
|
614
688
|
useTheme,
|
|
689
|
+
isGristWidgetEntry,
|
|
690
|
+
entryProps,
|
|
615
691
|
mountGristWidget,
|
|
616
692
|
GristWidgetApp
|
|
617
693
|
};
|
|
618
|
-
//# sourceMappingURL=chunk-
|
|
694
|
+
//# sourceMappingURL=chunk-P5I5MRC6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/app/deploy-path.ts","../src/app/released-versions.ts","../src/app/widget-theme.tsx","../src/app/mount-grist-widget.tsx","../src/app/chrome/local-dev-page.tsx","../src/app/chrome/tokens.ts","../src/app/chrome/widget-title.ts","../src/app/chrome/release-page.tsx","../src/sdk/helpers/grist-sdk-alerts.ts","../src/app/chrome/widget-alerts.tsx"],"sourcesContent":["/**\n * Where a deployed build is being served from.\n *\n * A widget's deploy pipeline publishes the same build at its root and at\n * `/latest/`, a preview at `/dev/`, and each release at `/v<version>/`, all\n * under one base path (e.g. `/my-widget/` on GitHub Pages). Opened outside\n * Grist, the page tells them apart from `window.location.pathname` alone.\n */\nexport type DeployChannel =\n | { kind: \"latest\" }\n | { kind: \"dev\" }\n | { kind: \"version\"; version: string }\n\nexport type DeployPath = {\n channel: DeployChannel\n /**\n * The path the channels live under, always ending in `/`: the current\n * path without its channel segment. `\"/my-widget/v1.2.0/\"` gives\n * `\"/my-widget/\"`.\n */\n basePath: string\n}\n\nconst VERSION_SEGMENT = /^v(\\d+\\.\\d+\\.\\d+(?:-[\\w.]+)?)$/\n\n/**\n * Parse a pathname into its deploy channel and base path. A path without a\n * channel segment (the deployed root, or a local dev server) is `latest`:\n * the deploy places the latest release at the root too.\n */\nexport function parseDeployPath(pathname: string): DeployPath {\n const segments = pathname.replace(/\\/+$/, \"\").split(\"/\")\n const last = segments[segments.length - 1] ?? \"\"\n\n let channel: DeployChannel | null = null\n if (last === \"latest\") channel = { kind: \"latest\" }\n else if (last === \"dev\") channel = { kind: \"dev\" }\n else {\n const match = VERSION_SEGMENT.exec(last)\n if (match) channel = { kind: \"version\", version: match[1] }\n }\n\n if (!channel) return { channel: { kind: \"latest\" }, basePath: withTrailingSlash(pathname) }\n return { channel, basePath: withTrailingSlash(segments.slice(0, -1).join(\"/\")) }\n}\n\n/** `\"latest\"`, `\"dev\"` or `\"v1.2.0\"`. */\nexport function deployChannelLabel(channel: DeployChannel): string {\n return channel.kind === \"version\" ? `v${channel.version}` : channel.kind\n}\n\nfunction withTrailingSlash(path: string): string {\n return path.endsWith(\"/\") ? path : `${path}/`\n}\n","import { useEffect, useState } from \"react\"\n\nimport { parseDeployPath } from \"./deploy-path\"\n\n/** One entry of the `versions.json` a widget's deploy pipeline maintains. */\nexport type ReleasedVersion = {\n version: string\n publishedAt: string\n}\n\nexport type UseReleasedVersionsResult = {\n /** Newest first, as the deploy writes them; `null` until loaded. */\n versions: ReleasedVersion[] | null\n /** `true` when `versions.json` couldn't be fetched or read. */\n error: boolean\n}\n\n/**\n * The widget's released versions, read from the `versions.json` next to its\n * channels (see {@link parseDeployPath}). For a page shown outside Grist,\n * such as a release page linking to each version.\n */\nexport function useReleasedVersions(\n pathname: string = typeof window === \"undefined\" ? \"/\" : window.location.pathname\n): UseReleasedVersionsResult {\n const url = `${parseDeployPath(pathname).basePath}versions.json`\n const [result, setResult] = useState<UseReleasedVersionsResult>({ versions: null, error: false })\n\n useEffect(() => {\n let cancelled = false\n fetch(url, { cache: \"no-store\" })\n .then((res) => (res.ok ? res.json() : Promise.reject(new Error(`HTTP ${res.status}`))))\n .then((data: unknown) => {\n if (cancelled) return\n if (!Array.isArray(data)) throw new Error(\"versions.json is not an array\")\n setResult({ versions: data as ReleasedVersion[], error: false })\n })\n .catch(() => {\n if (!cancelled) setResult({ versions: null, error: true })\n })\n return () => {\n cancelled = true\n }\n }, [url])\n\n return result\n}\n","import { createContext, useCallback, useContext, useEffect, useMemo, useState, type ReactNode } from \"react\"\n\nimport { useNearestGristState } from \"../sdk/use-grist\"\n\nexport type WidgetTheme = \"light\" | \"dark\" | \"system\"\nexport type ResolvedWidgetTheme = \"light\" | \"dark\"\n\nexport type UseThemeResult = {\n /**\n * Inside Grist: Grist's theme, or `\"system\"` until Grist has sent it.\n * Outside Grist: the saved choice, `\"system\"` by default.\n */\n theme: WidgetTheme\n /** The theme applied to `<html class>`: `\"system\"` resolved to light or dark. */\n resolvedTheme: ResolvedWidgetTheme\n /**\n * Choose a theme outside Grist; it is saved in `localStorage`. Inside Grist\n * this does nothing: the widget follows Grist's theme.\n */\n setTheme: (theme: WidgetTheme) => void\n}\n\nconst STORAGE_KEY = \"theme\"\nconst DARK_QUERY = \"(prefers-color-scheme: dark)\"\nconst THEMES: readonly WidgetTheme[] = [\"light\", \"dark\", \"system\"]\n\nconst ThemeContext = createContext<UseThemeResult | null>(null)\n\n/**\n * The widget's current theme, for components that need it in JavaScript\n * (a toaster, a chart). Same shape as shadcn's `useTheme()`. Styles should\n * rely on the `dark` class that {@link mountGristWidget} keeps on `<html>`.\n * Outside a mounted widget (a unit test, for instance) it reports the\n * system theme and `setTheme` does nothing.\n */\nexport function useTheme(): UseThemeResult {\n const value = useContext(ThemeContext)\n return value ?? { theme: \"system\", resolvedTheme: systemTheme(), setTheme: noop }\n}\n\n/** Inside Grist: follows Grist's theme, and the OS setting until Grist sends one. */\nexport function EmbeddedThemeProvider({ children }: { children: ReactNode }) {\n const gristTheme = useNearestGristState().state.theme\n const system = useSystemTheme(gristTheme === null)\n const resolvedTheme = gristTheme ?? system\n\n useApplyTheme(resolvedTheme)\n\n const value = useMemo<UseThemeResult>(\n () => ({ theme: gristTheme ?? \"system\", resolvedTheme, setTheme: noop }),\n [gristTheme, resolvedTheme]\n )\n return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>\n}\n\n/**\n * Outside Grist (`pnpm dev`, the deployed release page): the saved choice,\n * the OS setting by default, and the `d` key to switch between light and\n * dark, as shadcn's theme provider does.\n */\nexport function StandaloneThemeProvider({ children }: { children: ReactNode }) {\n const [theme, setThemeState] = useState<WidgetTheme>(() => readStoredTheme() ?? \"system\")\n const system = useSystemTheme(theme === \"system\")\n const resolvedTheme = theme === \"system\" ? system : theme\n\n useApplyTheme(resolvedTheme)\n\n const setTheme = useCallback((next: WidgetTheme) => {\n writeStoredTheme(next)\n setThemeState(next)\n }, [])\n\n // `d` switches between light and dark, unless typing or using a shortcut.\n useEffect(() => {\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.repeat || event.metaKey || event.ctrlKey || event.altKey) return\n if (event.key.toLowerCase() !== \"d\" || isEditableTarget(event.target)) return\n setThemeState((current) => {\n const currentResolved = current === \"system\" ? systemTheme() : current\n const next: WidgetTheme = currentResolved === \"dark\" ? \"light\" : \"dark\"\n writeStoredTheme(next)\n return next\n })\n }\n window.addEventListener(\"keydown\", onKeyDown)\n return () => window.removeEventListener(\"keydown\", onKeyDown)\n }, [])\n\n // Another tab saving a choice applies here too.\n useEffect(() => {\n const onStorage = (event: StorageEvent) => {\n if (event.key !== STORAGE_KEY) return\n setThemeState(isTheme(event.newValue) ? event.newValue : \"system\")\n }\n window.addEventListener(\"storage\", onStorage)\n return () => window.removeEventListener(\"storage\", onStorage)\n }, [])\n\n const value = useMemo<UseThemeResult>(\n () => ({ theme, resolvedTheme, setTheme }),\n [theme, resolvedTheme, setTheme]\n )\n return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>\n}\n\n/** The OS setting, kept current while `active`. */\nfunction useSystemTheme(active: boolean): ResolvedWidgetTheme {\n const [theme, setTheme] = useState<ResolvedWidgetTheme>(systemTheme)\n\n useEffect(() => {\n if (!active || typeof window.matchMedia !== \"function\") return\n const query = window.matchMedia(DARK_QUERY)\n const onChange = () => setTheme(query.matches ? \"dark\" : \"light\")\n onChange()\n query.addEventListener(\"change\", onChange)\n return () => query.removeEventListener(\"change\", onChange)\n }, [active])\n\n return theme\n}\n\n/** Keep `light` or `dark` on `<html class>`, which Tailwind's dark variant reads. */\nfunction useApplyTheme(theme: ResolvedWidgetTheme) {\n useEffect(() => {\n const root = document.documentElement\n if (root.classList.contains(theme) && !root.classList.contains(other(theme))) return\n const restoreTransitions = suspendTransitions()\n root.classList.remove(other(theme))\n root.classList.add(theme)\n restoreTransitions()\n }, [theme])\n}\n\nfunction systemTheme(): ResolvedWidgetTheme {\n if (typeof window === \"undefined\" || typeof window.matchMedia !== \"function\") return \"light\"\n return window.matchMedia(DARK_QUERY).matches ? \"dark\" : \"light\"\n}\n\nfunction other(theme: ResolvedWidgetTheme): ResolvedWidgetTheme {\n return theme === \"dark\" ? \"light\" : \"dark\"\n}\n\n/** Switch themes without every color transition animating at once. */\nfunction suspendTransitions(): () => void {\n const style = document.createElement(\"style\")\n style.appendChild(\n document.createTextNode(\"*,*::before,*::after{-webkit-transition:none!important;transition:none!important}\")\n )\n document.head.appendChild(style)\n return () => {\n window.getComputedStyle(document.body)\n requestAnimationFrame(() => requestAnimationFrame(() => style.remove()))\n }\n}\n\nfunction isEditableTarget(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false\n return target.isContentEditable || target.closest(\"input, textarea, select, [contenteditable='true']\") !== null\n}\n\nfunction isTheme(value: string | null): value is WidgetTheme {\n return value !== null && (THEMES as readonly string[]).includes(value)\n}\n\nfunction readStoredTheme(): WidgetTheme | null {\n try {\n const value = localStorage.getItem(STORAGE_KEY)\n return isTheme(value) ? value : null\n } catch {\n return null\n }\n}\n\nfunction writeStoredTheme(theme: WidgetTheme) {\n try {\n localStorage.setItem(STORAGE_KEY, theme)\n } catch {\n // Storage blocked (private mode, sandboxed iframe): the choice lasts for this page only.\n }\n}\n\nfunction noop() {}\n","import { StrictMode, Suspense, type ComponentType, type ReactNode } from \"react\"\nimport { createRoot } from \"react-dom/client\"\n\nimport { GristBoundary, GristWidgetProvider, useWidgetMetadata } from \"../sdk\"\nimport type { GristWidget, UseGristOptions } from \"../sdk\"\nimport { isGristWidget } from \"../sdk/define-widget\"\nimport { LocalDevPage as DefaultLocalDevPage } from \"./chrome/local-dev-page\"\nimport { ReleasePage as DefaultReleasePage } from \"./chrome/release-page\"\nimport { WidgetAlerts } from \"./chrome/widget-alerts\"\nimport { parseDeployPath, type DeployChannel } from \"./deploy-path\"\nimport { EmbeddedThemeProvider, StandaloneThemeProvider } from \"./widget-theme\"\n\nexport type GristWidgetAppProps = {\n /** The widget. A `React.lazy()` component works too: its code then loads only inside Grist. */\n App: ComponentType\n /** The widget's `GRIST_OPTIONS`: access level, columns, and so on. */\n options: UseGristOptions\n /** The page's title and description (the widget's `WIDGET_METADATA`, or its declaration's). */\n metadata?: { title?: string; description?: string }\n /**\n * Whether this is the local dev server. Pass `import.meta.env.DEV`.\n * Outside Grist it picks the local-dev page over the release page.\n */\n dev?: boolean\n /**\n * Wraps the widget inside Grist, under {@link GristBoundary}. The default\n * lists what needs the user's attention (column mapping, access level,\n * failed writes) above the widget; `null` renders the widget alone.\n */\n Alerts?: ComponentType<{ children: ReactNode }> | null\n /** Shown outside Grist on the local dev server. Defaults to a page pointing at `pnpm test` and the `dev` loop. */\n LocalDevPage?: ComponentType\n /**\n * Shown outside Grist on a deployed URL (`/latest/`, `/dev/`, `/v<version>/`).\n * Defaults to a page linking every channel and version, with the URL to\n * paste into Grist.\n */\n ReleasePage?: ComponentType<{ channel: DeployChannel }>\n}\n\nexport type MountGristWidgetConfig = GristWidgetAppProps & {\n /** The element to render into, or its CSS selector. Defaults to `#root`. */\n root?: Element | string\n}\n\n/**\n * A widget's entry module, `src/app/App.tsx`, as `import * as entry` gives\n * it: the widget as its default export, its declaration as `widget` (or, in\n * a widget made before `defineGristWidget`, `GRIST_OPTIONS` and\n * `WIDGET_METADATA`), and optionally its own `Alerts`, `LocalDevPage` and\n * `ReleasePage`. Everything a widget customises lives there, in its own\n * file: the template's `src/main.tsx` stays the same in every widget, and\n * `create-grist-widget upgrade` can rewrite it without losing anything.\n */\nexport type GristWidgetEntry = {\n default: ComponentType\n widget?: GristWidget\n GRIST_OPTIONS?: UseGristOptions\n WIDGET_METADATA?: { title?: string; description?: string }\n Alerts?: GristWidgetAppProps[\"Alerts\"]\n LocalDevPage?: GristWidgetAppProps[\"LocalDevPage\"]\n ReleasePage?: GristWidgetAppProps[\"ReleasePage\"]\n}\n\n/**\n * @internal An entry module, as opposed to `{ App, options }`: it has a\n * default export. A widget's module may also export its component as `App`,\n * so `App` alone doesn't tell them apart.\n */\nexport function isGristWidgetEntry(value: object): value is GristWidgetEntry {\n return \"default\" in value && value.default != null\n}\n\n/** The props {@link GristWidgetApp} takes, from a widget's entry module. */\nexport function entryProps(entry: GristWidgetEntry, dev = false): GristWidgetAppProps {\n const widget = isGristWidget(entry.widget) ? entry.widget : undefined\n const options = widget?.options ?? entry.GRIST_OPTIONS\n if (!options) {\n throw new Error(\n \"mountGristWidget: src/app/App.tsx exports neither `widget` (defineGristWidget) nor `GRIST_OPTIONS`.\"\n )\n }\n const props: GristWidgetAppProps = {\n App: entry.default,\n options,\n metadata: widget?.metadata ?? entry.WIDGET_METADATA,\n dev,\n }\n if (\"Alerts\" in entry) props.Alerts = entry.Alerts\n if (entry.LocalDevPage) props.LocalDevPage = entry.LocalDevPage\n if (entry.ReleasePage) props.ReleasePage = entry.ReleasePage\n return props\n}\n\nexport type MountedGristWidget = {\n unmount: () => void\n}\n\n/**\n * Render a widget into the page: everything `src/main.tsx` used to wire by\n * hand.\n *\n * ```tsx\n * import { mountGristWidget } from \"grist-widget-sdk/app\"\n * import \"./index.css\"\n * import * as entry from \"./app/App\"\n *\n * mountGristWidget(entry, { dev: import.meta.env.DEV })\n * ```\n *\n * It reads the entry module's exports ({@link GristWidgetEntry}): the widget,\n * its declaration and any page it replaces. The older form,\n * `mountGristWidget({ App, options: GRIST_OPTIONS, dev })`, still works.\n *\n * Inside Grist, the widget renders in {@link GristWidgetProvider} and\n * {@link GristBoundary}, which gates on its mapped columns when it declares\n * any, and follows Grist's light/dark theme. Outside Grist, where there is\n * nothing to connect to, the page shows `LocalDevPage` on the dev server and\n * `ReleasePage` on a deployed URL.\n */\nexport function mountGristWidget(entry: GristWidgetEntry, options?: { dev?: boolean; root?: Element | string }): MountedGristWidget\nexport function mountGristWidget(config: MountGristWidgetConfig): MountedGristWidget\nexport function mountGristWidget(\n config: MountGristWidgetConfig | GristWidgetEntry,\n entryOptions: { dev?: boolean; root?: Element | string } = {}\n): MountedGristWidget {\n const { root = \"#root\", ...props } =\n isGristWidgetEntry(config) ? { ...entryProps(config, entryOptions.dev), root: entryOptions.root } : config\n const container = typeof root === \"string\" ? document.querySelector(root) : root\n if (!container) {\n throw new Error(`mountGristWidget: no element matches \"${String(root)}\" to render the widget into.`)\n }\n\n const reactRoot = createRoot(container)\n reactRoot.render(\n <StrictMode>\n <GristWidgetApp {...props} />\n </StrictMode>\n )\n return { unmount: () => reactRoot.unmount() }\n}\n\n/**\n * The tree {@link mountGristWidget} renders, as a component: for a test, or\n * for a page that manages its own React root.\n */\nexport function GristWidgetApp({\n App,\n options,\n metadata,\n dev = false,\n Alerts = WidgetAlerts,\n LocalDevPage = DefaultLocalDevPage,\n ReleasePage = DefaultReleasePage,\n}: GristWidgetAppProps) {\n const Wrap = Alerts ?? PassThrough\n if (isEmbedded()) {\n return (\n <GristWidgetProvider options={options}>\n <PageMetadata metadata={metadata} />\n <EmbeddedThemeProvider>\n <GristBoundary>\n <div style={FILL}>\n <Wrap>\n <Suspense fallback={null}>\n <App />\n </Suspense>\n </Wrap>\n </div>\n </GristBoundary>\n </EmbeddedThemeProvider>\n </GristWidgetProvider>\n )\n }\n\n const channel = parseDeployPath(window.location.pathname).channel\n return (\n <StandaloneThemeProvider>\n <PageMetadata metadata={metadata} />\n <div style={FILL}>{dev ? <LocalDevPage /> : <ReleasePage channel={channel} />}</div>\n </StandaloneThemeProvider>\n )\n}\n\nconst FILL = { minHeight: \"100%\", width: \"100%\" } as const\n\n/** A Grist custom widget only ever runs in Grist's iframe. */\nfunction isEmbedded(): boolean {\n return typeof window !== \"undefined\" && window.self !== window.top\n}\n\n/** The page's title and description, from the widget's declaration. */\nfunction PageMetadata({ metadata }: { metadata: GristWidgetAppProps[\"metadata\"] }) {\n useWidgetMetadata(metadata?.title ? { title: metadata.title, description: metadata.description ?? \"\" } : null)\n return null\n}\n\nfunction PassThrough({ children }: { children: ReactNode }) {\n return <>{children}</>\n}\n","import { useEffect, useState } from \"react\"\n\nimport {\n cardStyle,\n cardTextStyle,\n cardTitleStyle,\n codeStyle,\n eyebrowStyle,\n headingStyle,\n leadStyle,\n pageStyle,\n} from \"./tokens\"\nimport { widgetTitle } from \"./widget-title\"\n\n/**\n * Whether the widget has a demo page (`public/demo/`). The dev server serves\n * it at `demo/index.html` (Vite answers a bare `demo/` with the app's own page).\n */\nfunction useHasDemo(): boolean | null {\n const [has, setHas] = useState<boolean | null>(null)\n useEffect(() => {\n if (typeof fetch !== \"function\") return\n let live = true\n fetch(\"demo/demo.grist\", { method: \"HEAD\" })\n .then((res) => live && setHas(res.ok))\n .catch(() => live && setHas(false))\n return () => {\n live = false\n }\n }, [])\n return has\n}\n\n/**\n * Shown outside Grist on the dev server. Deliberately not a preview of the\n * widget: an emulator can't match real Grist. It points at the loops worth\n * trusting: the widget in real Grist running in this browser (the demo page,\n * grist-static, on this dev server's build, so edits reload in place),\n * `pnpm test`, and the `dev` branch's preview inside a Grist document.\n */\nexport function LocalDevPage() {\n const hasDemo = useHasDemo()\n return (\n <main style={pageStyle}>\n <p style={eyebrowStyle}>{widgetTitle()} · local dev</p>\n <h1 style={headingStyle}>Not embedded in Grist</h1>\n <p style={leadStyle}>This is the local dev server: there's no Grist here to render the widget against.</p>\n\n <section style={cardStyle}>\n <h2 style={cardTitleStyle}>Open it in Grist, in this browser</h2>\n {hasDemo === false ? (\n <p style={cardTextStyle}>\n Run <code style={codeStyle}>pnpm demo --save</code> once (it needs Docker): it writes{\" \"}\n <code style={codeStyle}>public/demo/</code>, a document for this widget. Then{\" \"}\n <a href=\"demo/index.html\">demo/index.html</a> opens it in real Grist, running in the browser, on this dev server's\n widget: edits reload in place.\n </p>\n ) : (\n <p style={cardTextStyle}>\n <a href=\"demo/index.html\">Open demo/index.html</a>: real Grist running in the browser (no server, nothing saved), with\n this dev server's widget, so edits reload in place. Its document is{\" \"}\n <code style={codeStyle}>public/demo/demo.grist</code>: after changing the declared columns, run{\" \"}\n <code style={codeStyle}>pnpm demo --save</code> (Docker) to regenerate it.\n </p>\n )}\n </section>\n\n <section style={cardStyle}>\n <h2 style={cardTitleStyle}>Check it against real Grist</h2>\n <p style={cardTextStyle}>\n Push to <code style={codeStyle}>dev</code>, then open its <code style={codeStyle}>/dev/</code> URL in a\n custom widget of a real Grist document: later pushes reload it there within seconds. Locally,{\" \"}\n <code style={codeStyle}>pnpm test</code> runs the widget against an emulated Grist.\n </p>\n </section>\n\n <section style={cardStyle}>\n <h2 style={cardTitleStyle}>Starting from another example?</h2>\n <p style={cardTextStyle}>\n <code style={codeStyle}>npx create-grist-widget list</code> shows the examples, and{\" \"}\n <code style={codeStyle}>npx create-grist-widget use <example></code> swaps this widget for one.\n </p>\n </section>\n </main>\n )\n}\n","import type { CSSProperties } from \"react\"\n\n/**\n * The chrome's colours and radius: shadcn's CSS variables, so the pages\n * follow a widget's theme (light, dark, its own palette) without depending\n * on its Tailwind config, with neutral fallbacks for a widget without them.\n * Same approach as GristBoundaryScreen.\n */\nconst token = (name: string, fallback: string) => `var(--${name}, ${fallback})`\n\nexport const tokens = {\n background: token(\"background\", \"#ffffff\"),\n foreground: token(\"foreground\", \"#0a0a0a\"),\n card: token(\"card\", \"#ffffff\"),\n mutedForeground: token(\"muted-foreground\", \"#737373\"),\n border: token(\"border\", \"#e5e5e5\"),\n primary: token(\"primary\", \"#171717\"),\n primaryForeground: token(\"primary-foreground\", \"#fafafa\"),\n destructive: token(\"destructive\", \"#dc2626\"),\n radius: token(\"radius\", \"0.625rem\"),\n} as const\n\nexport const pageStyle: CSSProperties = {\n boxSizing: \"border-box\",\n display: \"flex\",\n flexDirection: \"column\",\n justifyContent: \"center\",\n maxWidth: \"28rem\",\n minHeight: \"100%\",\n margin: \"0 auto\",\n padding: \"4rem 1.5rem\",\n color: tokens.foreground,\n font: \"inherit\",\n}\n\nexport const eyebrowStyle: CSSProperties = {\n margin: \"0 0 0.5rem\",\n textAlign: \"center\",\n fontSize: \"0.875rem\",\n fontWeight: 500,\n color: tokens.mutedForeground,\n}\n\nexport const headingStyle: CSSProperties = {\n margin: 0,\n textAlign: \"center\",\n fontSize: \"1.5rem\",\n fontWeight: 600,\n letterSpacing: \"-0.01em\",\n}\n\nexport const leadStyle: CSSProperties = {\n margin: \"0.75rem auto 2rem\",\n maxWidth: \"24rem\",\n textAlign: \"center\",\n fontSize: \"0.875rem\",\n lineHeight: 1.5,\n color: tokens.mutedForeground,\n}\n\nexport const cardStyle: CSSProperties = {\n boxSizing: \"border-box\",\n marginBottom: \"1rem\",\n padding: \"1.25rem\",\n border: `1px solid ${tokens.border}`,\n borderRadius: tokens.radius,\n background: tokens.card,\n}\n\nexport const cardTitleStyle: CSSProperties = {\n margin: \"0 0 0.375rem\",\n fontSize: \"1rem\",\n fontWeight: 600,\n}\n\nexport const cardTextStyle: CSSProperties = {\n margin: 0,\n fontSize: \"0.875rem\",\n lineHeight: 1.5,\n color: tokens.mutedForeground,\n}\n\nexport const codeStyle: CSSProperties = {\n fontFamily: \"ui-monospace, SFMono-Regular, Menlo, monospace\",\n fontSize: \"0.8125rem\",\n color: tokens.foreground,\n}\n","/**\n * The widget's name for the pages shown outside Grist: the page title,\n * which `create-grist-widget` sets to the widget's title in `index.html`.\n */\nexport function widgetTitle(): string {\n const title = typeof document === \"undefined\" ? \"\" : document.title.trim()\n return title || \"Grist widget\"\n}\n","import { useState, type CSSProperties } from \"react\"\n\nimport { deployChannelLabel, parseDeployPath, type DeployChannel } from \"../deploy-path\"\nimport { useReleasedVersions } from \"../released-versions\"\nimport {\n cardStyle,\n cardTextStyle,\n cardTitleStyle,\n codeStyle,\n eyebrowStyle,\n headingStyle,\n leadStyle,\n pageStyle,\n tokens,\n} from \"./tokens\"\nimport { widgetTitle } from \"./widget-title\"\n\n/**\n * Shown outside Grist on a deployed URL (`/latest/`, `/dev/`, `/v<version>/`\n * or the root): which build this is, links to the others, and the URL to\n * paste into a Grist custom widget.\n */\nexport function ReleasePage({ channel }: { channel: DeployChannel }) {\n const label = deployChannelLabel(channel)\n return (\n <main style={pageStyle}>\n <p style={eyebrowStyle}>\n {widgetTitle()} · {label}\n </p>\n <h1 style={headingStyle}>Grist isn't loaded here</h1>\n <p style={leadStyle}>\n This is the <code style={codeStyle}>{label}</code> build, opened outside Grist. Hover a version to see when it\n was released.\n </p>\n <ChannelLinks current={channel} />\n <InstallUrl />\n </main>\n )\n}\n\nfunction ChannelLinks({ current }: { current: DeployChannel }) {\n const { basePath } = parseDeployPath(window.location.pathname)\n const { versions } = useReleasedVersions()\n const isCurrent = (channel: DeployChannel) =>\n channel.kind === current.kind && (channel.kind !== \"version\" || (current.kind === \"version\" && channel.version === current.version))\n\n return (\n <nav aria-label=\"Versions\" style={{ display: \"flex\", flexWrap: \"wrap\", justifyContent: \"center\", gap: \"0.5rem\", marginBottom: \"2rem\" }}>\n <ChannelLink href={`${basePath}latest/`} active={isCurrent({ kind: \"latest\" })}>\n latest\n </ChannelLink>\n <ChannelLink href={`${basePath}dev/`} active={isCurrent({ kind: \"dev\" })}>\n dev\n </ChannelLink>\n {versions?.map((v) => (\n <ChannelLink\n key={v.version}\n href={`${basePath}v${v.version}/`}\n title={formatDate(v.publishedAt)}\n active={isCurrent({ kind: \"version\", version: v.version })}\n >\n {`v${v.version}`}\n </ChannelLink>\n ))}\n </nav>\n )\n}\n\nfunction ChannelLink({\n href,\n title,\n active,\n children,\n}: {\n href: string\n title?: string\n active: boolean\n children: string\n}) {\n const style: CSSProperties = {\n padding: \"0.25rem 0.75rem\",\n border: `1px solid ${active ? tokens.primary : tokens.border}`,\n borderRadius: \"9999px\",\n background: active ? tokens.primary : \"transparent\",\n color: active ? tokens.primaryForeground : tokens.mutedForeground,\n fontSize: \"0.75rem\",\n fontWeight: 500,\n textDecoration: \"none\",\n }\n return (\n <a href={href} title={title} aria-current={active ? \"page\" : undefined} style={style}>\n {children}\n </a>\n )\n}\n\nfunction InstallUrl() {\n const url = window.location.href\n const [copied, setCopied] = useState(false)\n\n function copy() {\n void navigator.clipboard?.writeText(url).then(() => {\n setCopied(true)\n setTimeout(() => setCopied(false), 1500)\n })\n }\n\n return (\n <section style={cardStyle}>\n <h2 style={cardTitleStyle}>Use it as a Grist custom widget</h2>\n <p style={{ ...cardTextStyle, marginBottom: \"1rem\" }}>Paste this URL into a custom widget's URL field in Grist.</p>\n <div style={{ display: \"flex\", gap: \"0.5rem\" }}>\n <input\n readOnly\n value={url}\n aria-label=\"Widget URL\"\n onFocus={(event) => event.target.select()}\n style={{\n flex: 1,\n minWidth: 0,\n padding: \"0.5rem 0.75rem\",\n border: `1px solid ${tokens.border}`,\n borderRadius: tokens.radius,\n background: \"transparent\",\n color: tokens.foreground,\n font: \"inherit\",\n fontSize: \"0.875rem\",\n }}\n />\n <button\n type=\"button\"\n onClick={copy}\n style={{\n padding: \"0.5rem 1rem\",\n border: \"none\",\n borderRadius: tokens.radius,\n background: tokens.primary,\n color: tokens.primaryForeground,\n font: \"inherit\",\n fontSize: \"0.875rem\",\n fontWeight: 500,\n cursor: \"pointer\",\n }}\n >\n {copied ? \"Copied\" : \"Copy\"}\n </button>\n </div>\n </section>\n )\n}\n\nfunction formatDate(iso: string): string {\n const date = new Date(iso)\n return Number.isNaN(date.getTime())\n ? iso\n : date.toLocaleDateString(undefined, { year: \"numeric\", month: \"short\", day: \"numeric\" })\n}\n","/**\n * The alerts `mountGristWidget()` shows above a running widget: what needs the\n * user's attention in Grist (column mapping, access, a failed write, an\n * unlinked section). The blocking states (not connected, access refused,\n * required columns unmapped) are `<GristBoundary>`'s, not alerts.\n */\n\nimport { useNearestGristState } from \"../use-grist\"\nimport { deriveColumnMappingStatus, deriveStatus } from \"../runtime/derive\"\nimport { isAccessInsufficientError } from \"../runtime/api\"\nimport type { GristCellIssue } from \"../runtime/cells\"\nimport type { GristRuntimeState } from \"../runtime/runtime\"\nimport type { GristColumnsToMap, GristWidgetInteraction } from \"../types\"\nimport { parseGristWidgetLinkingInfo } from \"./grist-widget-interaction\"\n\nexport type GristSdkAlertKind =\n | \"column-mapping\"\n | \"mapping-pending\"\n | \"section-not-linked\"\n | \"source-not-wired\"\n | \"action-error\"\n | \"access-insufficient\"\n | \"map-back-skip\"\n | \"cell-issues\"\n\nexport type GristSdkAlertSeverity = \"info\" | \"warning\" | \"error\"\n\nexport type GristSdkAlertDescriptor = {\n id: string\n kind: GristSdkAlertKind\n severity: GristSdkAlertSeverity\n title: string\n ariaRole: \"status\" | \"alert\"\n message: string\n}\n\nexport type GristSdkAlertsOptions = {\n /** Added to the \"section not linked\" message, e.g. how to link in Grist. */\n sectionNotLinkedHint?: string\n}\n\nconst TITLE: Record<GristSdkAlertKind, string> = {\n \"column-mapping\": \"Column mapping\",\n \"mapping-pending\": \"Column mapping\",\n \"section-not-linked\": \"Widget linking\",\n \"source-not-wired\": \"Widget linking\",\n \"action-error\": \"Action error\",\n \"access-insufficient\": \"Access level\",\n \"map-back-skip\": \"Write skipped\",\n \"cell-issues\": \"Unexpected values\",\n}\n\nconst SEVERITY: Record<GristSdkAlertKind, GristSdkAlertSeverity> = {\n \"column-mapping\": \"warning\",\n \"mapping-pending\": \"info\",\n \"section-not-linked\": \"warning\",\n \"source-not-wired\": \"warning\",\n \"action-error\": \"error\",\n \"access-insufficient\": \"error\",\n \"map-back-skip\": \"warning\",\n \"cell-issues\": \"warning\",\n}\n\nconst alert = (kind: GristSdkAlertKind, message: string, ariaRole: \"status\" | \"alert\" = \"status\"): GristSdkAlertDescriptor => ({\n id: kind,\n kind,\n severity: SEVERITY[kind],\n title: TITLE[kind],\n ariaRole,\n message,\n})\n\n/** A widget section Grist says is linked to nothing. */\nexport function isWidgetSectionNotLinked(interaction: GristWidgetInteraction | null | undefined): boolean {\n const linking = parseGristWidgetLinkingInfo(interaction?.linking)\n return Boolean(linking) && linking!.asTarget == null\n}\n\n/** The alerts for a widget in `state`, pure (tested without React). */\nexport function getGristSdkAlerts(\n state: GristRuntimeState,\n widget: {\n columns?: GristColumnsToMap\n allowSelectBy?: boolean\n suppressAlerts?: readonly GristSdkAlertKind[]\n cellIssues?: readonly GristCellIssue[]\n },\n options: GristSdkAlertsOptions = {}\n): GristSdkAlertDescriptor[] {\n if (deriveStatus(state) !== \"ready\") return []\n const out: GristSdkAlertDescriptor[] = []\n\n const mapping = deriveColumnMappingStatus(widget.columns, state.mappings)\n if (mapping.pending) out.push(alert(\"mapping-pending\", \"Waiting for Grist to report column mappings.\"))\n else if (!mapping.ok) {\n const parts = [\"Column mapping is incomplete.\"]\n if (mapping.missing.length) parts.push(`Required columns: ${mapping.missing.join(\", \")}.`)\n if (mapping.emptyMultiples.length) parts.push(`Assign at least one sheet column for: ${mapping.emptyMultiples.join(\", \")}.`)\n out.push(alert(\"column-mapping\", parts.join(\" \")))\n }\n\n const failure = state.actionError ?? state.readError\n if (failure && isAccessInsufficientError(failure)) {\n out.push(\n alert(\n \"access-insufficient\",\n 'This operation requires \"Full document access\". Set the Access level to \"Full document access\" in the Custom widget configuration panel.',\n \"alert\"\n )\n )\n } else if (state.actionError) {\n out.push(alert(\"action-error\", state.actionError, \"alert\"))\n }\n\n if (state.mapBackSkipped.length) {\n const list = state.mapBackSkipped.join(\", \")\n out.push(alert(\"map-back-skip\", `mapBack skipped multi-mapped column${state.mapBackSkipped.length === 1 ? \"\" : \"s\"}: ${list}.`))\n }\n\n const cellIssues = widget.cellIssues ?? []\n if (cellIssues.length) {\n const first = cellIssues[0]!\n const where = first.column ? `${first.column} in row ${first.rowId}` : `row ${first.rowId}`\n const more = cellIssues.length > 1 ? ` (and ${cellIssues.length - 1} more)` : \"\"\n out.push(alert(\"cell-issues\", `${where}: ${first.message}${more}. Check the column's type, or the cell, in Grist.`))\n }\n\n const linking = parseGristWidgetLinkingInfo(state.interaction?.linking)\n if (widget.allowSelectBy) {\n if (linking && !linking.asSource) {\n out.push(\n alert(\n \"source-not-wired\",\n \"This widget is configured as a selector (allowSelectBy) but no other section is using it as a link source yet. Link another section to read from this widget.\"\n )\n )\n }\n } else if (isWidgetSectionNotLinked(state.interaction)) {\n const hint = options.sectionNotLinkedHint?.trim()\n out.push(\n alert(\n \"section-not-linked\",\n \"This widget section is not linked to a table or selector. Link it from the page settings so the selected row is sent to the widget.\" +\n (hint ? ` ${hint}` : \"\")\n )\n )\n }\n\n const suppressed = widget.suppressAlerts ?? []\n return out.filter((a) => !suppressed.includes(a.kind))\n}\n\n/** @internal The alerts for the widget under the nearest `<GristWidgetProvider>`; [] outside one. */\nexport function useGristSdkAlerts(options?: GristSdkAlertsOptions): GristSdkAlertDescriptor[] {\n const { connection, state, cellIssues } = useNearestGristState()\n if (!connection) return []\n const { columns, allowSelectBy, suppressAlerts } = connection.runtime.options\n return getGristSdkAlerts(state, { columns, allowSelectBy, suppressAlerts, cellIssues }, options)\n}\n","import type { CSSProperties, ReactNode } from \"react\"\n\nimport { useGristSdkAlerts, type GristSdkAlertDescriptor, type GristSdkAlertsOptions } from \"../../sdk/helpers/grist-sdk-alerts\"\nimport { tokens } from \"./tokens\"\n\nconst ALERT_OPTIONS: GristSdkAlertsOptions = {\n sectionNotLinkedHint:\n \"In Grist, select this widget section on the page, then use Link to connect a table, card, or chart view as the selector.\",\n}\n\n/**\n * The default `Alerts` of {@link mountGristWidget}: what needs the user's\n * attention (column mapping, access level, failed writes, an unlinked\n * section), above the widget. Renders nothing extra when all is well.\n */\nexport function WidgetAlerts({ children }: { children: ReactNode }) {\n const alerts = useGristSdkAlerts(ALERT_OPTIONS)\n if (alerts.length === 0) return <>{children}</>\n\n return (\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"0.75rem\" }}>\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"0.75rem\", padding: \"0.75rem 0.75rem 0\" }}>\n {alerts.map((alert) => (\n <WidgetAlert key={alert.id} alert={alert} />\n ))}\n </div>\n {children}\n </div>\n )\n}\n\nfunction WidgetAlert({ alert }: { alert: GristSdkAlertDescriptor }) {\n const linkIcon = alert.kind === \"section-not-linked\" || alert.kind === \"source-not-wired\"\n return (\n <div role={alert.ariaRole} style={{ ...alertStyle, ...SEVERITY[alert.severity] }}>\n <span aria-hidden style={{ flexShrink: 0, marginTop: \"0.125rem\" }}>\n {linkIcon ? <LinkIcon /> : <WarningIcon />}\n </span>\n <div style={{ minWidth: 0 }}>\n <p style={{ margin: 0, fontWeight: 500 }}>{alert.title}</p>\n <p style={{ margin: \"0.25rem 0 0\", color: tokens.mutedForeground }}>{alert.message}</p>\n </div>\n </div>\n )\n}\n\nconst alertStyle: CSSProperties = {\n boxSizing: \"border-box\",\n display: \"flex\",\n gap: \"0.75rem\",\n padding: \"0.75rem 1rem\",\n border: `1px solid ${tokens.border}`,\n borderRadius: tokens.radius,\n color: tokens.foreground,\n fontSize: \"0.875rem\",\n lineHeight: 1.5,\n}\n\nconst SEVERITY: Record<GristSdkAlertDescriptor[\"severity\"], CSSProperties> = {\n error: { borderColor: tokens.destructive, color: tokens.destructive },\n warning: { borderColor: \"rgb(245 158 11 / 0.4)\", background: \"rgb(245 158 11 / 0.1)\" },\n info: { background: \"transparent\" },\n}\n\nconst ICON = {\n width: 16,\n height: 16,\n viewBox: \"0 0 24 24\",\n fill: \"none\",\n stroke: \"currentColor\",\n strokeWidth: 2,\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\",\n} as const\n\nfunction WarningIcon() {\n return (\n <svg {...ICON}>\n <path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\" />\n <path d=\"M12 9v4\" />\n <path d=\"M12 17h.01\" />\n </svg>\n )\n}\n\nfunction LinkIcon() {\n return (\n <svg {...ICON}>\n <path d=\"M9 17H7A5 5 0 0 1 7 7h2\" />\n <path d=\"M15 7h2a5 5 0 1 1 0 10h-2\" />\n <line x1=\"8\" x2=\"16\" y1=\"12\" y2=\"12\" />\n </svg>\n )\n}\n"],"mappings":";;;;;;;;;;;;;AAuBA,IAAM,kBAAkB;AAOjB,SAAS,gBAAgB,UAA8B;AAC5D,QAAM,WAAW,SAAS,QAAQ,QAAQ,EAAE,EAAE,MAAM,GAAG;AACvD,QAAM,OAAO,SAAS,SAAS,SAAS,CAAC,KAAK;AAE9C,MAAI,UAAgC;AACpC,MAAI,SAAS,SAAU,WAAU,EAAE,MAAM,SAAS;AAAA,WACzC,SAAS,MAAO,WAAU,EAAE,MAAM,MAAM;AAAA,OAC5C;AACH,UAAM,QAAQ,gBAAgB,KAAK,IAAI;AACvC,QAAI,MAAO,WAAU,EAAE,MAAM,WAAW,SAAS,MAAM,CAAC,EAAE;AAAA,EAC5D;AAEA,MAAI,CAAC,QAAS,QAAO,EAAE,SAAS,EAAE,MAAM,SAAS,GAAG,UAAU,kBAAkB,QAAQ,EAAE;AAC1F,SAAO,EAAE,SAAS,UAAU,kBAAkB,SAAS,MAAM,GAAG,EAAE,EAAE,KAAK,GAAG,CAAC,EAAE;AACjF;AAGO,SAAS,mBAAmB,SAAgC;AACjE,SAAO,QAAQ,SAAS,YAAY,IAAI,QAAQ,OAAO,KAAK,QAAQ;AACtE;AAEA,SAAS,kBAAkB,MAAsB;AAC/C,SAAO,KAAK,SAAS,GAAG,IAAI,OAAO,GAAG,IAAI;AAC5C;;;ACrDA,SAAS,WAAW,gBAAgB;AAsB7B,SAAS,oBACd,WAAmB,OAAO,WAAW,cAAc,MAAM,OAAO,SAAS,UAC9C;AAC3B,QAAM,MAAM,GAAG,gBAAgB,QAAQ,EAAE,QAAQ;AACjD,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAoC,EAAE,UAAU,MAAM,OAAO,MAAM,CAAC;AAEhG,YAAU,MAAM;AACd,QAAI,YAAY;AAChB,UAAM,KAAK,EAAE,OAAO,WAAW,CAAC,EAC7B,KAAK,CAAC,QAAS,IAAI,KAAK,IAAI,KAAK,IAAI,QAAQ,OAAO,IAAI,MAAM,QAAQ,IAAI,MAAM,EAAE,CAAC,CAAE,EACrF,KAAK,CAAC,SAAkB;AACvB,UAAI,UAAW;AACf,UAAI,CAAC,MAAM,QAAQ,IAAI,EAAG,OAAM,IAAI,MAAM,+BAA+B;AACzE,gBAAU,EAAE,UAAU,MAA2B,OAAO,MAAM,CAAC;AAAA,IACjE,CAAC,EACA,MAAM,MAAM;AACX,UAAI,CAAC,UAAW,WAAU,EAAE,UAAU,MAAM,OAAO,KAAK,CAAC;AAAA,IAC3D,CAAC;AACH,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,GAAG,CAAC;AAER,SAAO;AACT;;;AC9CA,SAAS,eAAe,aAAa,YAAY,aAAAA,YAAW,SAAS,YAAAC,iBAAgC;AAoD5F;AA9BT,IAAM,cAAc;AACpB,IAAM,aAAa;AACnB,IAAM,SAAiC,CAAC,SAAS,QAAQ,QAAQ;AAEjE,IAAM,eAAe,cAAqC,IAAI;AASvD,SAAS,WAA2B;AACzC,QAAM,QAAQ,WAAW,YAAY;AACrC,SAAO,SAAS,EAAE,OAAO,UAAU,eAAe,YAAY,GAAG,UAAU,KAAK;AAClF;AAGO,SAAS,sBAAsB,EAAE,SAAS,GAA4B;AAC3E,QAAM,aAAa,qBAAqB,EAAE,MAAM;AAChD,QAAM,SAAS,eAAe,eAAe,IAAI;AACjD,QAAM,gBAAgB,cAAc;AAEpC,gBAAc,aAAa;AAE3B,QAAM,QAAQ;AAAA,IACZ,OAAO,EAAE,OAAO,cAAc,UAAU,eAAe,UAAU,KAAK;AAAA,IACtE,CAAC,YAAY,aAAa;AAAA,EAC5B;AACA,SAAO,oBAAC,aAAa,UAAb,EAAsB,OAAe,UAAS;AACxD;AAOO,SAAS,wBAAwB,EAAE,SAAS,GAA4B;AAC7E,QAAM,CAAC,OAAO,aAAa,IAAIC,UAAsB,MAAM,gBAAgB,KAAK,QAAQ;AACxF,QAAM,SAAS,eAAe,UAAU,QAAQ;AAChD,QAAM,gBAAgB,UAAU,WAAW,SAAS;AAEpD,gBAAc,aAAa;AAE3B,QAAM,WAAW,YAAY,CAAC,SAAsB;AAClD,qBAAiB,IAAI;AACrB,kBAAc,IAAI;AAAA,EACpB,GAAG,CAAC,CAAC;AAGL,EAAAC,WAAU,MAAM;AACd,UAAM,YAAY,CAAC,UAAyB;AAC1C,UAAI,MAAM,UAAU,MAAM,WAAW,MAAM,WAAW,MAAM,OAAQ;AACpE,UAAI,MAAM,IAAI,YAAY,MAAM,OAAO,iBAAiB,MAAM,MAAM,EAAG;AACvE,oBAAc,CAAC,YAAY;AACzB,cAAM,kBAAkB,YAAY,WAAW,YAAY,IAAI;AAC/D,cAAM,OAAoB,oBAAoB,SAAS,UAAU;AACjE,yBAAiB,IAAI;AACrB,eAAO;AAAA,MACT,CAAC;AAAA,IACH;AACA,WAAO,iBAAiB,WAAW,SAAS;AAC5C,WAAO,MAAM,OAAO,oBAAoB,WAAW,SAAS;AAAA,EAC9D,GAAG,CAAC,CAAC;AAGL,EAAAA,WAAU,MAAM;AACd,UAAM,YAAY,CAAC,UAAwB;AACzC,UAAI,MAAM,QAAQ,YAAa;AAC/B,oBAAc,QAAQ,MAAM,QAAQ,IAAI,MAAM,WAAW,QAAQ;AAAA,IACnE;AACA,WAAO,iBAAiB,WAAW,SAAS;AAC5C,WAAO,MAAM,OAAO,oBAAoB,WAAW,SAAS;AAAA,EAC9D,GAAG,CAAC,CAAC;AAEL,QAAM,QAAQ;AAAA,IACZ,OAAO,EAAE,OAAO,eAAe,SAAS;AAAA,IACxC,CAAC,OAAO,eAAe,QAAQ;AAAA,EACjC;AACA,SAAO,oBAAC,aAAa,UAAb,EAAsB,OAAe,UAAS;AACxD;AAGA,SAAS,eAAe,QAAsC;AAC5D,QAAM,CAAC,OAAO,QAAQ,IAAID,UAA8B,WAAW;AAEnE,EAAAC,WAAU,MAAM;AACd,QAAI,CAAC,UAAU,OAAO,OAAO,eAAe,WAAY;AACxD,UAAM,QAAQ,OAAO,WAAW,UAAU;AAC1C,UAAM,WAAW,MAAM,SAAS,MAAM,UAAU,SAAS,OAAO;AAChE,aAAS;AACT,UAAM,iBAAiB,UAAU,QAAQ;AACzC,WAAO,MAAM,MAAM,oBAAoB,UAAU,QAAQ;AAAA,EAC3D,GAAG,CAAC,MAAM,CAAC;AAEX,SAAO;AACT;AAGA,SAAS,cAAc,OAA4B;AACjD,EAAAA,WAAU,MAAM;AACd,UAAM,OAAO,SAAS;AACtB,QAAI,KAAK,UAAU,SAAS,KAAK,KAAK,CAAC,KAAK,UAAU,SAAS,MAAM,KAAK,CAAC,EAAG;AAC9E,UAAM,qBAAqB,mBAAmB;AAC9C,SAAK,UAAU,OAAO,MAAM,KAAK,CAAC;AAClC,SAAK,UAAU,IAAI,KAAK;AACxB,uBAAmB;AAAA,EACrB,GAAG,CAAC,KAAK,CAAC;AACZ;AAEA,SAAS,cAAmC;AAC1C,MAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,WAAY,QAAO;AACrF,SAAO,OAAO,WAAW,UAAU,EAAE,UAAU,SAAS;AAC1D;AAEA,SAAS,MAAM,OAAiD;AAC9D,SAAO,UAAU,SAAS,UAAU;AACtC;AAGA,SAAS,qBAAiC;AACxC,QAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,QAAM;AAAA,IACJ,SAAS,eAAe,mFAAmF;AAAA,EAC7G;AACA,WAAS,KAAK,YAAY,KAAK;AAC/B,SAAO,MAAM;AACX,WAAO,iBAAiB,SAAS,IAAI;AACrC,0BAAsB,MAAM,sBAAsB,MAAM,MAAM,OAAO,CAAC,CAAC;AAAA,EACzE;AACF;AAEA,SAAS,iBAAiB,QAAqC;AAC7D,MAAI,EAAE,kBAAkB,aAAc,QAAO;AAC7C,SAAO,OAAO,qBAAqB,OAAO,QAAQ,mDAAmD,MAAM;AAC7G;AAEA,SAAS,QAAQ,OAA4C;AAC3D,SAAO,UAAU,QAAS,OAA6B,SAAS,KAAK;AACvE;AAEA,SAAS,kBAAsC;AAC7C,MAAI;AACF,UAAM,QAAQ,aAAa,QAAQ,WAAW;AAC9C,WAAO,QAAQ,KAAK,IAAI,QAAQ;AAAA,EAClC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,iBAAiB,OAAoB;AAC5C,MAAI;AACF,iBAAa,QAAQ,aAAa,KAAK;AAAA,EACzC,QAAQ;AAAA,EAER;AACF;AAEA,SAAS,OAAO;AAAC;;;ACrLjB,SAAS,YAAY,gBAAoD;AACzE,SAAS,kBAAkB;;;ACD3B,SAAS,aAAAC,YAAW,YAAAC,iBAAgB;;;ACQpC,IAAM,QAAQ,CAAC,MAAc,aAAqB,SAAS,IAAI,KAAK,QAAQ;AAErE,IAAM,SAAS;AAAA,EACpB,YAAY,MAAM,cAAc,SAAS;AAAA,EACzC,YAAY,MAAM,cAAc,SAAS;AAAA,EACzC,MAAM,MAAM,QAAQ,SAAS;AAAA,EAC7B,iBAAiB,MAAM,oBAAoB,SAAS;AAAA,EACpD,QAAQ,MAAM,UAAU,SAAS;AAAA,EACjC,SAAS,MAAM,WAAW,SAAS;AAAA,EACnC,mBAAmB,MAAM,sBAAsB,SAAS;AAAA,EACxD,aAAa,MAAM,eAAe,SAAS;AAAA,EAC3C,QAAQ,MAAM,UAAU,UAAU;AACpC;AAEO,IAAM,YAA2B;AAAA,EACtC,WAAW;AAAA,EACX,SAAS;AAAA,EACT,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,OAAO,OAAO;AAAA,EACd,MAAM;AACR;AAEO,IAAM,eAA8B;AAAA,EACzC,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,OAAO,OAAO;AAChB;AAEO,IAAM,eAA8B;AAAA,EACzC,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,eAAe;AACjB;AAEO,IAAM,YAA2B;AAAA,EACtC,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,WAAW;AAAA,EACX,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,OAAO,OAAO;AAChB;AAEO,IAAM,YAA2B;AAAA,EACtC,WAAW;AAAA,EACX,cAAc;AAAA,EACd,SAAS;AAAA,EACT,QAAQ,aAAa,OAAO,MAAM;AAAA,EAClC,cAAc,OAAO;AAAA,EACrB,YAAY,OAAO;AACrB;AAEO,IAAM,iBAAgC;AAAA,EAC3C,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,YAAY;AACd;AAEO,IAAM,gBAA+B;AAAA,EAC1C,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,OAAO,OAAO;AAChB;AAEO,IAAM,YAA2B;AAAA,EACtC,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,OAAO,OAAO;AAChB;;;AClFO,SAAS,cAAsB;AACpC,QAAM,QAAQ,OAAO,aAAa,cAAc,KAAK,SAAS,MAAM,KAAK;AACzE,SAAO,SAAS;AAClB;;;AFqCM,SACA,OAAAC,MADA;AA1BN,SAAS,aAA6B;AACpC,QAAM,CAAC,KAAK,MAAM,IAAIC,UAAyB,IAAI;AACnD,EAAAC,WAAU,MAAM;AACd,QAAI,OAAO,UAAU,WAAY;AACjC,QAAI,OAAO;AACX,UAAM,mBAAmB,EAAE,QAAQ,OAAO,CAAC,EACxC,KAAK,CAAC,QAAQ,QAAQ,OAAO,IAAI,EAAE,CAAC,EACpC,MAAM,MAAM,QAAQ,OAAO,KAAK,CAAC;AACpC,WAAO,MAAM;AACX,aAAO;AAAA,IACT;AAAA,EACF,GAAG,CAAC,CAAC;AACL,SAAO;AACT;AASO,SAAS,eAAe;AAC7B,QAAM,UAAU,WAAW;AAC3B,SACE,qBAAC,UAAK,OAAO,WACX;AAAA,yBAAC,OAAE,OAAO,cAAe;AAAA,kBAAY;AAAA,MAAE;AAAA,OAAY;AAAA,IACnD,gBAAAF,KAAC,QAAG,OAAO,cAAc,mCAAqB;AAAA,IAC9C,gBAAAA,KAAC,OAAE,OAAO,WAAW,+FAAiF;AAAA,IAEtG,qBAAC,aAAQ,OAAO,WACd;AAAA,sBAAAA,KAAC,QAAG,OAAO,gBAAgB,+CAAiC;AAAA,MAC3D,YAAY,QACX,qBAAC,OAAE,OAAO,eAAe;AAAA;AAAA,QACnB,gBAAAA,KAAC,UAAK,OAAO,WAAW,8BAAgB;AAAA,QAAO;AAAA,QAAmC;AAAA,QACtF,gBAAAA,KAAC,UAAK,OAAO,WAAW,0BAAY;AAAA,QAAO;AAAA,QAAmC;AAAA,QAC9E,gBAAAA,KAAC,OAAE,MAAK,mBAAkB,6BAAe;AAAA,QAAI;AAAA,SAE/C,IAEA,qBAAC,OAAE,OAAO,eACR;AAAA,wBAAAA,KAAC,OAAE,MAAK,mBAAkB,kCAAoB;AAAA,QAAI;AAAA,QACuB;AAAA,QACzE,gBAAAA,KAAC,UAAK,OAAO,WAAW,oCAAsB;AAAA,QAAO;AAAA,QAA2C;AAAA,QAChG,gBAAAA,KAAC,UAAK,OAAO,WAAW,8BAAgB;AAAA,QAAO;AAAA,SACjD;AAAA,OAEJ;AAAA,IAEA,qBAAC,aAAQ,OAAO,WACd;AAAA,sBAAAA,KAAC,QAAG,OAAO,gBAAgB,yCAA2B;AAAA,MACtD,qBAAC,OAAE,OAAO,eAAe;AAAA;AAAA,QACf,gBAAAA,KAAC,UAAK,OAAO,WAAW,iBAAG;AAAA,QAAO;AAAA,QAAgB,gBAAAA,KAAC,UAAK,OAAO,WAAW,mBAAK;AAAA,QAAO;AAAA,QACA;AAAA,QAC9F,gBAAAA,KAAC,UAAK,OAAO,WAAW,uBAAS;AAAA,QAAO;AAAA,SAC1C;AAAA,OACF;AAAA,IAEA,qBAAC,aAAQ,OAAO,WACd;AAAA,sBAAAA,KAAC,QAAG,OAAO,gBAAgB,4CAA8B;AAAA,MACzD,qBAAC,OAAE,OAAO,eACR;AAAA,wBAAAA,KAAC,UAAK,OAAO,WAAW,0CAA4B;AAAA,QAAO;AAAA,QAAyB;AAAA,QACpF,gBAAAA,KAAC,UAAK,OAAO,WAAW,mDAA2C;AAAA,QAAO;AAAA,SAC5E;AAAA,OACF;AAAA,KACF;AAEJ;;;AGrFA,SAAS,YAAAG,iBAAoC;AA0BvC,SAGA,OAAAC,MAHA,QAAAC,aAAA;AAJC,SAAS,YAAY,EAAE,QAAQ,GAA+B;AACnE,QAAM,QAAQ,mBAAmB,OAAO;AACxC,SACE,gBAAAA,MAAC,UAAK,OAAO,WACX;AAAA,oBAAAA,MAAC,OAAE,OAAO,cACP;AAAA,kBAAY;AAAA,MAAE;AAAA,MAAI;AAAA,OACrB;AAAA,IACA,gBAAAD,KAAC,QAAG,OAAO,cAAc,qCAAuB;AAAA,IAChD,gBAAAC,MAAC,OAAE,OAAO,WAAW;AAAA;AAAA,MACP,gBAAAD,KAAC,UAAK,OAAO,WAAY,iBAAM;AAAA,MAAO;AAAA,OAEpD;AAAA,IACA,gBAAAA,KAAC,gBAAa,SAAS,SAAS;AAAA,IAChC,gBAAAA,KAAC,cAAW;AAAA,KACd;AAEJ;AAEA,SAAS,aAAa,EAAE,QAAQ,GAA+B;AAC7D,QAAM,EAAE,SAAS,IAAI,gBAAgB,OAAO,SAAS,QAAQ;AAC7D,QAAM,EAAE,SAAS,IAAI,oBAAoB;AACzC,QAAM,YAAY,CAAC,YACjB,QAAQ,SAAS,QAAQ,SAAS,QAAQ,SAAS,aAAc,QAAQ,SAAS,aAAa,QAAQ,YAAY,QAAQ;AAE7H,SACE,gBAAAC,MAAC,SAAI,cAAW,YAAW,OAAO,EAAE,SAAS,QAAQ,UAAU,QAAQ,gBAAgB,UAAU,KAAK,UAAU,cAAc,OAAO,GACnI;AAAA,oBAAAD,KAAC,eAAY,MAAM,GAAG,QAAQ,WAAW,QAAQ,UAAU,EAAE,MAAM,SAAS,CAAC,GAAG,oBAEhF;AAAA,IACA,gBAAAA,KAAC,eAAY,MAAM,GAAG,QAAQ,QAAQ,QAAQ,UAAU,EAAE,MAAM,MAAM,CAAC,GAAG,iBAE1E;AAAA,IACC,UAAU,IAAI,CAAC,MACd,gBAAAA;AAAA,MAAC;AAAA;AAAA,QAEC,MAAM,GAAG,QAAQ,IAAI,EAAE,OAAO;AAAA,QAC9B,OAAO,WAAW,EAAE,WAAW;AAAA,QAC/B,QAAQ,UAAU,EAAE,MAAM,WAAW,SAAS,EAAE,QAAQ,CAAC;AAAA,QAExD,cAAI,EAAE,OAAO;AAAA;AAAA,MALT,EAAE;AAAA,IAMT,CACD;AAAA,KACH;AAEJ;AAEA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,QAAuB;AAAA,IAC3B,SAAS;AAAA,IACT,QAAQ,aAAa,SAAS,OAAO,UAAU,OAAO,MAAM;AAAA,IAC5D,cAAc;AAAA,IACd,YAAY,SAAS,OAAO,UAAU;AAAA,IACtC,OAAO,SAAS,OAAO,oBAAoB,OAAO;AAAA,IAClD,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,gBAAgB;AAAA,EAClB;AACA,SACE,gBAAAA,KAAC,OAAE,MAAY,OAAc,gBAAc,SAAS,SAAS,QAAW,OACrE,UACH;AAEJ;AAEA,SAAS,aAAa;AACpB,QAAM,MAAM,OAAO,SAAS;AAC5B,QAAM,CAAC,QAAQ,SAAS,IAAIE,UAAS,KAAK;AAE1C,WAAS,OAAO;AACd,SAAK,UAAU,WAAW,UAAU,GAAG,EAAE,KAAK,MAAM;AAClD,gBAAU,IAAI;AACd,iBAAW,MAAM,UAAU,KAAK,GAAG,IAAI;AAAA,IACzC,CAAC;AAAA,EACH;AAEA,SACE,gBAAAD,MAAC,aAAQ,OAAO,WACd;AAAA,oBAAAD,KAAC,QAAG,OAAO,gBAAgB,6CAA+B;AAAA,IAC1D,gBAAAA,KAAC,OAAE,OAAO,EAAE,GAAG,eAAe,cAAc,OAAO,GAAG,uEAAyD;AAAA,IAC/G,gBAAAC,MAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,KAAK,SAAS,GAC3C;AAAA,sBAAAD;AAAA,QAAC;AAAA;AAAA,UACC,UAAQ;AAAA,UACR,OAAO;AAAA,UACP,cAAW;AAAA,UACX,SAAS,CAAC,UAAU,MAAM,OAAO,OAAO;AAAA,UACxC,OAAO;AAAA,YACL,MAAM;AAAA,YACN,UAAU;AAAA,YACV,SAAS;AAAA,YACT,QAAQ,aAAa,OAAO,MAAM;AAAA,YAClC,cAAc,OAAO;AAAA,YACrB,YAAY;AAAA,YACZ,OAAO,OAAO;AAAA,YACd,MAAM;AAAA,YACN,UAAU;AAAA,UACZ;AAAA;AAAA,MACF;AAAA,MACA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS;AAAA,UACT,OAAO;AAAA,YACL,SAAS;AAAA,YACT,QAAQ;AAAA,YACR,cAAc,OAAO;AAAA,YACrB,YAAY,OAAO;AAAA,YACnB,OAAO,OAAO;AAAA,YACd,MAAM;AAAA,YACN,UAAU;AAAA,YACV,YAAY;AAAA,YACZ,QAAQ;AAAA,UACV;AAAA,UAEC,mBAAS,WAAW;AAAA;AAAA,MACvB;AAAA,OACF;AAAA,KACF;AAEJ;AAEA,SAAS,WAAW,KAAqB;AACvC,QAAM,OAAO,IAAI,KAAK,GAAG;AACzB,SAAO,OAAO,MAAM,KAAK,QAAQ,CAAC,IAC9B,MACA,KAAK,mBAAmB,QAAW,EAAE,MAAM,WAAW,OAAO,SAAS,KAAK,UAAU,CAAC;AAC5F;;;ACnHA,IAAM,QAA2C;AAAA,EAC/C,kBAAkB;AAAA,EAClB,mBAAmB;AAAA,EACnB,sBAAsB;AAAA,EACtB,oBAAoB;AAAA,EACpB,gBAAgB;AAAA,EAChB,uBAAuB;AAAA,EACvB,iBAAiB;AAAA,EACjB,eAAe;AACjB;AAEA,IAAM,WAA6D;AAAA,EACjE,kBAAkB;AAAA,EAClB,mBAAmB;AAAA,EACnB,sBAAsB;AAAA,EACtB,oBAAoB;AAAA,EACpB,gBAAgB;AAAA,EAChB,uBAAuB;AAAA,EACvB,iBAAiB;AAAA,EACjB,eAAe;AACjB;AAEA,IAAM,QAAQ,CAAC,MAAyB,SAAiB,WAA+B,cAAuC;AAAA,EAC7H,IAAI;AAAA,EACJ;AAAA,EACA,UAAU,SAAS,IAAI;AAAA,EACvB,OAAO,MAAM,IAAI;AAAA,EACjB;AAAA,EACA;AACF;AAGO,SAAS,yBAAyB,aAAiE;AACxG,QAAM,UAAU,4BAA4B,aAAa,OAAO;AAChE,SAAO,QAAQ,OAAO,KAAK,QAAS,YAAY;AAClD;AAGO,SAAS,kBACd,OACA,QAMA,UAAiC,CAAC,GACP;AAC3B,MAAI,aAAa,KAAK,MAAM,QAAS,QAAO,CAAC;AAC7C,QAAM,MAAiC,CAAC;AAExC,QAAM,UAAU,0BAA0B,OAAO,SAAS,MAAM,QAAQ;AACxE,MAAI,QAAQ,QAAS,KAAI,KAAK,MAAM,mBAAmB,8CAA8C,CAAC;AAAA,WAC7F,CAAC,QAAQ,IAAI;AACpB,UAAM,QAAQ,CAAC,+BAA+B;AAC9C,QAAI,QAAQ,QAAQ,OAAQ,OAAM,KAAK,qBAAqB,QAAQ,QAAQ,KAAK,IAAI,CAAC,GAAG;AACzF,QAAI,QAAQ,eAAe,OAAQ,OAAM,KAAK,yCAAyC,QAAQ,eAAe,KAAK,IAAI,CAAC,GAAG;AAC3H,QAAI,KAAK,MAAM,kBAAkB,MAAM,KAAK,GAAG,CAAC,CAAC;AAAA,EACnD;AAEA,QAAM,UAAU,MAAM,eAAe,MAAM;AAC3C,MAAI,WAAW,0BAA0B,OAAO,GAAG;AACjD,QAAI;AAAA,MACF;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF,WAAW,MAAM,aAAa;AAC5B,QAAI,KAAK,MAAM,gBAAgB,MAAM,aAAa,OAAO,CAAC;AAAA,EAC5D;AAEA,MAAI,MAAM,eAAe,QAAQ;AAC/B,UAAM,OAAO,MAAM,eAAe,KAAK,IAAI;AAC3C,QAAI,KAAK,MAAM,iBAAiB,sCAAsC,MAAM,eAAe,WAAW,IAAI,KAAK,GAAG,KAAK,IAAI,GAAG,CAAC;AAAA,EACjI;AAEA,QAAM,aAAa,OAAO,cAAc,CAAC;AACzC,MAAI,WAAW,QAAQ;AACrB,UAAM,QAAQ,WAAW,CAAC;AAC1B,UAAM,QAAQ,MAAM,SAAS,GAAG,MAAM,MAAM,WAAW,MAAM,KAAK,KAAK,OAAO,MAAM,KAAK;AACzF,UAAM,OAAO,WAAW,SAAS,IAAI,SAAS,WAAW,SAAS,CAAC,WAAW;AAC9E,QAAI,KAAK,MAAM,eAAe,GAAG,KAAK,KAAK,MAAM,OAAO,GAAG,IAAI,mDAAmD,CAAC;AAAA,EACrH;AAEA,QAAM,UAAU,4BAA4B,MAAM,aAAa,OAAO;AACtE,MAAI,OAAO,eAAe;AACxB,QAAI,WAAW,CAAC,QAAQ,UAAU;AAChC,UAAI;AAAA,QACF;AAAA,UACE;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF,WAAW,yBAAyB,MAAM,WAAW,GAAG;AACtD,UAAM,OAAO,QAAQ,sBAAsB,KAAK;AAChD,QAAI;AAAA,MACF;AAAA,QACE;AAAA,QACA,yIACG,OAAO,IAAI,IAAI,KAAK;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aAAa,OAAO,kBAAkB,CAAC;AAC7C,SAAO,IAAI,OAAO,CAAC,MAAM,CAAC,WAAW,SAAS,EAAE,IAAI,CAAC;AACvD;AAGO,SAAS,kBAAkB,SAA4D;AAC5F,QAAM,EAAE,YAAY,OAAO,WAAW,IAAI,qBAAqB;AAC/D,MAAI,CAAC,WAAY,QAAO,CAAC;AACzB,QAAM,EAAE,SAAS,eAAe,eAAe,IAAI,WAAW,QAAQ;AACtE,SAAO,kBAAkB,OAAO,EAAE,SAAS,eAAe,gBAAgB,WAAW,GAAG,OAAO;AACjG;;;AC7IkC,0BAAAG,MAG9B,QAAAC,aAH8B;AAZlC,IAAM,gBAAuC;AAAA,EAC3C,sBACE;AACJ;AAOO,SAAS,aAAa,EAAE,SAAS,GAA4B;AAClE,QAAM,SAAS,kBAAkB,aAAa;AAC9C,MAAI,OAAO,WAAW,EAAG,QAAO,gBAAAD,KAAA,YAAG,UAAS;AAE5C,SACE,gBAAAC,MAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,eAAe,UAAU,KAAK,UAAU,GACrE;AAAA,oBAAAD,KAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,eAAe,UAAU,KAAK,WAAW,SAAS,oBAAoB,GAClG,iBAAO,IAAI,CAACE,WACX,gBAAAF,KAAC,eAA2B,OAAOE,UAAjBA,OAAM,EAAkB,CAC3C,GACH;AAAA,IACC;AAAA,KACH;AAEJ;AAEA,SAAS,YAAY,EAAE,OAAAA,OAAM,GAAuC;AAClE,QAAM,WAAWA,OAAM,SAAS,wBAAwBA,OAAM,SAAS;AACvE,SACE,gBAAAD,MAAC,SAAI,MAAMC,OAAM,UAAU,OAAO,EAAE,GAAG,YAAY,GAAGC,UAASD,OAAM,QAAQ,EAAE,GAC7E;AAAA,oBAAAF,KAAC,UAAK,eAAW,MAAC,OAAO,EAAE,YAAY,GAAG,WAAW,WAAW,GAC7D,qBAAW,gBAAAA,KAAC,YAAS,IAAK,gBAAAA,KAAC,eAAY,GAC1C;AAAA,IACA,gBAAAC,MAAC,SAAI,OAAO,EAAE,UAAU,EAAE,GACxB;AAAA,sBAAAD,KAAC,OAAE,OAAO,EAAE,QAAQ,GAAG,YAAY,IAAI,GAAI,UAAAE,OAAM,OAAM;AAAA,MACvD,gBAAAF,KAAC,OAAE,OAAO,EAAE,QAAQ,eAAe,OAAO,OAAO,gBAAgB,GAAI,UAAAE,OAAM,SAAQ;AAAA,OACrF;AAAA,KACF;AAEJ;AAEA,IAAM,aAA4B;AAAA,EAChC,WAAW;AAAA,EACX,SAAS;AAAA,EACT,KAAK;AAAA,EACL,SAAS;AAAA,EACT,QAAQ,aAAa,OAAO,MAAM;AAAA,EAClC,cAAc,OAAO;AAAA,EACrB,OAAO,OAAO;AAAA,EACd,UAAU;AAAA,EACV,YAAY;AACd;AAEA,IAAMC,YAAuE;AAAA,EAC3E,OAAO,EAAE,aAAa,OAAO,aAAa,OAAO,OAAO,YAAY;AAAA,EACpE,SAAS,EAAE,aAAa,yBAAyB,YAAY,wBAAwB;AAAA,EACrF,MAAM,EAAE,YAAY,cAAc;AACpC;AAEA,IAAM,OAAO;AAAA,EACX,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,aAAa;AAAA,EACb,eAAe;AAAA,EACf,gBAAgB;AAClB;AAEA,SAAS,cAAc;AACrB,SACE,gBAAAF,MAAC,SAAK,GAAG,MACP;AAAA,oBAAAD,KAAC,UAAK,GAAE,4EAA2E;AAAA,IACnF,gBAAAA,KAAC,UAAK,GAAE,WAAU;AAAA,IAClB,gBAAAA,KAAC,UAAK,GAAE,cAAa;AAAA,KACvB;AAEJ;AAEA,SAAS,WAAW;AAClB,SACE,gBAAAC,MAAC,SAAK,GAAG,MACP;AAAA,oBAAAD,KAAC,UAAK,GAAE,2BAA0B;AAAA,IAClC,gBAAAA,KAAC,UAAK,GAAE,6BAA4B;AAAA,IACpC,gBAAAA,KAAC,UAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA,KACvC;AAEJ;;;AN2CM,SA8DG,YAAAI,WA9DH,OAAAC,MAsBA,QAAAC,aAtBA;AAnEC,SAAS,mBAAmB,OAA0C;AAC3E,SAAO,aAAa,SAAS,MAAM,WAAW;AAChD;AAGO,SAAS,WAAW,OAAyB,MAAM,OAA4B;AACpF,QAAM,SAAS,cAAc,MAAM,MAAM,IAAI,MAAM,SAAS;AAC5D,QAAM,UAAU,QAAQ,WAAW,MAAM;AACzC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,QAAM,QAA6B;AAAA,IACjC,KAAK,MAAM;AAAA,IACX;AAAA,IACA,UAAU,QAAQ,YAAY,MAAM;AAAA,IACpC;AAAA,EACF;AACA,MAAI,YAAY,MAAO,OAAM,SAAS,MAAM;AAC5C,MAAI,MAAM,aAAc,OAAM,eAAe,MAAM;AACnD,MAAI,MAAM,YAAa,OAAM,cAAc,MAAM;AACjD,SAAO;AACT;AA8BO,SAAS,iBACd,QACA,eAA2D,CAAC,GACxC;AACpB,QAAM,EAAE,OAAO,SAAS,GAAG,MAAM,IAC/B,mBAAmB,MAAM,IAAI,EAAE,GAAG,WAAW,QAAQ,aAAa,GAAG,GAAG,MAAM,aAAa,KAAK,IAAI;AACtG,QAAM,YAAY,OAAO,SAAS,WAAW,SAAS,cAAc,IAAI,IAAI;AAC5E,MAAI,CAAC,WAAW;AACd,UAAM,IAAI,MAAM,yCAAyC,OAAO,IAAI,CAAC,8BAA8B;AAAA,EACrG;AAEA,QAAM,YAAY,WAAW,SAAS;AACtC,YAAU;AAAA,IACR,gBAAAD,KAAC,cACC,0BAAAA,KAAC,kBAAgB,GAAG,OAAO,GAC7B;AAAA,EACF;AACA,SAAO,EAAE,SAAS,MAAM,UAAU,QAAQ,EAAE;AAC9C;AAMO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA,MAAM;AAAA,EACN,SAAS;AAAA,EACT,cAAAE,gBAAe;AAAA,EACf,aAAAC,eAAc;AAChB,GAAwB;AACtB,QAAM,OAAO,UAAU;AACvB,MAAI,WAAW,GAAG;AAChB,WACE,gBAAAF,MAAC,uBAAoB,SACnB;AAAA,sBAAAD,KAAC,gBAAa,UAAoB;AAAA,MAClC,gBAAAA,KAAC,yBACC,0BAAAA,KAAC,iBACC,0BAAAA,KAAC,SAAI,OAAO,MACV,0BAAAA,KAAC,QACC,0BAAAA,KAAC,YAAS,UAAU,MAClB,0BAAAA,KAAC,OAAI,GACP,GACF,GACF,GACF,GACF;AAAA,OACF;AAAA,EAEJ;AAEA,QAAM,UAAU,gBAAgB,OAAO,SAAS,QAAQ,EAAE;AAC1D,SACE,gBAAAC,MAAC,2BACC;AAAA,oBAAAD,KAAC,gBAAa,UAAoB;AAAA,IAClC,gBAAAA,KAAC,SAAI,OAAO,MAAO,gBAAM,gBAAAA,KAACE,eAAA,EAAa,IAAK,gBAAAF,KAACG,cAAA,EAAY,SAAkB,GAAG;AAAA,KAChF;AAEJ;AAEA,IAAM,OAAO,EAAE,WAAW,QAAQ,OAAO,OAAO;AAGhD,SAAS,aAAsB;AAC7B,SAAO,OAAO,WAAW,eAAe,OAAO,SAAS,OAAO;AACjE;AAGA,SAAS,aAAa,EAAE,SAAS,GAAkD;AACjF,oBAAkB,UAAU,QAAQ,EAAE,OAAO,SAAS,OAAO,aAAa,SAAS,eAAe,GAAG,IAAI,IAAI;AAC7G,SAAO;AACT;AAEA,SAAS,YAAY,EAAE,SAAS,GAA4B;AAC1D,SAAO,gBAAAH,KAAAD,WAAA,EAAG,UAAS;AACrB;","names":["useEffect","useState","useState","useEffect","useEffect","useState","jsx","useState","useEffect","useState","jsx","jsxs","useState","jsx","jsxs","alert","SEVERITY","Fragment","jsx","jsxs","LocalDevPage","ReleasePage"]}
|