grist-widget-sdk 0.3.26 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +53 -0
- package/README.md +1 -1
- package/dist/app.cjs +1139 -4336
- package/dist/app.cjs.map +1 -1
- package/dist/app.d.cts +1 -3
- package/dist/app.d.ts +1 -3
- package/dist/app.js +9 -517
- package/dist/app.js.map +1 -1
- package/dist/chunk-4ZGVKGDF.js +204 -0
- package/dist/chunk-4ZGVKGDF.js.map +1 -0
- package/dist/{chunk-YQNMIL33.js → chunk-B5ZZNLVS.js} +528 -181
- package/dist/chunk-B5ZZNLVS.js.map +1 -0
- package/dist/chunk-O7NY46QY.js +1830 -0
- package/dist/chunk-O7NY46QY.js.map +1 -0
- package/dist/chunk-P6VTEKWO.js +618 -0
- package/dist/chunk-P6VTEKWO.js.map +1 -0
- package/dist/emulator/testing.cjs +2084 -391
- package/dist/emulator/testing.cjs.map +1 -1
- package/dist/emulator/testing.d.cts +55 -7
- package/dist/emulator/testing.d.ts +55 -7
- package/dist/emulator/testing.js +144 -19
- package/dist/emulator/testing.js.map +1 -1
- package/dist/emulator.cjs +59 -249
- package/dist/emulator.cjs.map +1 -1
- package/dist/emulator.d.cts +3 -5
- package/dist/emulator.d.ts +3 -5
- package/dist/emulator.js +5 -11
- package/dist/index.cjs +1373 -4859
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +81 -260
- package/dist/index.d.ts +81 -260
- package/dist/index.js +8 -161
- package/dist/{inline-C7DkvuET.d.cts → templates-CGmRIQBV.d.cts} +89 -35
- package/dist/{inline-DpcT8tV9.d.ts → templates-Cq94qOcf.d.ts} +89 -35
- package/dist/{types-D3JxUCfL.d.cts → types-DBStn0Dk.d.cts} +2 -26
- package/dist/{types-D3JxUCfL.d.ts → types-DBStn0Dk.d.ts} +2 -26
- package/dist/use-grist-BK0eke9K.d.cts +358 -0
- package/dist/use-grist-C5DMZ3wU.d.ts +358 -0
- package/package.json +8 -37
- package/dist/advanced.cjs +0 -2799
- package/dist/advanced.cjs.map +0 -1
- package/dist/advanced.d.cts +0 -822
- package/dist/advanced.d.ts +0 -822
- package/dist/advanced.js +0 -875
- package/dist/advanced.js.map +0 -1
- package/dist/chunk-22U7WAY3.js +0 -463
- package/dist/chunk-22U7WAY3.js.map +0 -1
- package/dist/chunk-64SVRWW7.js +0 -758
- package/dist/chunk-64SVRWW7.js.map +0 -1
- package/dist/chunk-ELGVOHFD.js +0 -32
- package/dist/chunk-ELGVOHFD.js.map +0 -1
- package/dist/chunk-EPEBKXVN.js +0 -470
- package/dist/chunk-EPEBKXVN.js.map +0 -1
- package/dist/chunk-GTTD5HPO.js +0 -36
- package/dist/chunk-GTTD5HPO.js.map +0 -1
- package/dist/chunk-JASMM2YC.js +0 -243
- package/dist/chunk-JASMM2YC.js.map +0 -1
- package/dist/chunk-N3X46JW2.js +0 -37
- package/dist/chunk-N3X46JW2.js.map +0 -1
- package/dist/chunk-PDGEZ24B.js +0 -2366
- package/dist/chunk-PDGEZ24B.js.map +0 -1
- package/dist/chunk-PM3B4WYV.js +0 -12
- package/dist/chunk-PM3B4WYV.js.map +0 -1
- package/dist/chunk-REV5AUXD.js +0 -25
- package/dist/chunk-REV5AUXD.js.map +0 -1
- package/dist/chunk-TZB3OZA6.js +0 -1630
- package/dist/chunk-TZB3OZA6.js.map +0 -1
- package/dist/chunk-YQNMIL33.js.map +0 -1
- package/dist/create-grist-emulator-BCqp1BF9.d.ts +0 -81
- package/dist/create-grist-emulator-DBM8OSIR.d.cts +0 -81
- package/dist/emulator/devtools.cjs +0 -1404
- package/dist/emulator/devtools.cjs.map +0 -1
- package/dist/emulator/devtools.d.cts +0 -48
- package/dist/emulator/devtools.d.ts +0 -48
- package/dist/emulator/devtools.js +0 -508
- package/dist/emulator/devtools.js.map +0 -1
- package/dist/emulator/transports.cjs +0 -1132
- package/dist/emulator/transports.cjs.map +0 -1
- package/dist/emulator/transports.d.cts +0 -38
- package/dist/emulator/transports.d.ts +0 -38
- package/dist/emulator/transports.js +0 -12
- package/dist/emulator/transports.js.map +0 -1
- package/dist/templates-8k2LKoO-.d.cts +0 -24
- package/dist/templates-DIwi_mvI.d.ts +0 -24
- package/dist/use-grist-reads-DUMvJgV7.d.ts +0 -480
- package/dist/use-grist-reads-DpjVuI0H.d.cts +0 -480
- package/dist/use-grist-types-DdOLEJXN.d.cts +0 -499
- package/dist/use-grist-types-kwxoFeub.d.ts +0 -499
- package/dist/use-grist-widget-options-from-context-CGOlQ5Vc.d.cts +0 -43
- package/dist/use-grist-widget-options-from-context-CGOlQ5Vc.d.ts +0 -43
package/dist/advanced.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/sdk/low-level-hooks/use-grist-availability.ts","../src/sdk/low-level-hooks/use-grist-handshake.ts","../src/sdk/low-level-hooks/use-ambient-grist-handshake.ts","../src/sdk/components/grist-handshake-provider.tsx","../src/sdk/low-level-hooks/use-grist-record.ts","../src/sdk/low-level-hooks/use-grist-records.ts","../src/sdk/low-level-hooks/use-grist-new-record.ts","../src/sdk/mid-level-hooks/use-grist-actions.ts","../src/sdk/mid-level-hooks/use-grist-mapped-record.ts","../src/sdk/mid-level-hooks/use-grist-table-ops.ts","../src/sdk/mid-level-hooks/use-grist-rows-from-table.ts","../src/sdk/mid-level-hooks/use-grist-access-token.ts","../src/sdk/mid-level-hooks/use-grist-section.ts","../src/sdk/mid-level-hooks/use-grist-widget-options.ts","../src/sdk/use-grist-table.ts"],"sourcesContent":["import { useGristCore, type UseGristCoreOptions } from \"../internal/hooks/use-grist-core\"\n\nexport type UseGristAvailabilityOptions = Pick<\n UseGristCoreOptions,\n \"availabilityMaxAttempts\" | \"availabilityIntervalMs\" | \"logWhenNotEmbedded\"\n>\n\n/**\n * Handshake-backed availability — projects `isAvailable` from the FSM.\n */\nexport function useGristAvailability(options?: UseGristAvailabilityOptions): boolean | null {\n const { isAvailable } = useGristCore(options)\n return isAvailable\n}\n","/**\n * `useGristHandshake()` — React adapter over {@link GristHandshakeManager}.\n *\n * Exposes the full {@link GristWidgetSnapshot} plus derived\n * {@link GristCapabilities}, plus `reload()` / `restart()` controls.\n *\n * Identity stability\n * ------------------\n * The snapshot reference changes whenever the reducer produces a new\n * snapshot. Capabilities are memoized by snapshot identity, so consumers\n * branching on a single capability (e.g. `canWriteRecords`) avoid extra\n * re-renders unless that boolean actually flips.\n *\n * SSR-safe: `getServerSnapshot` returns the initial snapshot deterministically.\n */\n\nimport { useEffect, useMemo, useRef, useSyncExternalStore } from \"react\"\n\nimport {\n deriveCapabilities,\n deriveErrorMessage,\n deriveStatus,\n initialGristSnapshot,\n type GristCapabilities,\n type GristWidgetSnapshot,\n type GristWidgetStatus,\n} from \"../internal/handshake\"\nimport {\n createGristHandshakeManager,\n type ManagerControls,\n type ManagerOptions,\n} from \"../internal/handshake/manager\"\nimport { ensureGristReady, resetGristReadySingleton } from \"../internal/ready-singleton\"\n\nexport type UseGristHandshakeOptions = ManagerOptions\n\nexport type UseGristHandshakeResult = {\n snapshot: GristWidgetSnapshot\n status: GristWidgetStatus\n error: string | null\n capabilities: GristCapabilities\n reload: () => void\n restart: () => void\n}\n\n/**\n * Mount a handshake manager local to the component subtree. Multiple\n * widgets in the same page should NOT call this in parallel — instead,\n * mount a single `<GristWidgetProvider>` at the app root.\n *\n * In tests, pass `options.env` (see `createTestEnvironment`) to drive the\n * machine with a virtual clock.\n */\nexport function useGristHandshake(options: UseGristHandshakeOptions = {}): UseGristHandshakeResult {\n // Memoize the manager so it survives re-renders. Caller is responsible for\n // passing stable options; in practice this is set once at the provider.\n const optionsRef = useRef(options)\n optionsRef.current = options\n const managerRef = useRef<ManagerControls | null>(null)\n if (managerRef.current === null) {\n // Default to the page-level `ensureGristReady()` singleton so a\n // standalone `useGristHandshake()` (mounted alongside a real\n // `<GristWidgetProvider>` for its observable snapshot, per the \"custom\n // retry / observability\" pattern) can't call the real `grist.ready()`\n // independently and race the widget's own declared options. Callers\n // that pass their own `negotiate`/`onBeforeReload` still win.\n managerRef.current = createGristHandshakeManager({\n ...options,\n negotiate: {\n readyImpl: (payload) => ensureGristReady(payload),\n ...options.negotiate,\n },\n onBeforeReload: () => {\n resetGristReadySingleton()\n options.onBeforeReload?.()\n },\n })\n }\n const manager = managerRef.current\n\n useEffect(() => {\n manager.start()\n return () => {\n manager.stop()\n }\n }, [manager])\n\n const snapshot = useSyncExternalStore(\n manager.subscribe,\n manager.getSnapshot,\n initialGristSnapshot\n )\n\n const projected = useMemo(\n () => ({\n status: deriveStatus(snapshot),\n error: deriveErrorMessage(snapshot),\n capabilities: deriveCapabilities(snapshot),\n }),\n [snapshot]\n )\n\n return useMemo(\n () => ({\n snapshot,\n status: projected.status,\n error: projected.error,\n capabilities: projected.capabilities,\n reload: manager.reload,\n restart: manager.restart,\n }),\n [snapshot, projected, manager]\n )\n}\n\n/**\n * Convenience hook — equivalent to `useGristHandshake().capabilities` but\n * skips returning the full snapshot. Intended for leaf components that only\n * need to gate UI on `canRender` / `canWriteRecords` / etc.\n */\nexport function useGristCapabilities(\n options: UseGristHandshakeOptions = {}\n): GristCapabilities {\n return useGristHandshake(options).capabilities\n}\n","/**\n * `useAmbientGristHandshake()` — observe an already-mounted handshake\n * manager without ever creating one.\n *\n * `useGristHandshake()` / `<GristHandshakeProvider>` both mount their OWN\n * manager, which calls the real `grist.ready()` independently of any\n * `<GristWidgetProvider>` elsewhere on the page. That's fine for a widget's\n * single app-root provider, but wrong for read-only UI (a connection-status\n * chip, a debug overlay) that must share the *same* handshake as the real\n * widget rather than run a second, competing one. This hook only reads\n * whatever manager a `<GristWidgetProvider>` ancestor already published;\n * it returns `null` outside one instead of falling back to creating its own.\n */\n\nimport { useMemo, useSyncExternalStore } from \"react\"\n\nimport {\n deriveCapabilities,\n deriveErrorMessage,\n deriveStatus,\n initialGristSnapshot,\n type GristCapabilities,\n type GristWidgetSnapshot,\n type GristWidgetStatus,\n} from \"../internal/handshake\"\nimport { useGristManagerOptional } from \"../internal/handshake-manager-context\"\n\nexport type UseAmbientGristHandshakeResult = {\n snapshot: GristWidgetSnapshot\n status: GristWidgetStatus\n error: string | null\n capabilities: GristCapabilities\n reload: () => void\n restart: () => void\n}\n\nconst noopSubscribe = () => () => {}\nconst getInitialSnapshot = () => initialGristSnapshot()\n\n/**\n * Returns `null` when mounted outside a `<GristWidgetProvider>` — there is\n * no ambient manager to observe, and this hook intentionally never creates\n * one. Mount inside `<GristWidgetProvider>` to get a live value.\n */\nexport function useAmbientGristHandshake(): UseAmbientGristHandshakeResult | null {\n const manager = useGristManagerOptional()\n\n const snapshot = useSyncExternalStore(\n manager?.subscribe ?? noopSubscribe,\n manager?.getSnapshot ?? getInitialSnapshot,\n getInitialSnapshot\n )\n\n return useMemo(() => {\n if (!manager) return null\n return {\n snapshot,\n status: deriveStatus(snapshot),\n error: deriveErrorMessage(snapshot),\n capabilities: deriveCapabilities(snapshot),\n reload: manager.reload,\n restart: manager.restart,\n }\n }, [manager, snapshot])\n}\n","/**\n * `<GristHandshakeProvider>` — opt-in React provider that mounts a single\n * {@link GristHandshakeManager} at the app root and broadcasts its snapshot\n * to all descendants.\n *\n * Use this provider when you want the full SOTA handshake model (snapshot +\n * capabilities + heartbeat + reload/restart) without the slice composition\n * of `<GristWidgetProvider>`. The two providers are independent:\n *\n * - `<GristWidgetProvider>` (legacy) — full SDK surface, hooks slices.\n * - `<GristHandshakeProvider>` (new) — handshake state machine only.\n *\n * Both can coexist if you need both surfaces; `grist.ready` is deduped by\n * the SDK's ready singleton so concurrent calls are safe.\n */\n\nimport {\n createContext,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useSyncExternalStore,\n type ReactNode,\n} from \"react\"\n\nimport {\n createGristHandshakeManager,\n type ManagerControls,\n type ManagerOptions,\n} from \"../internal/handshake/manager\"\nimport {\n deriveCapabilities,\n deriveErrorMessage,\n deriveStatus,\n initialGristSnapshot,\n type GristCapabilities,\n type GristWidgetSnapshot,\n type GristWidgetStatus,\n} from \"../internal/handshake\"\nimport { ensureGristReady, resetGristReadySingleton } from \"../internal/ready-singleton\"\n\nexport type GristHandshakeContextValue = {\n snapshot: GristWidgetSnapshot\n status: GristWidgetStatus\n error: string | null\n capabilities: GristCapabilities\n reload: () => void\n restart: () => void\n recordRpcSuccess: () => void\n recordRpcFailure: () => void\n}\n\nconst GristHandshakeReactContext = createContext<GristHandshakeContextValue | null>(null)\n\nexport type GristHandshakeProviderProps = {\n options?: ManagerOptions\n children: ReactNode\n}\n\n/**\n * Mount a single {@link GristHandshakeManager} for the React subtree and\n * expose its snapshot via context.\n *\n * The manager is created **once** on first mount; the `options` prop is\n * captured at that time. To re-create the manager with new options, unmount\n * and re-mount the provider (e.g. via a `key`).\n */\nexport function GristHandshakeProvider({ options, children }: GristHandshakeProviderProps) {\n // Manager is allocated once. Subsequent option changes are intentionally\n // ignored — handshake configuration should be stable for the lifetime of\n // the widget.\n const managerRef = useRef<ManagerControls | null>(null)\n if (managerRef.current === null) {\n // Default to the page-level `ensureGristReady()` singleton so a bare\n // `<GristHandshakeProvider>` (no options) can't win a race against a\n // sibling `<GristWidgetProvider>` by calling the real `grist.ready()`\n // directly with its own default payload. Callers that pass their own\n // `negotiate`/`onBeforeReload` still win. (Read-only observers of an\n // ancestor `<GristWidgetProvider>`, like the template's `GristStatusChip`,\n // should prefer `useAmbientGristHandshake()` instead of this provider —\n // it observes the existing manager rather than allocating a new one.)\n managerRef.current = createGristHandshakeManager({\n ...options,\n negotiate: {\n readyImpl: (payload) => ensureGristReady(payload),\n ...options?.negotiate,\n },\n onBeforeReload: () => {\n resetGristReadySingleton()\n options?.onBeforeReload?.()\n },\n })\n }\n const manager = managerRef.current\n\n useEffect(() => {\n manager.start()\n return () => {\n manager.stop()\n }\n }, [manager])\n\n const snapshot = useSyncExternalStore(\n manager.subscribe,\n manager.getSnapshot,\n initialGristSnapshot\n )\n\n const value = useMemo<GristHandshakeContextValue>(\n () => ({\n snapshot,\n status: deriveStatus(snapshot),\n error: deriveErrorMessage(snapshot),\n capabilities: deriveCapabilities(snapshot),\n reload: manager.reload,\n restart: manager.restart,\n recordRpcSuccess: manager.recordRpcSuccess,\n recordRpcFailure: manager.recordRpcFailure,\n }),\n [snapshot, manager]\n )\n\n return (\n <GristHandshakeReactContext.Provider value={value}>\n {children}\n </GristHandshakeReactContext.Provider>\n )\n}\n\n/**\n * Read the handshake context. Throws if no `<GristHandshakeProvider>` is\n * mounted in the tree.\n *\n * Use {@link useGristHandshakeContextOptional} when the provider is optional\n * (e.g. when the same component is sometimes used standalone).\n */\nexport function useGristHandshakeContext(): GristHandshakeContextValue {\n const ctx = useContext(GristHandshakeReactContext)\n if (!ctx) {\n throw new Error(\n \"useGristHandshakeContext() must be used inside <GristHandshakeProvider>\"\n )\n }\n return ctx\n}\n\n/** Non-throwing variant. */\nexport function useGristHandshakeContextOptional(): GristHandshakeContextValue | null {\n return useContext(GristHandshakeReactContext)\n}\n","import { useEffect, useRef, useState } from \"react\"\n\nimport { recordEvent } from \"../internal/subscriptions\"\nimport type { GristReadyOptions, GristWidgetColumnMap } from \"../types\"\nimport { useGristReady } from \"./use-grist-ready\"\n\nexport type UseGristRecordSubscriptionResult = {\n loading: boolean\n error: string | null\n /** Latest mappings from `grist.onRecord` (logical name → real column id, or `string[]` for `allowMultiple`). */\n mappings: GristWidgetColumnMap | null\n}\n\n// Subscription errors are logged inside the singleton; nothing surfaces here.\n\n/**\n * Subscribes to the currently-selected row in the widget's section.\n *\n * The Grist event is shared across all hook instances (no leak).\n */\nexport function useGristRecord(\n cb: (record: Record<string, unknown> | null, mappings: GristWidgetColumnMap | null) => void,\n options?: GristReadyOptions\n): UseGristRecordSubscriptionResult {\n const cbRef = useRef(cb)\n useEffect(() => {\n cbRef.current = cb\n }, [cb])\n\n const [mappings, setMappings] = useState<GristWidgetColumnMap | null>(null)\n const { docApi, error: readyError } = useGristReady({\n requiredAccess: options?.requiredAccess ?? \"read table\",\n columns: options?.columns,\n allowSelectBy: options?.allowSelectBy,\n hasCustomOptions: options?.hasCustomOptions,\n onEditOptions: options?.onEditOptions,\n })\n\n useEffect(() => {\n if (!docApi) return\n return recordEvent.subscribe(({ record, mappings: nextMappings }) => {\n setMappings(nextMappings)\n cbRef.current(record, nextMappings)\n })\n }, [docApi])\n\n return {\n loading: docApi === null && !readyError,\n error: readyError,\n mappings,\n }\n}\n","import { useEffect, useRef, useState } from \"react\"\n\nimport { recordsEvent } from \"../internal/subscriptions\"\nimport type { GristReadyOptions, GristWidgetColumnMap } from \"../types\"\nimport { useGristReady } from \"./use-grist-ready\"\nimport type { UseGristRecordSubscriptionResult } from \"./use-grist-record\"\n\n/**\n * Subscribes to the full row set visible in the widget's section\n * (filters, sorts, and linked rows applied).\n */\nexport function useGristRecords(\n cb: (records: Record<string, unknown>[], mappings: GristWidgetColumnMap | null) => void,\n options?: GristReadyOptions\n): UseGristRecordSubscriptionResult {\n const cbRef = useRef(cb)\n useEffect(() => {\n cbRef.current = cb\n }, [cb])\n\n const [mappings, setMappings] = useState<GristWidgetColumnMap | null>(null)\n const { docApi, error: readyError } = useGristReady({\n requiredAccess: options?.requiredAccess ?? \"read table\",\n columns: options?.columns,\n allowSelectBy: options?.allowSelectBy,\n hasCustomOptions: options?.hasCustomOptions,\n onEditOptions: options?.onEditOptions,\n })\n\n useEffect(() => {\n if (!docApi) return\n return recordsEvent.subscribe(({ records, mappings: nextMappings }) => {\n setMappings(nextMappings)\n cbRef.current(records, nextMappings)\n })\n }, [docApi])\n\n return {\n loading: docApi === null && !readyError,\n error: readyError,\n mappings,\n }\n}\n","import { useEffect, useRef, useState } from \"react\"\n\nimport { newRecordEvent } from \"../internal/subscriptions\"\nimport type { GristReadyOptions, GristWidgetColumnMap } from \"../types\"\nimport { useGristReady } from \"./use-grist-ready\"\n\nexport type UseGristNewRecordResult = {\n /** True when the user has selected the blank \"new row\" placeholder. */\n isNewRecord: boolean\n /** Mappings reported by Grist alongside the new-record event. */\n mappings: GristWidgetColumnMap | null\n loading: boolean\n error: string | null\n}\n\n/**\n * Subscribes to `grist.onNewRecord` — fires when the user selects the blank\n * row in the linked section. Useful for form-style widgets that need to\n * switch into \"create\" mode.\n *\n * `isNewRecord` is reset to `false` whenever a real `onRecord` payload arrives,\n * so callers don't need to manage that themselves.\n */\nexport function useGristNewRecord(options?: GristReadyOptions): UseGristNewRecordResult {\n const { docApi, error: readyError } = useGristReady({\n requiredAccess: options?.requiredAccess ?? \"read table\",\n columns: options?.columns,\n allowSelectBy: options?.allowSelectBy,\n hasCustomOptions: options?.hasCustomOptions,\n onEditOptions: options?.onEditOptions,\n })\n\n const [isNewRecord, setIsNewRecord] = useState(false)\n const [mappings, setMappings] = useState<GristWidgetColumnMap | null>(null)\n const subscribedRef = useRef(false)\n\n useEffect(() => {\n if (!docApi || subscribedRef.current) return\n if (typeof grist.onNewRecord !== \"function\") return\n subscribedRef.current = true\n return newRecordEvent.subscribe(({ mappings: nextMappings }) => {\n setIsNewRecord(true)\n setMappings(nextMappings)\n })\n }, [docApi])\n\n return {\n isNewRecord,\n mappings,\n loading: docApi === null && !readyError,\n error: readyError,\n }\n}\n","import { useCallback, useState } from \"react\"\n\nimport {\n gristAddRecordAction,\n gristBulkAddRecordAction,\n gristBulkRemoveRecordAction,\n gristBulkUpdateRecordAction,\n gristRemoveRecordAction,\n gristUpdateRecordAction,\n type GristUserActionTuple,\n} from \"../helpers/grist-user-actions\"\nimport { useRpcHeartbeatCoalesce } from \"../internal/hooks/use-rpc-heartbeat-coalesce\"\nimport { useGristReady } from \"../low-level-hooks/use-grist-ready\"\nimport type { GristApplyUserActionsOptions, GristReadyOptions } from \"../types\"\n\nexport type GristActionsStatus = \"idle\" | \"running\" | \"error\"\n\nexport type UseGristActionsOptions = Pick<\n GristReadyOptions,\n \"requiredAccess\" | \"columns\" | \"allowSelectBy\" | \"hasCustomOptions\" | \"onEditOptions\"\n>\n\nexport type UseGristActionsResult = {\n status: GristActionsStatus\n error: string | null\n /** Apply raw user actions. `applyOptions.desc` is shown in the document undo stack. */\n apply: (actions: GristUserActionTuple[], applyOptions?: GristApplyUserActionsOptions) => Promise<unknown>\n updateRecord: (\n tableId: string,\n recordId: number,\n patch: Record<string, unknown>,\n applyOptions?: GristApplyUserActionsOptions\n ) => Promise<unknown>\n addRecord: (\n tableId: string,\n values: Record<string, unknown>,\n applyOptions?: GristApplyUserActionsOptions\n ) => Promise<unknown>\n removeRecord: (\n tableId: string,\n recordId: number,\n applyOptions?: GristApplyUserActionsOptions\n ) => Promise<unknown>\n bulkAddRecord: (\n tableId: string,\n values: Record<string, unknown[]>,\n applyOptions?: GristApplyUserActionsOptions\n ) => Promise<unknown>\n bulkUpdateRecord: (\n tableId: string,\n rowIds: number[],\n columnarPatch: Record<string, unknown[]>,\n applyOptions?: GristApplyUserActionsOptions\n ) => Promise<unknown>\n bulkRemoveRecord: (\n tableId: string,\n rowIds: number[],\n applyOptions?: GristApplyUserActionsOptions\n ) => Promise<unknown>\n}\n\nexport function useGristActions(options?: UseGristActionsOptions): UseGristActionsResult {\n const requiredAccess = options?.requiredAccess ?? \"full\"\n const { docApi, error: readyError } = useGristReady({\n requiredAccess,\n columns: options?.columns,\n allowSelectBy: options?.allowSelectBy,\n hasCustomOptions: options?.hasCustomOptions,\n onEditOptions: options?.onEditOptions,\n })\n const [status, setStatus] = useState<GristActionsStatus>(\"idle\")\n const [actionError, setActionError] = useState<string | null>(null)\n const coalesceRpc = useRpcHeartbeatCoalesce()\n\n const apply = useCallback(\n async (actions: GristUserActionTuple[], applyOptions?: GristApplyUserActionsOptions): Promise<unknown> => {\n if (!docApi) throw new Error(\"Grist docApi is not ready\")\n setStatus(\"running\")\n setActionError(null)\n try {\n const out = await coalesceRpc(() => docApi.applyUserActions(actions, applyOptions))\n setStatus(\"idle\")\n return out\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n setActionError(message)\n setStatus(\"error\")\n throw err\n }\n },\n [docApi, coalesceRpc]\n )\n\n const updateRecord = useCallback(\n (tableId: string, recordId: number, patch: Record<string, unknown>, applyOptions?: GristApplyUserActionsOptions) =>\n apply([gristUpdateRecordAction(tableId, recordId, patch)], applyOptions),\n [apply]\n )\n\n const addRecord = useCallback(\n (tableId: string, values: Record<string, unknown>, applyOptions?: GristApplyUserActionsOptions) =>\n apply([gristAddRecordAction(tableId, values)], applyOptions),\n [apply]\n )\n\n const removeRecord = useCallback(\n (tableId: string, recordId: number, applyOptions?: GristApplyUserActionsOptions) =>\n apply([gristRemoveRecordAction(tableId, recordId)], applyOptions),\n [apply]\n )\n\n const bulkAddRecord = useCallback(\n (tableId: string, values: Record<string, unknown[]>, applyOptions?: GristApplyUserActionsOptions) =>\n apply([gristBulkAddRecordAction(tableId, values)], applyOptions),\n [apply]\n )\n\n const bulkUpdateRecord = useCallback(\n (tableId: string, rowIds: number[], columnarPatch: Record<string, unknown[]>, applyOptions?: GristApplyUserActionsOptions) =>\n apply([gristBulkUpdateRecordAction(tableId, rowIds, columnarPatch)], applyOptions),\n [apply]\n )\n\n const bulkRemoveRecord = useCallback(\n (tableId: string, rowIds: number[], applyOptions?: GristApplyUserActionsOptions) =>\n apply([gristBulkRemoveRecordAction(tableId, rowIds)], applyOptions),\n [apply]\n )\n\n return {\n status: readyError ? \"error\" : status,\n error: readyError ?? actionError,\n apply,\n updateRecord,\n addRecord,\n removeRecord,\n bulkAddRecord,\n bulkUpdateRecord,\n bulkRemoveRecord,\n }\n}\n","import { useCallback, useEffect, useState } from \"react\"\n\nimport { recordEvent } from \"../internal/subscriptions\"\nimport { useGristReady } from \"../low-level-hooks/use-grist-ready\"\nimport type { GristReadyOptions, GristWidgetColumnMap } from \"../types\"\n\nexport type UseGristMappedRecordResult<T> = {\n rawRecord: Record<string, unknown> | null\n mappedRecord: T | null\n /** Current column mappings reported by Grist. */\n mappings: GristWidgetColumnMap | null\n loading: boolean\n error: string | null\n /**\n * Reverse-map a logical patch (`{ logicalName: value }`) into a real-column\n * patch (`{ realColId: value }`) ready for `applyUserActions` /\n * `useGristTableOps.update`.\n * Falls back to `grist.mapColumnNamesBack` when present, otherwise resolves\n * names manually from `mappings` (single-mapped columns only).\n */\n mapBack: (patch: Partial<T>) => Record<string, unknown>\n /** Resolve a single logical name to its current real column id. */\n resolveColumnId: (logicalName: keyof T & string) => string | undefined\n}\n\nfunction manualMapBack<T>(patch: Partial<T>, mappings: GristWidgetColumnMap | null): Record<string, unknown> {\n if (!mappings) return { ...(patch as Record<string, unknown>) }\n const out: Record<string, unknown> = {}\n for (const [name, value] of Object.entries(patch as Record<string, unknown>)) {\n const target = mappings[name]\n if (Array.isArray(target)) {\n // allowMultiple: cannot decide which underlying column to write — skip and warn.\n if (typeof console !== \"undefined\") {\n console.warn(`[lib/grist] mapBack: cannot reverse-map allowMultiple field \"${name}\" without grist.mapColumnNamesBack`)\n }\n continue\n }\n out[target ?? name] = value\n }\n return out\n}\n\n/**\n * Subscribes to the selected row, applies `grist.mapColumnNames` so widget code\n * sees logical column names, and exposes `mapBack` for safe writes.\n */\nexport function useGristMappedRecord<T = Record<string, unknown>>(\n options?: GristReadyOptions\n): UseGristMappedRecordResult<T> {\n const requiredAccess = options?.requiredAccess ?? \"read table\"\n const { docApi, error: readyError } = useGristReady({\n requiredAccess,\n columns: options?.columns,\n allowSelectBy: options?.allowSelectBy,\n hasCustomOptions: options?.hasCustomOptions,\n onEditOptions: options?.onEditOptions,\n })\n const [rawRecord, setRawRecord] = useState<Record<string, unknown> | null>(null)\n const [mappedRecord, setMappedRecord] = useState<T | null>(null)\n const [mappings, setMappings] = useState<GristWidgetColumnMap | null>(null)\n\n useEffect(() => {\n if (!docApi) return\n return recordEvent.subscribe(({ record, mappings: nextMappings }) => {\n setRawRecord(record)\n setMappings(nextMappings)\n if (!record) {\n setMappedRecord(null)\n return\n }\n if (typeof grist.mapColumnNames === \"function\") {\n const mapped = grist.mapColumnNames(record)\n setMappedRecord(\n mapped !== null && mapped !== undefined ? (mapped as T) : null\n )\n return\n }\n setMappedRecord(record as T)\n })\n }, [docApi])\n\n const mapBack = useCallback(\n (patch: Partial<T>): Record<string, unknown> => {\n if (typeof grist.mapColumnNamesBack === \"function\") {\n return grist.mapColumnNamesBack(patch as Record<string, unknown>)\n }\n return manualMapBack<T>(patch, mappings)\n },\n [mappings]\n )\n\n const resolveColumnId = useCallback(\n (logicalName: keyof T & string): string | undefined => {\n const value = mappings?.[logicalName]\n if (Array.isArray(value)) return undefined\n return value ?? undefined\n },\n [mappings]\n )\n\n return {\n rawRecord,\n mappedRecord,\n mappings,\n loading: docApi === null && !readyError,\n error: readyError,\n mapBack,\n resolveColumnId,\n }\n}\n","import { useCallback, useState } from \"react\"\n\nimport { useRpcHeartbeatCoalesce } from \"../internal/hooks/use-rpc-heartbeat-coalesce\"\nimport { useGristReady } from \"../low-level-hooks/use-grist-ready\"\nimport type {\n GristMinimalRecord,\n GristReadyOptions,\n GristTableNewRecord,\n GristTableOpOptions,\n GristTableOperations,\n GristTableUpdateRecord,\n GristTableUpsertOptions,\n GristTableUpsertRecord,\n} from \"../types\"\n\nexport type GristTableOpsStatus = \"idle\" | \"running\" | \"error\"\n\nexport type UseGristTableOpsOptions = {\n /**\n * Table to operate on:\n * - `\"selected\"` (default): use `grist.selectedTable` (the widget's current table).\n * - any other string: use `grist.getTable(tableId)`.\n */\n tableId?: \"selected\" | string\n /** Defaults to `\"full\"` since these operations write to the document. */\n requiredAccess?: GristReadyOptions[\"requiredAccess\"]\n} & Pick<GristReadyOptions, \"columns\" | \"allowSelectBy\" | \"hasCustomOptions\" | \"onEditOptions\">\n\nexport type UseGristTableOpsResult = {\n status: GristTableOpsStatus\n error: string | null\n /** Resolves the runtime tableId (only meaningful when `tableId` is `\"selected\"`). */\n getTableId: () => Promise<string>\n create: (\n records: GristTableNewRecord | GristTableNewRecord[],\n opOptions?: GristTableOpOptions\n ) => Promise<GristMinimalRecord | GristMinimalRecord[]>\n update: (\n records: GristTableUpdateRecord | GristTableUpdateRecord[],\n opOptions?: GristTableOpOptions\n ) => Promise<void>\n upsert: (\n records: GristTableUpsertRecord | GristTableUpsertRecord[],\n opOptions?: GristTableUpsertOptions\n ) => Promise<void>\n destroy: (recordIds: number | number[]) => Promise<void>\n}\n\nfunction resolveOps(tableId: \"selected\" | string): GristTableOperations {\n if (tableId === \"selected\") {\n if (!grist.selectedTable) throw new Error(\"grist.selectedTable is not available\")\n return grist.selectedTable\n }\n if (typeof grist.getTable !== \"function\") {\n throw new Error(\"grist.getTable is not available in this Grist version\")\n }\n return grist.getTable(tableId)\n}\n\n/**\n * Strongly-typed CRUD wrapper around Grist's `TableOperations` (`grist.selectedTable`\n * or `grist.getTable(tableId)`). Prefer this over hand-rolled `applyUserActions`.\n *\n * @see https://support.getgrist.com/code/interfaces/TableOperations.TableOperations/\n */\nexport function useGristTableOps(options?: UseGristTableOpsOptions): UseGristTableOpsResult {\n const requiredAccess = options?.requiredAccess ?? \"full\"\n const tableIdOption: \"selected\" | string = options?.tableId ?? \"selected\"\n const { docApi, error: readyError } = useGristReady({\n requiredAccess,\n columns: options?.columns,\n allowSelectBy: options?.allowSelectBy,\n hasCustomOptions: options?.hasCustomOptions,\n onEditOptions: options?.onEditOptions,\n })\n\n const [status, setStatus] = useState<GristTableOpsStatus>(\"idle\")\n const [actionError, setActionError] = useState<string | null>(null)\n const coalesceRpc = useRpcHeartbeatCoalesce()\n\n // `resolveOps` is synchronous and idempotent (it only reads `grist.selectedTable`\n // / `grist.getTable`), so derive `ops` during render instead of via effect.\n let ops: GristTableOperations | null = null\n let resolveError: string | null = null\n if (docApi) {\n try {\n ops = resolveOps(tableIdOption)\n } catch (err) {\n resolveError = err instanceof Error ? err.message : String(err)\n }\n }\n\n const wrap = useCallback(\n async <T>(run: (ops: GristTableOperations) => Promise<T>): Promise<T> => {\n if (!ops) throw new Error(\"Grist table operations are not ready\")\n setStatus(\"running\")\n setActionError(null)\n try {\n const out = await coalesceRpc(() => run(ops))\n setStatus(\"idle\")\n return out\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n setActionError(message)\n setStatus(\"error\")\n throw err\n }\n },\n [ops, coalesceRpc]\n )\n\n const getTableId = useCallback(async () => {\n if (!ops) throw new Error(\"Grist table operations are not ready\")\n return ops.getTableId()\n }, [ops])\n\n const create = useCallback(\n (records: GristTableNewRecord | GristTableNewRecord[], opOptions?: GristTableOpOptions) =>\n wrap((o) => o.create(records, opOptions)),\n [wrap]\n )\n\n const update = useCallback(\n (records: GristTableUpdateRecord | GristTableUpdateRecord[], opOptions?: GristTableOpOptions) =>\n wrap((o) => o.update(records, opOptions)),\n [wrap]\n )\n\n const upsert = useCallback(\n (records: GristTableUpsertRecord | GristTableUpsertRecord[], opOptions?: GristTableUpsertOptions) =>\n wrap((o) => o.upsert(records, opOptions)),\n [wrap]\n )\n\n const destroy = useCallback(\n (recordIds: number | number[]) => wrap((o) => o.destroy(recordIds)),\n [wrap]\n )\n\n return {\n status: readyError || resolveError ? \"error\" : status,\n error: readyError ?? resolveError ?? actionError,\n getTableId,\n create,\n update,\n upsert,\n destroy,\n }\n}\n","import { useCallback, useContext, useEffect, useRef, useState } from \"react\"\n\nimport { tableDataToRows, type GristColumnarTable } from \"../helpers/grist-table-data\"\nimport { GristReadsContext } from \"../internal/contexts\"\nimport { useRpcHeartbeatCoalesce } from \"../internal/hooks/use-rpc-heartbeat-coalesce\"\nimport { useGristReady } from \"../low-level-hooks/use-grist-ready\"\nimport type { GristReadyOptions, GristRowRecord } from \"../types\"\n\nexport type UseGristRowsFromTableOptions<T> = {\n tableId: string\n /** Re-fetch on a fixed cadence (ms). Default: disabled. */\n pollIntervalMs?: number\n /** Map raw rows to a domain shape (e.g. `decodeGristValue` your columns). */\n transform?: (row: GristRowRecord) => GristRowRecord<T>\n requiredAccess?: GristReadyOptions[\"requiredAccess\"]\n} & Pick<GristReadyOptions, \"columns\" | \"allowSelectBy\" | \"hasCustomOptions\" | \"onEditOptions\">\n\nexport type UseGristRowsFromTableResult<T> = {\n rows: GristRowRecord<T>[] | null\n loading: boolean\n error: string | null\n /** Force a re-fetch (call after writes that should be reflected immediately). */\n refresh: () => Promise<void>\n}\n\n/**\n * Subscribes to a full table's rows via `docApi.fetchTable`.\n *\n * Unlike `useGristRecords` (which is bound to the widget's selected section),\n * this hook works against any table id and **doesn't auto-update on Grist\n * writes from elsewhere** — call `refresh()` after your own writes, or set\n * `pollIntervalMs` for polling.\n */\nexport function useGristRowsFromTable<T = Record<string, unknown>>(\n options: UseGristRowsFromTableOptions<T>\n): UseGristRowsFromTableResult<T> {\n const requiredAccess = options.requiredAccess ?? \"read table\"\n const { docApi, error: readyError } = useGristReady({\n requiredAccess,\n columns: options.columns,\n allowSelectBy: options.allowSelectBy,\n hasCustomOptions: options.hasCustomOptions,\n onEditOptions: options.onEditOptions,\n })\n\n // When inside a GristWidgetProvider, delegate to the provider's guarded\n // fetchTable so access-insufficient errors flow through readError → alerts.\n const providerFetchTable = useContext(GristReadsContext)?.fetchTable\n\n const [rows, setRows] = useState<GristRowRecord<T>[] | null>(null)\n const [loading, setLoading] = useState(false)\n const [fetchError, setFetchError] = useState<string | null>(null)\n const transformRef = useRef(options.transform)\n transformRef.current = options.transform\n const coalesceRpc = useRpcHeartbeatCoalesce()\n\n const refresh = useCallback(async () => {\n if (!docApi) return\n setLoading(true)\n setFetchError(null)\n try {\n const data = providerFetchTable\n ? await providerFetchTable(options.tableId)\n : ((await coalesceRpc(\n () => docApi.fetchTable(options.tableId) as Promise<GristColumnarTable>\n )) as GristColumnarTable)\n const raw = tableDataToRows(data)\n const t = transformRef.current\n setRows(t ? raw.map((r) => t(r)) : (raw as GristRowRecord<T>[]))\n } catch (err) {\n setFetchError(err instanceof Error ? err.message : String(err))\n setRows(null)\n } finally {\n setLoading(false)\n }\n }, [docApi, providerFetchTable, options.tableId, coalesceRpc])\n\n useEffect(() => {\n if (docApi) void refresh()\n }, [docApi, refresh])\n\n useEffect(() => {\n if (!docApi || !options.pollIntervalMs || options.pollIntervalMs <= 0) return\n const id = window.setInterval(() => void refresh(), options.pollIntervalMs)\n return () => window.clearInterval(id)\n }, [docApi, options.pollIntervalMs, refresh])\n\n return {\n rows,\n loading,\n error: readyError ?? fetchError,\n refresh,\n }\n}\n","import { useCallback, useEffect, useState } from \"react\"\n\nimport {\n fetchWithGristAuth as fetchWithGristAuthCore,\n getGristAccessToken,\n type GristAccessToken,\n} from \"../helpers/grist-fetch-with-auth\"\nimport { useGristReady } from \"../low-level-hooks/use-grist-ready\"\nimport type { GristReadyOptions } from \"../types\"\n\nexport type UseGristAccessTokenOptions = {\n /** Default for all token requests issued by this hook. */\n readOnly?: boolean\n /** Pre-fetch a token on mount so `token` is non-null when widgets render. */\n prefetch?: boolean\n /** Defaults to `\"full\"` since tokens are used for REST calls. */\n requiredAccess?: GristReadyOptions[\"requiredAccess\"]\n} & Pick<GristReadyOptions, \"columns\" | \"allowSelectBy\" | \"hasCustomOptions\" | \"onEditOptions\">\n\nexport type UseGristAccessTokenResult = {\n token: GristAccessToken | null\n loading: boolean\n error: string | null\n /** Request a fresh token (Grist tokens are short-lived; do not cache aggressively). */\n refresh: (overrides?: { readOnly?: boolean }) => Promise<GristAccessToken>\n /** `fetch()` against Grist's REST API with auth attached. */\n fetch: (path: string, init?: RequestInit & { readOnly?: boolean }) => Promise<Response>\n}\n\n/**\n * Exposes `docApi.getAccessToken` plus a ready-to-use `fetch` for calling\n * Grist's REST API (e.g. attachments, records, sql) from a widget.\n */\nexport function useGristAccessToken(options?: UseGristAccessTokenOptions): UseGristAccessTokenResult {\n const requiredAccess = options?.requiredAccess ?? \"full\"\n const readOnlyDefault = options?.readOnly ?? false\n const prefetch = options?.prefetch ?? false\n const { docApi, error: readyError } = useGristReady({\n requiredAccess,\n columns: options?.columns,\n allowSelectBy: options?.allowSelectBy,\n hasCustomOptions: options?.hasCustomOptions,\n onEditOptions: options?.onEditOptions,\n })\n\n const [token, setToken] = useState<GristAccessToken | null>(null)\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n const refresh = useCallback(\n async (overrides?: { readOnly?: boolean }): Promise<GristAccessToken> => {\n if (!docApi) throw new Error(\"Grist is not ready\")\n setLoading(true)\n setError(null)\n try {\n const next = await getGristAccessToken(docApi, { readOnly: overrides?.readOnly ?? readOnlyDefault })\n setToken(next)\n return next\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n setError(message)\n throw err\n } finally {\n setLoading(false)\n }\n },\n [docApi, readOnlyDefault]\n )\n\n const fetchFn = useCallback(\n (path: string, init?: RequestInit & { readOnly?: boolean }) => {\n if (!docApi) throw new Error(\"Grist is not ready\")\n return fetchWithGristAuthCore(docApi, path, { readOnly: readOnlyDefault, ...init })\n },\n [docApi, readOnlyDefault]\n )\n\n useEffect(() => {\n if (docApi && prefetch) void refresh()\n }, [docApi, prefetch, refresh])\n\n return {\n token,\n loading,\n error: readyError ?? error,\n refresh,\n fetch: fetchFn,\n }\n}\n","import { useCallback, useEffect, useState } from \"react\"\n\nimport { useGristReady } from \"../low-level-hooks/use-grist-ready\"\nimport type { GristReadyOptions, GristWidgetColumnMap } from \"../types\"\n\nexport type UseGristSectionResult = {\n /** Current widget ↔ section column mappings, refreshed on demand. */\n mappings: GristWidgetColumnMap | null\n loading: boolean\n error: string | null\n /** Re-read mappings from `sectionApi`. */\n refresh: () => Promise<void>\n /**\n * Update the widget's declared `ColumnsToMap` (and other ready options) after\n * mount. Use this to dynamically request more columns once the user has\n * configured the widget.\n */\n configure: (options: GristReadyOptions) => Promise<void>\n}\n\n/**\n * Wraps Grist's `sectionApi` (`mappings()` + `configure()`) so widgets can\n * inspect/refresh the column mapping and re-declare requirements without\n * touching `grist` directly.\n */\nexport function useGristSection(options?: GristReadyOptions): UseGristSectionResult {\n const { docApi, error: readyError } = useGristReady({\n requiredAccess: options?.requiredAccess ?? \"read table\",\n columns: options?.columns,\n allowSelectBy: options?.allowSelectBy,\n hasCustomOptions: options?.hasCustomOptions,\n onEditOptions: options?.onEditOptions,\n })\n\n const [mappings, setMappings] = useState<GristWidgetColumnMap | null>(null)\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n const refresh = useCallback(async () => {\n if (!docApi) return\n if (!grist.sectionApi?.mappings) {\n setError(\"grist.sectionApi.mappings is not available in this Grist version\")\n return\n }\n setLoading(true)\n setError(null)\n try {\n const next = await grist.sectionApi.mappings()\n setMappings(next)\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err))\n } finally {\n setLoading(false)\n }\n }, [docApi])\n\n const configure = useCallback(async (next: GristReadyOptions) => {\n if (!grist.sectionApi?.configure) {\n throw new Error(\"grist.sectionApi.configure is not available in this Grist version\")\n }\n await grist.sectionApi.configure(next)\n }, [])\n\n useEffect(() => {\n if (docApi) void refresh()\n }, [docApi, refresh])\n\n return {\n mappings,\n loading,\n error: readyError ?? error,\n refresh,\n configure,\n }\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from \"react\"\n\nimport { optionsEvent } from \"../internal/subscriptions\"\nimport { useGristReady } from \"../low-level-hooks/use-grist-ready\"\nimport type { GristReadyOptions } from \"../types\"\n\nexport type UseGristWidgetOptionsConfig<T> = {\n /** Default values returned before Grist responds and merged with stored options. */\n defaults: T\n /** Debounce window for `setOptions` writes (ms). Default: 250. */\n debounceMs?: number\n /**\n * Optional namespace inside `grist.setOptions`. When set, this hook reads/writes\n * `grist.setOption(namespace, value)` instead of the whole options blob — useful\n * to share the options bag with `hasCustomOptions` / unrelated widget state.\n */\n namespace?: string\n requiredAccess?: GristReadyOptions[\"requiredAccess\"]\n} & Pick<GristReadyOptions, \"columns\" | \"allowSelectBy\" | \"hasCustomOptions\" | \"onEditOptions\">\n\nexport type UseGristWidgetOptionsResult<T> = {\n options: T\n /** True until Grist has responded with the initial `onOptions` payload. */\n loading: boolean\n error: string | null\n /** Replace the options object (debounced write to Grist). */\n setOptions: (next: T) => void\n /** Patch a subset of keys (debounced write to Grist). */\n patchOptions: (patch: Partial<T>) => void\n /** Reset to `defaults` (immediate write to Grist). */\n reset: () => Promise<void>\n}\n\nfunction mergeWithDefaults<T>(defaults: T, stored: unknown, namespace?: string): T {\n if (stored === null || stored === undefined) return { ...defaults }\n const source = (namespace ? (stored as Record<string, unknown>)[namespace] : stored) as Partial<T> | undefined\n if (!source || typeof source !== \"object\") return { ...defaults }\n return { ...defaults, ...source }\n}\n\n/**\n * Persist a typed object of widget settings via `grist.onOptions` / `setOptions`.\n *\n * - Defaults are returned immediately (no flicker before Grist responds).\n * - Writes are debounced and batched.\n * - `hasCustomOptions` defaults to `true` so Grist exposes the gear icon — pass\n * `hasCustomOptions: false` to opt out.\n */\nexport function useGristWidgetOptions<T extends Record<string, unknown>>(\n config: UseGristWidgetOptionsConfig<T>\n): UseGristWidgetOptionsResult<T> {\n const requiredAccess = config.requiredAccess ?? \"read table\"\n const debounceMs = config.debounceMs ?? 250\n const hasCustomOptions = config.hasCustomOptions ?? true\n const { docApi, error: readyError } = useGristReady({\n requiredAccess,\n columns: config.columns,\n allowSelectBy: config.allowSelectBy,\n hasCustomOptions,\n onEditOptions: config.onEditOptions,\n })\n\n const defaultsRef = useRef(config.defaults)\n useEffect(() => {\n defaultsRef.current = config.defaults\n }, [config.defaults])\n\n const [options, setOptionsState] = useState<T>(() => ({ ...config.defaults }))\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<string | null>(null)\n const lastWrittenRef = useRef<T | null>(null)\n const debounceRef = useRef<number | null>(null)\n\n // Subscribe to remote changes (initial + external edits)\n useEffect(() => {\n if (!docApi) return\n return optionsEvent.subscribe(({ options: stored }) => {\n const merged = mergeWithDefaults(defaultsRef.current, stored, config.namespace)\n lastWrittenRef.current = merged\n setOptionsState(merged)\n setLoading(false)\n })\n }, [docApi, config.namespace])\n\n const flushWrite = useCallback(\n async (value: T) => {\n try {\n if (config.namespace) {\n await grist.setOption(config.namespace, value)\n } else {\n await grist.setOptions({ ...value })\n }\n lastWrittenRef.current = value\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err))\n }\n },\n [config.namespace]\n )\n\n const scheduleWrite = useCallback(\n (value: T) => {\n if (debounceRef.current) window.clearTimeout(debounceRef.current)\n debounceRef.current = window.setTimeout(() => {\n debounceRef.current = null\n void flushWrite(value)\n }, debounceMs)\n },\n [debounceMs, flushWrite]\n )\n\n useEffect(() => {\n return () => {\n if (debounceRef.current) window.clearTimeout(debounceRef.current)\n }\n }, [])\n\n const setOptionsApi = useCallback(\n (next: T) => {\n setOptionsState(next)\n scheduleWrite(next)\n },\n [scheduleWrite]\n )\n\n const patchOptionsApi = useCallback(\n (patch: Partial<T>) => {\n setOptionsState((prev) => {\n const next = { ...prev, ...patch }\n scheduleWrite(next)\n return next\n })\n },\n [scheduleWrite]\n )\n\n const reset = useCallback(async () => {\n if (debounceRef.current) {\n window.clearTimeout(debounceRef.current)\n debounceRef.current = null\n }\n const next = { ...defaultsRef.current }\n setOptionsState(next)\n await flushWrite(next)\n }, [flushWrite])\n\n return useMemo(\n () => ({\n options,\n loading,\n error: readyError ?? error,\n setOptions: setOptionsApi,\n patchOptions: patchOptionsApi,\n reset,\n }),\n [options, loading, readyError, error, setOptionsApi, patchOptionsApi, reset]\n )\n}\n","import { useCallback, useEffect, useState } from \"react\"\n\nimport type { GristColumnarTable } from \"./helpers/grist-table-data\"\nimport { useGristReady } from \"./low-level-hooks/use-grist-ready\"\nimport type { GristFetchSelectedOptions, GristReadyOptions, GristRequiredAccess } from \"./types\"\n\nexport type UseGristTableOptions = {\n requiredAccess?: GristRequiredAccess\n /**\n * `'current'` (default): follow the widget’s selected table.\n * Any other string: fixed table id (no `grist.selectedTable` polling).\n */\n tableId?: \"current\" | string\n} & Pick<GristReadyOptions, \"columns\" | \"allowSelectBy\" | \"hasCustomOptions\" | \"onEditOptions\">\n\nexport type UseGristTableResult = {\n tableId: string | null\n loading: boolean\n error: string | null\n refresh: () => Promise<void>\n fetchTable: (targetTableId: string) => Promise<GristColumnarTable>\n listTables: () => Promise<string[]>\n getDocName: () => Promise<string>\n fetchSelectedTable: (fetchOptions?: GristFetchSelectedOptions) => Promise<GristColumnarTable>\n fetchSelectedRecord: (rowId: number, fetchOptions?: GristFetchSelectedOptions) => Promise<Record<string, unknown>>\n}\n\nfunction isCurrentMode(option: string | undefined): boolean {\n return option === undefined || option === \"current\"\n}\n\n/**\n * Selected or fixed table id plus document reads — no raw `docApi` on the result.\n */\nexport function useGristTable(options?: UseGristTableOptions): UseGristTableResult {\n const requiredAccess = options?.requiredAccess ?? \"read table\"\n const tableIdOption = options?.tableId ?? \"current\"\n const { docApi, error: readyError } = useGristReady({\n requiredAccess,\n columns: options?.columns,\n allowSelectBy: options?.allowSelectBy,\n hasCustomOptions: options?.hasCustomOptions,\n onEditOptions: options?.onEditOptions,\n })\n const [tableId, setTableId] = useState<string | null>(null)\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n const fetchTable = useCallback(\n async (targetTableId: string) => {\n if (!docApi) throw new Error(\"Grist is not ready\")\n return docApi.fetchTable(targetTableId) as Promise<GristColumnarTable>\n },\n [docApi]\n )\n\n const listTables = useCallback(async () => {\n if (!docApi) throw new Error(\"Grist is not ready\")\n const out = await Promise.resolve(docApi.listTables())\n return [...out]\n }, [docApi])\n\n const getDocName = useCallback(async () => {\n if (!docApi) throw new Error(\"Grist is not ready\")\n return String(await Promise.resolve(docApi.getDocName()))\n }, [docApi])\n\n const fetchSelectedTable = useCallback(\n async (fetchOptions?: GristFetchSelectedOptions) => {\n if (!docApi) throw new Error(\"Grist is not ready\")\n const impl = docApi.fetchSelectedTable ?? grist.fetchSelectedTable\n if (!impl) throw new Error(\"fetchSelectedTable is not available in this Grist version\")\n const merged: GristFetchSelectedOptions = { keepEncoded: false, format: \"rows\", ...fetchOptions }\n return (await impl(merged)) as GristColumnarTable\n },\n [docApi]\n )\n\n const fetchSelectedRecord = useCallback(\n async (rowId: number, fetchOptions?: GristFetchSelectedOptions) => {\n if (!docApi) throw new Error(\"Grist is not ready\")\n const impl = docApi.fetchSelectedRecord ?? grist.fetchSelectedRecord\n if (!impl) throw new Error(\"fetchSelectedRecord is not available in this Grist version\")\n const merged: GristFetchSelectedOptions = { keepEncoded: false, format: \"rows\", ...fetchOptions }\n return (await impl(rowId, merged)) as Record<string, unknown>\n },\n [docApi]\n )\n\n const refresh = useCallback(async () => {\n if (!docApi) return\n if (!isCurrentMode(tableIdOption)) {\n setTableId(tableIdOption)\n setError(null)\n return\n }\n setLoading(true)\n setError(null)\n try {\n const next = await grist.selectedTable?.getTableId()\n setTableId(next ?? null)\n } catch (err) {\n setTableId(null)\n setError(err instanceof Error ? err.message : String(err))\n } finally {\n setLoading(false)\n }\n }, [docApi, tableIdOption])\n\n useEffect(() => {\n if (docApi) void refresh()\n }, [docApi, refresh])\n\n return {\n tableId,\n loading,\n error: readyError ?? error,\n refresh,\n fetchTable,\n listTables,\n getDocName,\n fetchSelectedTable,\n fetchSelectedRecord,\n }\n}\n"],"mappings":"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","names":["useMemo","useSyncExternalStore","useSyncExternalStore","useMemo","useEffect","useMemo","useRef","useSyncExternalStore","useRef","useEffect","useSyncExternalStore","useMemo","useEffect","useRef","useRef","useEffect","useEffect","useRef","useState","useRef","useEffect","useState","useEffect","useRef","useState","useState","useRef","useEffect","useState","useState","useCallback","useEffect","useState","useState","useEffect","useCallback","useCallback","useState","useState","useCallback","useCallback","useContext","useEffect","useRef","useState","useContext","useState","useRef","useCallback","useEffect","useCallback","useEffect","useState","useState","useCallback","useEffect","useCallback","useEffect","useState","useState","useCallback","useEffect","useCallback","useEffect","useMemo","useRef","useState","useRef","useEffect","useState","useCallback","useMemo","useCallback","useEffect","useState","useState","useCallback","useEffect"]}
|
package/dist/chunk-22U7WAY3.js
DELETED
|
@@ -1,463 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
applyUserActions,
|
|
3
|
-
buildGristThemeHostMessage,
|
|
4
|
-
createDocument,
|
|
5
|
-
createIframeTransport,
|
|
6
|
-
createInlineTransport,
|
|
7
|
-
findRow,
|
|
8
|
-
getSelectedTable,
|
|
9
|
-
getTable,
|
|
10
|
-
synthesizeTablesColumnMeta,
|
|
11
|
-
synthesizeTablesMeta
|
|
12
|
-
} from "./chunk-YQNMIL33.js";
|
|
13
|
-
import {
|
|
14
|
-
rowToRecord,
|
|
15
|
-
rowsToColumnar
|
|
16
|
-
} from "./chunk-ELGVOHFD.js";
|
|
17
|
-
import {
|
|
18
|
-
resolveMappings
|
|
19
|
-
} from "./chunk-PM3B4WYV.js";
|
|
20
|
-
|
|
21
|
-
// src/emulator/validators.ts
|
|
22
|
-
import { z } from "zod";
|
|
23
|
-
var emulatorRowSchema = z.object({ id: z.number() }).catchall(z.unknown());
|
|
24
|
-
var formulaKindSchema = z.enum(["computed", "trigger", "none", "empty_slot"]);
|
|
25
|
-
var replicaColumnSchema = z.object({
|
|
26
|
-
colRef: z.number().optional(),
|
|
27
|
-
type: z.string().optional(),
|
|
28
|
-
label: z.string().optional(),
|
|
29
|
-
parentPos: z.number().optional(),
|
|
30
|
-
isFormula: z.boolean().optional(),
|
|
31
|
-
formulaKind: formulaKindSchema.optional(),
|
|
32
|
-
formula: z.string().optional(),
|
|
33
|
-
description: z.string().optional(),
|
|
34
|
-
widgetOptions: z.record(z.string(), z.unknown()).optional(),
|
|
35
|
-
displayColRef: z.number().optional(),
|
|
36
|
-
visibleColRef: z.number().optional()
|
|
37
|
-
}).strict();
|
|
38
|
-
var replicaTableSchema = z.object({
|
|
39
|
-
label: z.string().optional(),
|
|
40
|
-
columns: z.record(z.string(), replicaColumnSchema).optional(),
|
|
41
|
-
rows: z.array(emulatorRowSchema).optional(),
|
|
42
|
-
rowCount: z.number().optional(),
|
|
43
|
-
dataOmitted: z.boolean().optional(),
|
|
44
|
-
dataOmittedReason: z.string().optional(),
|
|
45
|
-
error: z.string().optional()
|
|
46
|
-
}).strict();
|
|
47
|
-
var replicaSelectionSchema = z.object({
|
|
48
|
-
tableId: z.string().optional(),
|
|
49
|
-
rowId: z.union([z.number(), z.literal("new"), z.null()]).optional(),
|
|
50
|
-
mappings: z.unknown().nullable().optional(),
|
|
51
|
-
cursor: z.unknown().optional()
|
|
52
|
-
}).strict();
|
|
53
|
-
var replicaWidgetConfigurationSchema = z.object({
|
|
54
|
-
requiredAccess: z.string().optional(),
|
|
55
|
-
columns: z.unknown().optional(),
|
|
56
|
-
allowSelectBy: z.boolean().optional(),
|
|
57
|
-
hasCustomOptions: z.boolean().optional()
|
|
58
|
-
}).strict();
|
|
59
|
-
var replicaAccessTokenSchema = z.object({
|
|
60
|
-
token: z.string(),
|
|
61
|
-
baseUrl: z.string(),
|
|
62
|
-
ttlMsecs: z.number()
|
|
63
|
-
}).strict();
|
|
64
|
-
var replicaDocumentSchema = z.object({
|
|
65
|
-
generatedAt: z.string(),
|
|
66
|
-
source: z.string().optional(),
|
|
67
|
-
docName: z.string().optional(),
|
|
68
|
-
mode: z.enum(["schema-only", "schema+samples", "schema+data"]).optional(),
|
|
69
|
-
tables: z.record(z.string(), replicaTableSchema),
|
|
70
|
-
selection: replicaSelectionSchema.optional(),
|
|
71
|
-
widgetOptions: z.record(z.string(), z.unknown()).optional(),
|
|
72
|
-
widgetInteraction: z.unknown().optional(),
|
|
73
|
-
configuration: replicaWidgetConfigurationSchema.optional(),
|
|
74
|
-
accessToken: replicaAccessTokenSchema.nullable().optional()
|
|
75
|
-
}).strict().refine((value) => Object.keys(value.tables).length > 0, {
|
|
76
|
-
message: "at least one table is required",
|
|
77
|
-
path: ["tables"]
|
|
78
|
-
});
|
|
79
|
-
function formatZodError(prefix, error) {
|
|
80
|
-
const details = error.issues.map((issue) => {
|
|
81
|
-
const where = issue.path.length > 0 ? issue.path.join(".") : "<root>";
|
|
82
|
-
return `${where}: ${issue.message}`;
|
|
83
|
-
}).join("; ");
|
|
84
|
-
return new Error(`${prefix}: ${details}`);
|
|
85
|
-
}
|
|
86
|
-
function safeParseDocument(input) {
|
|
87
|
-
return replicaDocumentSchema.safeParse(input);
|
|
88
|
-
}
|
|
89
|
-
function parseDocument(input) {
|
|
90
|
-
const result = safeParseDocument(input);
|
|
91
|
-
if (!result.success) {
|
|
92
|
-
throw formatZodError("parseDocument", result.error);
|
|
93
|
-
}
|
|
94
|
-
return result.data;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// src/emulator/api/command-api.ts
|
|
98
|
-
function createCommandApiImpl(bus) {
|
|
99
|
-
return {
|
|
100
|
-
async run(name) {
|
|
101
|
-
bus.emit({ type: "user-action", action: ["RunCommand", name] });
|
|
102
|
-
}
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// src/emulator/api/custom-section-api.ts
|
|
107
|
-
function createCustomSectionApiImpl(state, bus) {
|
|
108
|
-
return {
|
|
109
|
-
async configure(settings) {
|
|
110
|
-
const config = {
|
|
111
|
-
requiredAccess: settings.requiredAccess,
|
|
112
|
-
columns: settings.columns,
|
|
113
|
-
allowSelectBy: settings.allowSelectBy,
|
|
114
|
-
hasCustomOptions: settings.hasCustomOptions
|
|
115
|
-
};
|
|
116
|
-
state.configuration = config;
|
|
117
|
-
bus.emit({ type: "ready", configuration: config });
|
|
118
|
-
bus.emit({ type: "mappings-change", mappings: resolveMappings(state) });
|
|
119
|
-
},
|
|
120
|
-
async mappings() {
|
|
121
|
-
return resolveMappings(state);
|
|
122
|
-
}
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// src/emulator/api/grist-api.ts
|
|
127
|
-
function createGristApiImpl() {
|
|
128
|
-
return {
|
|
129
|
-
async ping() {
|
|
130
|
-
return "pong";
|
|
131
|
-
}
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// src/emulator/api/grist-doc-api.ts
|
|
136
|
-
function createGristDocApiImpl(state, bus) {
|
|
137
|
-
return {
|
|
138
|
-
async getDocName() {
|
|
139
|
-
return state.docName;
|
|
140
|
-
},
|
|
141
|
-
async listTables() {
|
|
142
|
-
return [...state.tables.keys()];
|
|
143
|
-
},
|
|
144
|
-
async fetchTable(tableId) {
|
|
145
|
-
if (tableId === "_grist_Tables") {
|
|
146
|
-
return synthesizeTablesMeta(state);
|
|
147
|
-
}
|
|
148
|
-
if (tableId === "_grist_Tables_column") {
|
|
149
|
-
return synthesizeTablesColumnMeta(state);
|
|
150
|
-
}
|
|
151
|
-
const table = getTable(state, tableId);
|
|
152
|
-
return rowsToColumnar(table, table.rows);
|
|
153
|
-
},
|
|
154
|
-
async applyUserActions(actions) {
|
|
155
|
-
const result = applyUserActions(state, bus, actions);
|
|
156
|
-
return { retValues: result.retValues };
|
|
157
|
-
},
|
|
158
|
-
async getAccessToken() {
|
|
159
|
-
if (!state.accessToken) {
|
|
160
|
-
const err = new Error("getAccessToken not available (no token configured on emulator)");
|
|
161
|
-
throw err;
|
|
162
|
-
}
|
|
163
|
-
return { ...state.accessToken };
|
|
164
|
-
}
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// src/emulator/api/grist-view.ts
|
|
169
|
-
function createGristViewImpl(state, bus) {
|
|
170
|
-
return {
|
|
171
|
-
async fetchSelectedTable(options) {
|
|
172
|
-
const table = getSelectedTable(state);
|
|
173
|
-
return rowsToColumnar(table, table.rows, { keepEncoded: options?.keepEncoded });
|
|
174
|
-
},
|
|
175
|
-
async fetchSelectedRecord(rowId, options) {
|
|
176
|
-
const table = getSelectedTable(state);
|
|
177
|
-
const row = findRow(table, rowId);
|
|
178
|
-
if (!row) throw new Error(`No row ${rowId} in ${table.tableId}`);
|
|
179
|
-
return rowToRecord(table, row, { keepEncoded: options?.keepEncoded });
|
|
180
|
-
},
|
|
181
|
-
async allowSelectBy() {
|
|
182
|
-
return state.configuration?.allowSelectBy ?? false;
|
|
183
|
-
},
|
|
184
|
-
async setSelectedRows(rowIds) {
|
|
185
|
-
if (!rowIds || rowIds.length === 0) {
|
|
186
|
-
state.selection.rowId = null;
|
|
187
|
-
} else {
|
|
188
|
-
state.selection.rowId = rowIds[0];
|
|
189
|
-
}
|
|
190
|
-
bus.emit({
|
|
191
|
-
type: "cursor-change",
|
|
192
|
-
tableId: state.selection.tableId,
|
|
193
|
-
rowId: state.selection.rowId
|
|
194
|
-
});
|
|
195
|
-
},
|
|
196
|
-
async setCursorPos(cursor) {
|
|
197
|
-
const tableId = state.selection.tableId;
|
|
198
|
-
if (typeof cursor.rowId === "number") state.selection.rowId = cursor.rowId;
|
|
199
|
-
state.selection.cursor = { ...state.selection.cursor, ...cursor };
|
|
200
|
-
bus.emit({
|
|
201
|
-
type: "cursor-change",
|
|
202
|
-
tableId,
|
|
203
|
-
rowId: state.selection.rowId,
|
|
204
|
-
cursor: state.selection.cursor
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
// src/emulator/api/widget-api.ts
|
|
211
|
-
function createWidgetApiImpl(state, bus) {
|
|
212
|
-
function emit() {
|
|
213
|
-
bus.emit({
|
|
214
|
-
type: "options-change",
|
|
215
|
-
options: { ...state.widgetOptions },
|
|
216
|
-
interaction: { ...state.widgetInteraction }
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
return {
|
|
220
|
-
async getOption(key) {
|
|
221
|
-
return state.widgetOptions[key];
|
|
222
|
-
},
|
|
223
|
-
async setOption(key, value) {
|
|
224
|
-
state.widgetOptions[key] = value;
|
|
225
|
-
emit();
|
|
226
|
-
},
|
|
227
|
-
async getOptions() {
|
|
228
|
-
return Object.keys(state.widgetOptions).length > 0 ? { ...state.widgetOptions } : null;
|
|
229
|
-
},
|
|
230
|
-
async setOptions(options) {
|
|
231
|
-
state.widgetOptions = { ...state.widgetOptions, ...options };
|
|
232
|
-
emit();
|
|
233
|
-
},
|
|
234
|
-
async clearOptions() {
|
|
235
|
-
state.widgetOptions = {};
|
|
236
|
-
emit();
|
|
237
|
-
}
|
|
238
|
-
};
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
// src/emulator/api/index.ts
|
|
242
|
-
function createApiBundle(state, bus) {
|
|
243
|
-
return {
|
|
244
|
-
GristView: createGristViewImpl(state, bus),
|
|
245
|
-
GristDocAPI: createGristDocApiImpl(state, bus),
|
|
246
|
-
WidgetAPI: createWidgetApiImpl(state, bus),
|
|
247
|
-
CustomSectionAPI: createCustomSectionApiImpl(state, bus),
|
|
248
|
-
GristAPI: createGristApiImpl(),
|
|
249
|
-
CommandAPI: createCommandApiImpl(bus)
|
|
250
|
-
};
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// src/emulator/core/event-bus.ts
|
|
254
|
-
function createEventBus(options = {}) {
|
|
255
|
-
const limit = options.historyLimit ?? 200;
|
|
256
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
257
|
-
const history = [];
|
|
258
|
-
return {
|
|
259
|
-
emit(event) {
|
|
260
|
-
history.push(event);
|
|
261
|
-
if (history.length > limit) history.shift();
|
|
262
|
-
for (const fn of [...listeners]) {
|
|
263
|
-
try {
|
|
264
|
-
fn(event);
|
|
265
|
-
} catch (err) {
|
|
266
|
-
console.error("[grist-emulator] event listener threw:", err);
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
},
|
|
270
|
-
on(listener) {
|
|
271
|
-
listeners.add(listener);
|
|
272
|
-
return () => {
|
|
273
|
-
listeners.delete(listener);
|
|
274
|
-
};
|
|
275
|
-
},
|
|
276
|
-
history() {
|
|
277
|
-
return history;
|
|
278
|
-
},
|
|
279
|
-
clear() {
|
|
280
|
-
history.length = 0;
|
|
281
|
-
}
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// src/emulator/create-grist-emulator.ts
|
|
286
|
-
function createGristEmulator(options) {
|
|
287
|
-
const validatedDocument = parseDocument(options.document);
|
|
288
|
-
const state = createDocument({
|
|
289
|
-
...validatedDocument,
|
|
290
|
-
widgetOptions: options.widgetOptions ?? validatedDocument.widgetOptions,
|
|
291
|
-
widgetInteraction: options.widgetInteraction ?? validatedDocument.widgetInteraction ?? { access_level: "read table" }
|
|
292
|
-
});
|
|
293
|
-
const bus = createEventBus();
|
|
294
|
-
const api = createApiBundle(state, bus);
|
|
295
|
-
const transportKind = options.transport?.kind ?? "inline";
|
|
296
|
-
let transport;
|
|
297
|
-
let grist;
|
|
298
|
-
if (transportKind === "iframe") {
|
|
299
|
-
if (options.transport?.kind !== "iframe") throw new Error("transport mismatch");
|
|
300
|
-
transport = createIframeTransport({
|
|
301
|
-
iframe: options.transport.iframe,
|
|
302
|
-
targetOrigin: options.transport.targetOrigin,
|
|
303
|
-
state,
|
|
304
|
-
bus,
|
|
305
|
-
api,
|
|
306
|
-
initialTheme: options.initialTheme
|
|
307
|
-
});
|
|
308
|
-
} else {
|
|
309
|
-
const inline = createInlineTransport({
|
|
310
|
-
state,
|
|
311
|
-
bus,
|
|
312
|
-
api,
|
|
313
|
-
initialTheme: options.initialTheme,
|
|
314
|
-
target: options.transport?.kind === "inline" ? options.transport.target : void 0
|
|
315
|
-
});
|
|
316
|
-
transport = inline;
|
|
317
|
-
grist = inline.grist;
|
|
318
|
-
}
|
|
319
|
-
function apply(actions) {
|
|
320
|
-
return applyUserActions(state, bus, actions);
|
|
321
|
-
}
|
|
322
|
-
return {
|
|
323
|
-
state,
|
|
324
|
-
bus,
|
|
325
|
-
api,
|
|
326
|
-
transport,
|
|
327
|
-
grist,
|
|
328
|
-
apply,
|
|
329
|
-
mutate: {
|
|
330
|
-
addRow: (tableId, fields) => apply([["AddRecord", tableId, null, fields]]).retValues[0],
|
|
331
|
-
updateRow: (tableId, rowId, fields) => {
|
|
332
|
-
apply([["UpdateRecord", tableId, rowId, fields]]);
|
|
333
|
-
},
|
|
334
|
-
removeRow: (tableId, rowId) => {
|
|
335
|
-
apply([["RemoveRecord", tableId, rowId]]);
|
|
336
|
-
}
|
|
337
|
-
},
|
|
338
|
-
selectRow(rowId) {
|
|
339
|
-
state.selection.rowId = rowId;
|
|
340
|
-
bus.emit({ type: "cursor-change", tableId: state.selection.tableId, rowId });
|
|
341
|
-
},
|
|
342
|
-
selectTable(tableId) {
|
|
343
|
-
if (!state.tables.has(tableId)) throw new Error(`Unknown table: ${tableId}`);
|
|
344
|
-
state.selection.tableId = tableId;
|
|
345
|
-
const first = state.tables.get(tableId).rows[0]?.id ?? null;
|
|
346
|
-
state.selection.rowId = first;
|
|
347
|
-
bus.emit({ type: "data-change", tableId });
|
|
348
|
-
bus.emit({ type: "cursor-change", tableId, rowId: first });
|
|
349
|
-
},
|
|
350
|
-
setColumnMappings(mappings) {
|
|
351
|
-
if (mappings === void 0) {
|
|
352
|
-
delete state.selection.mappings;
|
|
353
|
-
} else {
|
|
354
|
-
state.selection.mappings = mappings;
|
|
355
|
-
}
|
|
356
|
-
bus.emit({ type: "mappings-change", mappings: resolveMappings(state) });
|
|
357
|
-
},
|
|
358
|
-
async setOptions(opts) {
|
|
359
|
-
await api.WidgetAPI.setOptions(opts);
|
|
360
|
-
},
|
|
361
|
-
setInteraction(interaction) {
|
|
362
|
-
state.widgetInteraction = { ...interaction };
|
|
363
|
-
bus.emit({ type: "options-change", options: { ...state.widgetOptions }, interaction: { ...interaction } });
|
|
364
|
-
},
|
|
365
|
-
theme: {
|
|
366
|
-
set(next) {
|
|
367
|
-
bus.emit({ type: "theme-change", message: buildGristThemeHostMessage(next) });
|
|
368
|
-
}
|
|
369
|
-
},
|
|
370
|
-
dispose() {
|
|
371
|
-
transport.dispose();
|
|
372
|
-
bus.clear();
|
|
373
|
-
}
|
|
374
|
-
};
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
// src/emulator/templates.ts
|
|
378
|
-
var PRESET_GENERATED_AT = "1970-01-01T00:00:00.000Z";
|
|
379
|
-
function replicaBase(overrides) {
|
|
380
|
-
return {
|
|
381
|
-
generatedAt: PRESET_GENERATED_AT,
|
|
382
|
-
...overrides
|
|
383
|
-
};
|
|
384
|
-
}
|
|
385
|
-
var presets = {
|
|
386
|
-
/**
|
|
387
|
-
* Default starter fixture for demos / sandboxes that need a neutral document
|
|
388
|
-
* without choosing a domain-specific preset.
|
|
389
|
-
*/
|
|
390
|
-
defaultTemplate() {
|
|
391
|
-
return replicaBase({
|
|
392
|
-
docName: "Default",
|
|
393
|
-
tables: {
|
|
394
|
-
Table1: {
|
|
395
|
-
label: "Table1",
|
|
396
|
-
rows: [
|
|
397
|
-
{ id: 1, Name: "Alice" },
|
|
398
|
-
{ id: 2, Name: "Bob" }
|
|
399
|
-
]
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
});
|
|
403
|
-
},
|
|
404
|
-
blank() {
|
|
405
|
-
return replicaBase({
|
|
406
|
-
docName: "Blank",
|
|
407
|
-
tables: {
|
|
408
|
-
Table1: { rows: [{ id: 1 }] }
|
|
409
|
-
}
|
|
410
|
-
});
|
|
411
|
-
},
|
|
412
|
-
todoList() {
|
|
413
|
-
return replicaBase({
|
|
414
|
-
docName: "Todo list",
|
|
415
|
-
mode: "schema+data",
|
|
416
|
-
tables: {
|
|
417
|
-
Tasks: {
|
|
418
|
-
label: "Tasks",
|
|
419
|
-
columns: {
|
|
420
|
-
title: { type: "Text", label: "Title" },
|
|
421
|
-
done: { type: "Bool", label: "Done" },
|
|
422
|
-
priority: { type: "Choice", label: "Priority" }
|
|
423
|
-
},
|
|
424
|
-
rows: [
|
|
425
|
-
{ id: 1, title: "Buy milk", done: false, priority: "high" },
|
|
426
|
-
{ id: 2, title: "Write the SOTA emulator", done: true, priority: "high" },
|
|
427
|
-
{ id: 3, title: "Ship it", done: false, priority: "medium" }
|
|
428
|
-
]
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
});
|
|
432
|
-
},
|
|
433
|
-
contacts() {
|
|
434
|
-
return replicaBase({
|
|
435
|
-
docName: "Contacts",
|
|
436
|
-
mode: "schema+data",
|
|
437
|
-
tables: {
|
|
438
|
-
Contacts: {
|
|
439
|
-
label: "Contacts",
|
|
440
|
-
columns: {
|
|
441
|
-
firstName: { type: "Text" },
|
|
442
|
-
lastName: { type: "Text" },
|
|
443
|
-
email: { type: "Text" },
|
|
444
|
-
company: { type: "Text" }
|
|
445
|
-
},
|
|
446
|
-
rows: [
|
|
447
|
-
{ id: 1, firstName: "Ada", lastName: "Lovelace", email: "ada@analytical.engine", company: "British Crown" },
|
|
448
|
-
{ id: 2, firstName: "Linus", lastName: "Torvalds", email: "linus@kernel.org", company: "Linux Foundation" },
|
|
449
|
-
{ id: 3, firstName: "Margaret", lastName: "Hamilton", email: "margaret@apollo.nasa", company: "NASA" }
|
|
450
|
-
]
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
});
|
|
454
|
-
}
|
|
455
|
-
};
|
|
456
|
-
|
|
457
|
-
export {
|
|
458
|
-
safeParseDocument,
|
|
459
|
-
parseDocument,
|
|
460
|
-
createGristEmulator,
|
|
461
|
-
presets
|
|
462
|
-
};
|
|
463
|
-
//# sourceMappingURL=chunk-22U7WAY3.js.map
|