grist-widget-sdk 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/CHANGELOG.md +730 -0
  2. package/LICENSE +15 -0
  3. package/README.md +249 -0
  4. package/dist/advanced.cjs +2749 -0
  5. package/dist/advanced.cjs.map +1 -0
  6. package/dist/advanced.d.cts +790 -0
  7. package/dist/advanced.d.ts +790 -0
  8. package/dist/advanced.js +825 -0
  9. package/dist/advanced.js.map +1 -0
  10. package/dist/chunk-64SVRWW7.js +758 -0
  11. package/dist/chunk-64SVRWW7.js.map +1 -0
  12. package/dist/chunk-BNBV24WM.js +479 -0
  13. package/dist/chunk-BNBV24WM.js.map +1 -0
  14. package/dist/chunk-ELGVOHFD.js +32 -0
  15. package/dist/chunk-ELGVOHFD.js.map +1 -0
  16. package/dist/chunk-GTTD5HPO.js +36 -0
  17. package/dist/chunk-GTTD5HPO.js.map +1 -0
  18. package/dist/chunk-JASMM2YC.js +243 -0
  19. package/dist/chunk-JASMM2YC.js.map +1 -0
  20. package/dist/chunk-PM3B4WYV.js +12 -0
  21. package/dist/chunk-PM3B4WYV.js.map +1 -0
  22. package/dist/chunk-QKXKZ27D.js +1189 -0
  23. package/dist/chunk-QKXKZ27D.js.map +1 -0
  24. package/dist/chunk-QZG7SNUG.js +463 -0
  25. package/dist/chunk-QZG7SNUG.js.map +1 -0
  26. package/dist/chunk-REV5AUXD.js +25 -0
  27. package/dist/chunk-REV5AUXD.js.map +1 -0
  28. package/dist/chunk-XE2SKNLH.js +1641 -0
  29. package/dist/chunk-XE2SKNLH.js.map +1 -0
  30. package/dist/create-grist-emulator-C_0I4wax.d.ts +80 -0
  31. package/dist/create-grist-emulator-DBS6gmiI.d.cts +80 -0
  32. package/dist/emulator/devtools.cjs +1367 -0
  33. package/dist/emulator/devtools.cjs.map +1 -0
  34. package/dist/emulator/devtools.d.cts +46 -0
  35. package/dist/emulator/devtools.d.ts +46 -0
  36. package/dist/emulator/devtools.js +480 -0
  37. package/dist/emulator/devtools.js.map +1 -0
  38. package/dist/emulator/testing.cjs +2061 -0
  39. package/dist/emulator/testing.cjs.map +1 -0
  40. package/dist/emulator/testing.d.cts +50 -0
  41. package/dist/emulator/testing.d.ts +50 -0
  42. package/dist/emulator/testing.js +124 -0
  43. package/dist/emulator/testing.js.map +1 -0
  44. package/dist/emulator/transports.cjs +1132 -0
  45. package/dist/emulator/transports.cjs.map +1 -0
  46. package/dist/emulator/transports.d.cts +37 -0
  47. package/dist/emulator/transports.d.ts +37 -0
  48. package/dist/emulator/transports.js +12 -0
  49. package/dist/emulator/transports.js.map +1 -0
  50. package/dist/emulator.cjs +1796 -0
  51. package/dist/emulator.cjs.map +1 -0
  52. package/dist/emulator.d.cts +107 -0
  53. package/dist/emulator.d.ts +107 -0
  54. package/dist/emulator.js +26 -0
  55. package/dist/emulator.js.map +1 -0
  56. package/dist/index.cjs +5511 -0
  57. package/dist/index.cjs.map +1 -0
  58. package/dist/index.d.cts +825 -0
  59. package/dist/index.d.ts +825 -0
  60. package/dist/index.js +2447 -0
  61. package/dist/index.js.map +1 -0
  62. package/dist/inline-CRwQQ-GW.d.cts +311 -0
  63. package/dist/inline-QitZwXKP.d.ts +311 -0
  64. package/dist/templates-BC7FoSdW.d.ts +24 -0
  65. package/dist/templates-DBq719O_.d.cts +24 -0
  66. package/dist/types-Fb2wplkv.d.cts +228 -0
  67. package/dist/types-Fb2wplkv.d.ts +228 -0
  68. package/dist/use-grist-widget-options-from-context-BFhQBGRY.d.ts +522 -0
  69. package/dist/use-grist-widget-options-from-context-qpFMdoBJ.d.cts +522 -0
  70. package/package.json +131 -0
package/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2026, Arthur Blanchon
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,249 @@
1
+ # grist-widget-sdk
2
+
3
+ React hooks and TypeScript utilities for building Grist widgets.
4
+
5
+ ## Why not use `grist` directly?
6
+
7
+ Grist’s [`grist-plugin-api.js`](https://docs.getgrist.com/grist-plugin-api.js) exposes a global `grist` object. For React widgets, **`grist-widget-sdk`** replaces hand-rolled glue:
8
+
9
+ | Raw `grist` | SDK |
10
+ | --- | --- |
11
+ | `grist.ready` + `onRecord` callbacks | `<GristWidgetProvider>` + `useGrist()` with `mode` |
12
+ | Wire-format dates/refs | Decoded values by default |
13
+ | `mapColumnNames` / tuples for writes | `mappedRecord`, `mapBack`, `table.update` |
14
+ | No test harness | `renderWithGrist` + emulator presets |
15
+
16
+ Full comparison: [Raw plugin API vs SDK](https://github.com/ArthurBlanchon/grist-widget-sdk/blob/main/apps/docs/guide/raw-plugin-api-vs-sdk.md) (also in the published docs site under **Guide → Raw API vs SDK**).
17
+
18
+ ## What This Package Provides
19
+
20
+ - Main API via `grist-widget-sdk` (hooks, types, helpers)
21
+ - `grist-widget-sdk/advanced` — lower-level hooks (`useGristReady`, `useGristHandshake`, …)
22
+ - `grist-widget-sdk/emulator` subpath for emulator utilities
23
+ - ESM + CJS + type declaration builds (`.d.ts`)
24
+
25
+ ## Installation
26
+
27
+ ```bash
28
+ pnpm add grist-widget-sdk
29
+ ```
30
+
31
+ Required peer dependencies:
32
+
33
+ - `react >= 18`
34
+ - `react-dom >= 18`
35
+
36
+ ## Grist Runtime Script (Required)
37
+
38
+ This package expects a global `grist` object at runtime.
39
+
40
+ Load the official Grist plugin API script in your app shell/layout:
41
+
42
+ ```html
43
+ <script src="https://docs.getgrist.com/grist-plugin-api.js"></script>
44
+ ```
45
+
46
+ ## Quick Start Next.js (`app/layout.tsx`)
47
+
48
+ ```tsx
49
+ import Script from "next/script"
50
+ import { GristBoundary, GristWidgetProvider } from "grist-widget-sdk"
51
+
52
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
53
+ return (
54
+ <html lang="en">
55
+ <body>
56
+ <Script src="https://docs.getgrist.com/grist-plugin-api.js" />
57
+ <GristWidgetProvider options={{ requiredAccess: "read table" }}>
58
+ <GristBoundary>
59
+ {children}
60
+ </GristBoundary>
61
+ </GristWidgetProvider>
62
+ </body>
63
+ </html>
64
+ )
65
+ }
66
+ ```
67
+
68
+ Then render widget content from your page, for example `app/page.tsx`:
69
+
70
+ ```tsx
71
+ import { useGrist } from "grist-widget-sdk"
72
+
73
+ export default function Page() {
74
+ const w = useGrist()
75
+
76
+ if (w.status === "booting") return <p>Loading...</p>
77
+ if (w.mode === "empty") return <p>Select a row.</p>
78
+ if (w.mode === "new-row") return <p>New row flow</p>
79
+
80
+ return <p>Record id: {String(w.record?.id ?? "")}</p>
81
+ }
82
+ ```
83
+
84
+ ## Quick Start Vite (`src/main.tsx`)
85
+
86
+ In `index.html`, load the script:
87
+
88
+ ```html
89
+ <script src="https://docs.getgrist.com/grist-plugin-api.js"></script>
90
+ ```
91
+
92
+ Then mount your widget root:
93
+
94
+ ```tsx
95
+ import { StrictMode } from "react"
96
+ import { createRoot } from "react-dom/client"
97
+ import { GristBoundary, GristWidgetProvider, useGrist } from "grist-widget-sdk"
98
+
99
+ function WidgetContent() {
100
+ const w = useGrist()
101
+
102
+ if (w.status === "booting") return <p>Loading...</p>
103
+ if (w.mode === "empty") return <p>Select a row.</p>
104
+ if (w.mode === "new-row") return <p>New row flow</p>
105
+
106
+ return <p>Record id: {String(w.record?.id ?? "")}</p>
107
+ }
108
+
109
+ function App() {
110
+ return (
111
+ <GristWidgetProvider options={{ requiredAccess: "read table" }}>
112
+ <GristBoundary>
113
+ <WidgetContent />
114
+ </GristBoundary>
115
+ </GristWidgetProvider>
116
+ )
117
+ }
118
+
119
+ createRoot(document.getElementById("root")!).render(
120
+ <StrictMode>
121
+ <App />
122
+ </StrictMode>
123
+ )
124
+ ```
125
+
126
+ ## Exports
127
+
128
+ Main entrypoint:
129
+
130
+ - `grist-widget-sdk` — production surface:
131
+ - Components: `GristWidgetProvider`, `GristBoundary`, `useGristContext`, `useGristOptional`
132
+ - Primary hook: `useGrist` (includes `capabilities` — `canRender`, `canWriteRecords`, …)
133
+ - Slice hooks: `useGristStatus`, `useGristSelection`, `useGristWrites`, `useGristTheme`
134
+ - Schema hook: `useGristSchema`
135
+ - Helpers: action builders, value codec, safe parsing, replica builders,
136
+ REST auth, attachments, column-mapping validation, alerts.
137
+
138
+ Subpath exports:
139
+
140
+ - `grist-widget-sdk/advanced` — low-level / mid-level hooks for power users
141
+ (`useGristReady`, `useGristAvailability`, `useGristRecord`, `useGristRecords`,
142
+ `useGristActions`, `useGristTableOps`, `useGristMappedRecord`,
143
+ `useGristRowsFromTable`, `useGristAccessToken`, `useGristSection`,
144
+ `useGristWidgetOptions`, `useGristTable`).
145
+ - `grist-widget-sdk/emulator` — `createGristEmulator`, `parseDocument`,
146
+ `safeParseDocument`, `presets`, emulator types.
147
+
148
+ ## Replica document (`GristReplicaDocument`)
149
+
150
+ One JSON shape is used for **`useGristSchema()`**, **`getDocumentJson` / `buildDocumentJson`**, playground **`*.grist.json`** fixtures, and **`createGristEmulator({ document })`**. Valid fixtures are checked with **`parseDocument`** (Zod).
151
+
152
+ ### Top-level fields
153
+
154
+ | Field | Required | Notes |
155
+ | --- | --- | --- |
156
+ | `generatedAt` | yes | ISO 8601 string |
157
+ | `tables` | yes | `Record<tableId, GristReplicaTable>` — keys align with `docApi.listTables()` / `fetchTable(tableId)` |
158
+ | `source` | no | Provenance (e.g. pass `useGristSchema({ source })` or `buildReplicaDocumentFromDocApi(docApi, { source })`); hosts may log it |
159
+ | `docName`, `mode`, `selection`, `widgetOptions`, `widgetInteraction`, `configuration`, `accessToken` | no | Same semantics as in types |
160
+
161
+ Optional **`mode`**: `"schema-only"` \| `"schema+samples"` \| `"schema+data"` (hint only). At boundaries, use **`normalizeReplicaTableInput`** / **`normalizeReplicaDocumentInput`** so missing **`rows`** behaves like **`[]`**.
162
+
163
+ ### Tables and rows
164
+
165
+ - **`GristReplicaTable`**: optional `label`, `columns`, `rows`, `rowCount`, `dataOmitted`, etc.
166
+ - Row bodies are **`GristReplicaRow`** (`{ id: number, … }`), **not** columnar `fetchTable` wire format. Use **`buildReplicaDocumentFromDocApi`** or **`decodeColumnarToReplicaRows`** to build rows from `docApi.fetchTable`.
167
+
168
+ ### Building and serializing
169
+
170
+ - Prefer **`buildReplicaDocumentFromDocApi(docApi, { includeRows: false \| "samples" \| "full", sampleRowLimit, source, includeSystemTableData })`**, or **`w.buildReplicaDocumentFromDocApi(...)`** from **`useGrist()`**.
171
+ - **`getDocumentJson` / `buildDocumentJson`** accept **`includeRows`**: `"none"` \| `"samples"` \| `"full"` (plus optional **`sampleRowLimit`**, **`space`**).
172
+
173
+ ### Emulator
174
+
175
+ Only a full **`GristReplicaDocument`** is accepted: **`createGristEmulator({ document })`** and **`parseDocument`**. There is no legacy coercion or alternate “emulator input” type; assemble the object (or load JSON), then **`parseDocument`** if you need validation.
176
+
177
+ The canonical design document for this shape lives at **`apps/docs/design/replica-document.md`**.
178
+ - `grist-widget-sdk/emulator/transports` — low-level `iframe` and `inline` transports if you need to wire your own host.
179
+ - `grist-widget-sdk/emulator/devtools` — `<EmulatorInspector />` React component (table editor + event timeline + options).
180
+ - `grist-widget-sdk/emulator/testing` — `renderWithGrist(...)`, vitest
181
+ matchers (`actionsOf`, `eventsOf`, `waitForEvent`), document `presets`,
182
+ and the most-used `@testing-library/react` primitives (`screen`,
183
+ `fireEvent`, `waitFor`, `act`, `cleanup`, `within`, `render`) so a typical
184
+ test file only needs one import line.
185
+
186
+ ## Emulator (SOTA)
187
+
188
+ The emulator is the single source of truth for three use-cases:
189
+
190
+ 1. **Demoing widgets** — production-fidelity by loading the *real*
191
+ `grist-plugin-api.js` inside an iframe and speaking `grain-rpc` over
192
+ `postMessage`:
193
+
194
+ ```tsx
195
+ import { createGristEmulator, presets } from "grist-widget-sdk/emulator"
196
+ import { EmulatorInspector } from "grist-widget-sdk/emulator/devtools"
197
+
198
+ const iframe = document.querySelector("iframe")!
199
+ const emulator = createGristEmulator({
200
+ document: presets.todoList(),
201
+ transport: { kind: "iframe", iframe },
202
+ })
203
+ ```
204
+
205
+ 2. **Robust SDK testing** — `renderWithGrist` synthesises `window.grist`
206
+ in-process, so every `useGrist` test goes through the *exact* same code
207
+ path without ceremony:
208
+
209
+ ```ts
210
+ import { renderWithGrist } from "grist-widget-sdk/emulator/testing"
211
+
212
+ const { emulator, getByText } = renderWithGrist(<MyWidget />, {
213
+ emulator: { document: presets.contacts() },
214
+ })
215
+ emulator.mutate.addRow("Contacts", { firstName: "Grace", lastName: "Hopper" })
216
+ ```
217
+
218
+ 3. **Live IDE preview** — same `inline` transport, mounted next to the
219
+ widget to give a Storybook-grade dev loop.
220
+
221
+ ## Local Development
222
+
223
+ From the workspace root:
224
+
225
+ ```bash
226
+ pnpm --filter grist-widget-sdk build
227
+ pnpm --filter grist-widget-sdk dev
228
+ pnpm --filter grist-widget-sdk test
229
+ ```
230
+
231
+ ## Pre-Commit / Pre-Publish Checks
232
+
233
+ ```bash
234
+ pnpm --filter grist-widget-sdk build
235
+ pnpm --filter grist-widget-sdk exec tsc --noEmit
236
+ pnpm --filter grist-widget-sdk exec vitest run
237
+ pnpm dlx @arethetypeswrong/cli -P packages/core
238
+ ```
239
+
240
+ If no tests exist yet:
241
+
242
+ ```bash
243
+ pnpm --filter grist-widget-sdk exec vitest run --passWithNoTests
244
+ ```
245
+
246
+ ## Notes
247
+
248
+ - This package targets pure TypeScript/React usage (no Next.js dependency required).
249
+ - ATTW may report a `node10` warning for the `grist-widget-sdk/emulator` subpath. This is expected for modern `exports`-based packages and is non-blocking for Node 16+ and modern bundlers.