@colixsystems/widget-sdk 0.53.0 → 0.54.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/README.md +9 -4
- package/dist/contract.cjs +37 -3
- package/dist/contract.js +37 -3
- package/dist/hooks.js +82 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +1 -0
- package/dist/index.native.js +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ The data layer lives in **four separate domain-client packages**, each instantia
|
|
|
19
19
|
| ----- | ---------------- | ------- | ------------- |
|
|
20
20
|
| **CORE** | `useTheme()` | `{ colors, spacing, radii, typography }` | `ctx.workspace.theme` — no scope |
|
|
21
21
|
| **CORE** | `useWidgetStyle()` | `{ [styleField]: value }` | `ctx.props.style` — no scope. The author-set per-widget style values declared in `manifest.styleSchema`; apply each onto whatever element you choose. |
|
|
22
|
-
| **CORE** | `useUser()` | `{ id, email,
|
|
22
|
+
| **CORE** | `useUser()` | `{ id, email, displayName, roles, groupIds }` | `ctx.user` (host-built context, **camelCase** — not a wire payload; `id` null when anonymous) — no scope |
|
|
23
23
|
| **CORE** | `useNavigation()` | `{ goTo, goBack, push, replace, back, currentRoute }` | `ctx.navigation` — no scope (external URLs use the `Linking` primitive) |
|
|
24
24
|
| **CORE** | `useWidgetEvent(name)` | `(payload?) => void` | `ctx.events.emit` — no scope |
|
|
25
25
|
| **CORE** | `useChildRenderer()` | `{ renderNode(node) }` | `ctx.renderer` — no scope (prefer the `WidgetTree` component) |
|
|
@@ -40,6 +40,7 @@ The data layer lives in **four separate domain-client packages**, each instantia
|
|
|
40
40
|
| **DIRECTORY** | `useUsers(query?)` | `{ users, loading, error, refetch, invite, deactivate, reactivate, remove }` | `directory.users.*` — `users.read:*` (edits also `users.write:*`; `remove()` also `users.delete:*`) |
|
|
41
41
|
| **DIRECTORY** | `useGroups(query?)` | `{ groups, loading, error, refetch, create, remove, addMember, removeMember }` | `directory.groups.*` — `groups.read:*` (mutations also `groups.write:*`) |
|
|
42
42
|
| **DIRECTORY** | `useBankIdLink()` | `{ linked, available, status, qr, message, startLink, refresh, cancel, unlink, refetchStatus, … }` | `directory.bankid.*` — no scope (JWT-gated self-service) |
|
|
43
|
+
| **FILESTORE** (`ctx.filestore`) | `usePdfExport({ spaceType, folderId? })` | `{ exportToPdf, exporting, error, lastExported }` | `ctx.filestore.files.exportPdf` — `files.write:*`. `exportToPdf(html, { fileName?, folderId? })` renders the HTML to a PDF server-side and saves it as a file (`application/pdf`); same server-side renderer on web + native. |
|
|
43
44
|
| **PAYMENTS** (`ctx.payments`) | `usePayments()` | `{ requestPayment, getPayment }` | `ctx.payments.*` — `payments.charge:appUser` |
|
|
44
45
|
| **NOTIFICATIONS** (`ctx.notifications`) | `useSendNotification()` | `{ send, sending, error }` | `ctx.notifications.send` — `notifications.send:appUser`. `send({ recipient_user_id, title, body, link?, payload? })` notifies one app user in the same workspace; call from an event handler (never render); rejects with `NotificationError`. |
|
|
45
46
|
|
|
@@ -51,7 +52,11 @@ See the design reference for the full architecture: [`docs/architecture/widget-m
|
|
|
51
52
|
|
|
52
53
|
## Status
|
|
53
54
|
|
|
54
|
-
`v0.
|
|
55
|
+
`v0.54.0` — pre-publish. The package surface (types, function names, export paths) is the v1 contract; runtime behaviour for some hooks is stubbed (each hook documents what's wired and what isn't). It is **not yet published to npm**.
|
|
56
|
+
|
|
57
|
+
### What's new in 0.54.0
|
|
58
|
+
|
|
59
|
+
**Generate & save PDFs from a widget (sc-2314).** New `usePdfExport({ spaceType, folderId? })` hook. `exportToPdf(html, { fileName?, folderId? })` renders the HTML to a PDF **server-side** (the platform's headless-Chromium pipeline) and saves it into the end-user's Filestore via `ctx.filestore.files.exportPdf`, resolving to the created file row (`application/pdf`). It reuses the filestore owner_id resolution + per-folder write gate and the existing `files.write:*` scope. Because the rendering is server-side, the capability behaves identically on the web Player and the native Expo export — no browser-only PDF library is added to the vetted set. Pairs with `@colixsystems/filestore-client@0.6.0`'s new `files.exportPdf(...)`. `CONTRACT.version` → `1.38.0`. Additive — no existing hook, primitive, manifest field, or token changed shape.
|
|
55
60
|
|
|
56
61
|
### What's new in 0.53.0
|
|
57
62
|
|
|
@@ -278,7 +283,7 @@ Also: `useFileSignatures(fileIds)` is now **self-scoped** (the caller's own sign
|
|
|
278
283
|
|
|
279
284
|
- **The SDK no longer owns any data facade.** The bespoke per-hook facades that used to live on `WidgetContext` (`ctx.datastore` as an opaque host object, `ctx.directory.listUsers`, `ctx.users`, `ctx.groups`, `ctx.recordPermissions`, `ctx.assets.get`) are replaced by four host-instantiated, host-injected domain clients: `ctx.datastore` (`@colixsystems/datastore-client`), `ctx.directory` (`@colixsystems/directory-client`), `ctx.assets` (`@colixsystems/assets-client`, flattened), `ctx.payments` (`@colixsystems/payments-client`). The SDK imports none of them and ships no HTTP.
|
|
280
285
|
- **`ctx.recordPermissions`, `ctx.users`, `ctx.groups` are removed.** Per-record permission management moved under `ctx.datastore.records(tableId).permissions(recordId)`; user / group administration moved under `ctx.directory.users` / `ctx.directory.groups`. The hooks (`useRecordPermissions`, `useUsers`, `useGroups`) keep the same names and signatures — only the client slice they read changed.
|
|
281
|
-
- **snake_case end to end, no client-side transform.** Clients send and return snake_case verbatim (`group_ids`, `can_read`, `is_active`, `amount_cents`, `data_type`, `created_at`, …). The SDK passes bodies straight through and unwraps the `{ data, meta }` list envelope without renaming a single field.
|
|
286
|
+
- **snake_case end to end, no client-side transform.** Clients send and return snake_case verbatim (`group_ids`, `can_read`, `is_active`, `amount_cents`, `data_type`, `created_at`, …). The SDK passes bodies straight through and unwraps the `{ data, meta }` list envelope without renaming a single field. Wire-payload hook return rows are therefore snake_case (`is_active`, `member_count`, and `useRecordPermissions` rows carry `user_id` / `group_id` / `can_read` / `can_write` / `can_delete` / `can_grant`). The one exception is `useUser()`: it reads the host-built `ctx.user` context object, not a wire payload, so its fields are **camelCase** (`displayName`, `groupIds`).
|
|
282
287
|
- **Companion package versions:** `datastore-client 0.5.0`, `assets-client 0.4.0`, `directory-client 0.1.0`, `payments-client 0.1.0`.
|
|
283
288
|
- **`CONTRACT.version` → `1.9.0`.** Breaking for `WidgetContext` consumers (removed slices, renamed wire fields); the hook export surface is unchanged.
|
|
284
289
|
|
|
@@ -423,7 +428,7 @@ import { defineWidget, validateManifest, useDatastoreQuery, Text, View } from "@
|
|
|
423
428
|
|
|
424
429
|
- `defineWidget({ manifest, component })` — validates the manifest and produces a widget module the host can register.
|
|
425
430
|
- `validateManifest(m)` / `validatePropertySchema(s)` / `validateProps(schema, props)` — shape validation; no third-party deps.
|
|
426
|
-
- `useDatastoreQuery`, `useDatastoreRecord`, `useDatastoreSchema`, `useDatastoreMutation`, `useDirectory`, `useUsers`, `useGroups`, `useRecordPermissions`, `useAsset`, `useWidgetEvent`, `usePayments`, `useSendNotification`, `useTheme`, `useI18n`, `useUser`, `useNavigation`, `useChildRenderer`, `useClipboard`, `useToast` — hooks that read from the host-provided `WidgetContext` (or, for `useClipboard`, the platform clipboard API directly). `useDirectory(query?)` returns `{ users, loading, error, refetch }` (each user `{ id, name, role }`) and requires the `directory.read:users` scope. `useUsers(query?)` returns `{ users, loading, error, refetch, invite, deactivate, reactivate, remove }` and requires `users.read:*` (mutations also need `users.write:*`); rejections are a `DirectoryError`. `useGroups(query?)` returns `{ groups, loading, error, refetch, create, remove, addMember, removeMember }` and requires `groups.read:*` (mutations also need `groups.write:*`). `usePayments()` returns `{ requestPayment, getPayment }` and requires the `payments.charge:appUser` scope; `requestPayment(...)` rejects with a `PaymentError`. `useSendNotification()` returns `{ send, sending, error }` and requires the `notifications.send:appUser` scope; `send({ recipient_user_id, title, body, link?, payload? })` notifies one app user in the same workspace (cross-workspace `recipient_user_id` is rejected), must be called from an event handler rather than render, and rejects with a `NotificationError`. `useUser()` returns the active end-user identity `{ id, email,
|
|
431
|
+
- `useDatastoreQuery`, `useDatastoreRecord`, `useDatastoreSchema`, `useDatastoreMutation`, `useDirectory`, `useUsers`, `useGroups`, `useRecordPermissions`, `useAsset`, `useWidgetEvent`, `usePayments`, `useSendNotification`, `useTheme`, `useI18n`, `useUser`, `useNavigation`, `useChildRenderer`, `useClipboard`, `useToast` — hooks that read from the host-provided `WidgetContext` (or, for `useClipboard`, the platform clipboard API directly). `useDirectory(query?)` returns `{ users, loading, error, refetch }` (each user `{ id, name, role }`) and requires the `directory.read:users` scope. `useUsers(query?)` returns `{ users, loading, error, refetch, invite, deactivate, reactivate, remove }` and requires `users.read:*` (mutations also need `users.write:*`); rejections are a `DirectoryError`. `useGroups(query?)` returns `{ groups, loading, error, refetch, create, remove, addMember, removeMember }` and requires `groups.read:*` (mutations also need `groups.write:*`). `usePayments()` returns `{ requestPayment, getPayment }` and requires the `payments.charge:appUser` scope; `requestPayment(...)` rejects with a `PaymentError`. `useSendNotification()` returns `{ send, sending, error }` and requires the `notifications.send:appUser` scope; `send({ recipient_user_id, title, body, link?, payload? })` notifies one app user in the same workspace (cross-workspace `recipient_user_id` is rejected), must be called from an event handler rather than render, and rejects with a `NotificationError`. `useUser()` returns the active end-user identity `{ id, email, displayName, roles, groupIds }` (camelCase — the host-built context object, not a wire payload; `id` is `null` for anonymous / preview). `useNavigation()` returns `{ goTo, goBack, push, replace, back, currentRoute }` for internal page navigation — for external URLs use the `Linking` primitive (`Linking.openURL(url)`). `useDatastoreRecord(tableId, recordId)` returns `{ data, loading, error, refetch }` for a single record (data is one row or null). `useDatastoreSchema(tableId)` returns `{ schema, loading, error, refetch }` where `schema` is `{ id, name, columns: [{ id, name, data_type, required, relation_type, target_table_id, is_identification }] }` (structure only, no row data; snake_case verbatim) — use it to resolve a stored `columnId` to its column type at runtime; requires the `datastore.read:<table>` scope. `useAsset(fileId)` returns `{ url, file, loading, error, refetch }` — the `url` is an absolute URL composed against the host's API base. `useChildRenderer()` returns `{ renderNode(node) }` — container widgets call it to render arbitrary child page-tree nodes (prefer the `WidgetTree` component for the common case).
|
|
427
432
|
- `WidgetTree({ node })` — component that renders an author-authored child node through the host's renderer; used by Tabs / Card / custom containers to host arbitrary child widgets.
|
|
428
433
|
- `Text`, `View`, `Pressable`, `Image`, `ScrollView`, `TextInput`, `FlatList`, `SectionList`, `ActivityIndicator`, `Switch`, `StyleSheet`, `Linking`, `Icon`, `DateTimePicker` — re-exported from `react-native` (the RN primitives) or implemented in the SDK (`Icon` wraps `lucide-react-native`; `DateTimePicker` wraps `@react-native-community/datetimepicker` on native and renders `<input type="date|time|datetime-local">` directly on web because the RN library has no react-native-web mapping). The web build aliases `react-native` to `react-native-web` so the RN-re-exported primitives render in the browser without any per-platform code; the exported Expo app's Metro bundler resolves the real `react-native` library. `Linking` is a static API (`Linking.openURL(url)`) — use it for external URLs, and use `useNavigation().goTo(pageId)` for internal page navigation. See https://reactnative.dev/docs/ for per-component props.
|
|
429
434
|
- `WidgetContextProvider` — React context provider that the host (Studio, Player, exported app) wraps widgets with.
|
package/dist/contract.cjs
CHANGED
|
@@ -235,6 +235,29 @@ const HOOKS = [
|
|
|
235
235
|
requiredContextSlice: ["filestore.files"],
|
|
236
236
|
scopes: ["files.write:*"],
|
|
237
237
|
},
|
|
238
|
+
{
|
|
239
|
+
name: "usePdfExport",
|
|
240
|
+
signature: "usePdfExport({ spaceType, folderId? })",
|
|
241
|
+
description:
|
|
242
|
+
"Render an HTML string to a PDF server-side and SAVE it as a file in " +
|
|
243
|
+
"the end-user's Filestore space. The widget passes the SPACE " +
|
|
244
|
+
"(`{ spaceType, folderId? }`); the hook resolves owner_id from the host " +
|
|
245
|
+
"context and POSTs JSON through ctx.filestore.files.exportPdf. " +
|
|
246
|
+
"`exportToPdf(html, { fileName?, folderId? })` resolves to the created " +
|
|
247
|
+
"file row (mime_type `application/pdf`) or throws the wire error; a 404 " +
|
|
248
|
+
"means the destination folder denied a write, a 413 that the rendered " +
|
|
249
|
+
"PDF exceeded the size cap. The HTML is rendered by the host's PDF " +
|
|
250
|
+
"service (headless Chromium) — the SAME server-side pipeline on the web " +
|
|
251
|
+
"Player and the native export, so no browser-only PDF library is used.",
|
|
252
|
+
returnShape: {
|
|
253
|
+
exportToPdf: "(html, { fileName?, folderId? }) => Promise<FilestoreFile>",
|
|
254
|
+
exporting: "boolean",
|
|
255
|
+
error: "Error | null",
|
|
256
|
+
lastExported: "FilestoreFile | null",
|
|
257
|
+
},
|
|
258
|
+
requiredContextSlice: ["filestore.files"],
|
|
259
|
+
scopes: ["files.write:*"],
|
|
260
|
+
},
|
|
238
261
|
{
|
|
239
262
|
name: "useFilestoreFolders",
|
|
240
263
|
signature: "useFilestoreFolders({ spaceType, parentFolderId?, q?, enabled? })",
|
|
@@ -975,9 +998,9 @@ const WIDGET_CONTEXT_SHAPE = {
|
|
|
975
998
|
},
|
|
976
999
|
user: {
|
|
977
1000
|
description:
|
|
978
|
-
"Signed-in user, host-
|
|
1001
|
+
"Signed-in user, host-built context object (camelCase: { id, email, displayName, roles, groupIds }) — NOT a wire payload, so it is the one camelCase island among the hooks. Not a data-client.",
|
|
979
1002
|
required: true,
|
|
980
|
-
fields: { id: "string", email: "string",
|
|
1003
|
+
fields: { id: "string", email: "string", displayName: "string" },
|
|
981
1004
|
},
|
|
982
1005
|
workspace: {
|
|
983
1006
|
description:
|
|
@@ -1824,7 +1847,18 @@ const CONTRACT = deepFreeze({
|
|
|
1824
1847
|
// the platform host, and an unknown slug / SSRF / timeout throws a
|
|
1825
1848
|
// catchable Error. New entry in ACTION_SCRIPT_GLOBALS only — no widget
|
|
1826
1849
|
// hook, primitive, manifest field, or token changed shape; minor bump.
|
|
1827
|
-
|
|
1850
|
+
//
|
|
1851
|
+
// 1.38.0: additive (sc-2314) — new `usePdfExport({ spaceType, folderId? })`
|
|
1852
|
+
// hook. `exportToPdf(html, { fileName?, folderId? })` renders the HTML to
|
|
1853
|
+
// a PDF server-side (the host's headless-Chromium pipeline) and SAVES it
|
|
1854
|
+
// into the Filestore via `ctx.filestore.files.exportPdf`, resolving to the
|
|
1855
|
+
// created file row (`application/pdf`). Reuses the filestore owner_id
|
|
1856
|
+
// resolution + per-folder write gate; gated on the existing
|
|
1857
|
+
// `files.write:*` scope. The same server-side renderer backs the web
|
|
1858
|
+
// Player and the native export, so no browser-only PDF library is added
|
|
1859
|
+
// to the vetted set. No existing hook, primitive, manifest field, or
|
|
1860
|
+
// token changed shape — minor bump.
|
|
1861
|
+
version: "1.38.0",
|
|
1828
1862
|
sharedTranslationKeys: SHARED_TRANSLATION_KEYS,
|
|
1829
1863
|
hooks: HOOKS,
|
|
1830
1864
|
primitives: PRIMITIVES,
|
package/dist/contract.js
CHANGED
|
@@ -235,6 +235,29 @@ const HOOKS = [
|
|
|
235
235
|
requiredContextSlice: ["filestore.files"],
|
|
236
236
|
scopes: ["files.write:*"],
|
|
237
237
|
},
|
|
238
|
+
{
|
|
239
|
+
name: "usePdfExport",
|
|
240
|
+
signature: "usePdfExport({ spaceType, folderId? })",
|
|
241
|
+
description:
|
|
242
|
+
"Render an HTML string to a PDF server-side and SAVE it as a file in " +
|
|
243
|
+
"the end-user's Filestore space. The widget passes the SPACE " +
|
|
244
|
+
"(`{ spaceType, folderId? }`); the hook resolves owner_id from the host " +
|
|
245
|
+
"context and POSTs JSON through ctx.filestore.files.exportPdf. " +
|
|
246
|
+
"`exportToPdf(html, { fileName?, folderId? })` resolves to the created " +
|
|
247
|
+
"file row (mime_type `application/pdf`) or throws the wire error; a 404 " +
|
|
248
|
+
"means the destination folder denied a write, a 413 that the rendered " +
|
|
249
|
+
"PDF exceeded the size cap. The HTML is rendered by the host's PDF " +
|
|
250
|
+
"service (headless Chromium) — the SAME server-side pipeline on the web " +
|
|
251
|
+
"Player and the native export, so no browser-only PDF library is used.",
|
|
252
|
+
returnShape: {
|
|
253
|
+
exportToPdf: "(html, { fileName?, folderId? }) => Promise<FilestoreFile>",
|
|
254
|
+
exporting: "boolean",
|
|
255
|
+
error: "Error | null",
|
|
256
|
+
lastExported: "FilestoreFile | null",
|
|
257
|
+
},
|
|
258
|
+
requiredContextSlice: ["filestore.files"],
|
|
259
|
+
scopes: ["files.write:*"],
|
|
260
|
+
},
|
|
238
261
|
{
|
|
239
262
|
name: "useFilestoreFolders",
|
|
240
263
|
signature: "useFilestoreFolders({ spaceType, parentFolderId?, q?, enabled? })",
|
|
@@ -975,9 +998,9 @@ const WIDGET_CONTEXT_SHAPE = {
|
|
|
975
998
|
},
|
|
976
999
|
user: {
|
|
977
1000
|
description:
|
|
978
|
-
"Signed-in user, host-
|
|
1001
|
+
"Signed-in user, host-built context object (camelCase: { id, email, displayName, roles, groupIds }) — NOT a wire payload, so it is the one camelCase island among the hooks. Not a data-client.",
|
|
979
1002
|
required: true,
|
|
980
|
-
fields: { id: "string", email: "string",
|
|
1003
|
+
fields: { id: "string", email: "string", displayName: "string" },
|
|
981
1004
|
},
|
|
982
1005
|
workspace: {
|
|
983
1006
|
description:
|
|
@@ -1824,7 +1847,18 @@ const CONTRACT = deepFreeze({
|
|
|
1824
1847
|
// the platform host, and an unknown slug / SSRF / timeout throws a
|
|
1825
1848
|
// catchable Error. New entry in ACTION_SCRIPT_GLOBALS only — no widget
|
|
1826
1849
|
// hook, primitive, manifest field, or token changed shape; minor bump.
|
|
1827
|
-
|
|
1850
|
+
//
|
|
1851
|
+
// 1.38.0: additive (sc-2314) — new `usePdfExport({ spaceType, folderId? })`
|
|
1852
|
+
// hook. `exportToPdf(html, { fileName?, folderId? })` renders the HTML to
|
|
1853
|
+
// a PDF server-side (the host's headless-Chromium pipeline) and SAVES it
|
|
1854
|
+
// into the Filestore via `ctx.filestore.files.exportPdf`, resolving to the
|
|
1855
|
+
// created file row (`application/pdf`). Reuses the filestore owner_id
|
|
1856
|
+
// resolution + per-folder write gate; gated on the existing
|
|
1857
|
+
// `files.write:*` scope. The same server-side renderer backs the web
|
|
1858
|
+
// Player and the native export, so no browser-only PDF library is added
|
|
1859
|
+
// to the vetted set. No existing hook, primitive, manifest field, or
|
|
1860
|
+
// token changed shape — minor bump.
|
|
1861
|
+
version: "1.38.0",
|
|
1828
1862
|
sharedTranslationKeys: SHARED_TRANSLATION_KEYS,
|
|
1829
1863
|
hooks: HOOKS,
|
|
1830
1864
|
primitives: PRIMITIVES,
|
package/dist/hooks.js
CHANGED
|
@@ -113,7 +113,7 @@ export function useWidgetStyle() {
|
|
|
113
113
|
|
|
114
114
|
/**
|
|
115
115
|
* Returns the active end-user identity VERBATIM from the host, e.g.
|
|
116
|
-
* `{ id, email,
|
|
116
|
+
* `{ id, email, displayName, roles, groupIds }` (camelCase — host-built context, not a wire payload).
|
|
117
117
|
*
|
|
118
118
|
* `id` is `null` for anonymous visitors (and on the Studio canvas preview,
|
|
119
119
|
* which renders widgets as if signed-out so the public branch shows). The
|
|
@@ -1578,6 +1578,87 @@ export function useFilestoreUpload(options) {
|
|
|
1578
1578
|
return { upload, uploading, error, lastUploaded };
|
|
1579
1579
|
}
|
|
1580
1580
|
|
|
1581
|
+
/**
|
|
1582
|
+
* sc-2314 — render an HTML string to a PDF server-side and SAVE it into the
|
|
1583
|
+
* end-user's Filestore space. Returns `{ exportToPdf, exporting, error,
|
|
1584
|
+
* lastExported }`. The widget passes the SPACE (`{ spaceType, folderId? }`);
|
|
1585
|
+
* the hook resolves `owner_id` the same way the upload hook does (tenant for
|
|
1586
|
+
* PROJECT, app user for PERSONAL) and posts JSON to
|
|
1587
|
+
* `ctx.filestore.files.exportPdf`.
|
|
1588
|
+
*
|
|
1589
|
+
* `exportToPdf(html, { fileName?, folderId? })` resolves to the created file
|
|
1590
|
+
* record (`{ id, name, mime_type: "application/pdf", presigned_url, … }`).
|
|
1591
|
+
* `fileName` defaults to `document.pdf` and is forced to a `.pdf` suffix by the
|
|
1592
|
+
* backend. The HTML is rendered by the host's PDF service (headless Chromium)
|
|
1593
|
+
* — the SAME server-side pipeline backs the web Player and the native export,
|
|
1594
|
+
* so the capability behaves identically on both platforms (no browser-only PDF
|
|
1595
|
+
* library is involved).
|
|
1596
|
+
*
|
|
1597
|
+
* A 404 means the destination folder denied a write; a 413 means the rendered
|
|
1598
|
+
* PDF exceeded the size cap.
|
|
1599
|
+
*/
|
|
1600
|
+
export function usePdfExport(options) {
|
|
1601
|
+
const ctx = useWidgetContextOrThrow("usePdfExport");
|
|
1602
|
+
if (
|
|
1603
|
+
!ctx.filestore ||
|
|
1604
|
+
!ctx.filestore.files ||
|
|
1605
|
+
typeof ctx.filestore.files.exportPdf !== "function"
|
|
1606
|
+
) {
|
|
1607
|
+
throw new Error(
|
|
1608
|
+
"usePdfExport: host did not inject a filestore client (ctx.filestore.files.exportPdf)",
|
|
1609
|
+
);
|
|
1610
|
+
}
|
|
1611
|
+
const { spaceType = "project", folderId: defaultFolderId = null } = options || {};
|
|
1612
|
+
const ownerId = _filestoreOwnerId(ctx, spaceType);
|
|
1613
|
+
|
|
1614
|
+
const [exporting, setExporting] = useState(false);
|
|
1615
|
+
const [error, setError] = useState(null);
|
|
1616
|
+
const [lastExported, setLastExported] = useState(null);
|
|
1617
|
+
|
|
1618
|
+
const filesRef = useRef(ctx.filestore.files);
|
|
1619
|
+
filesRef.current = ctx.filestore.files;
|
|
1620
|
+
|
|
1621
|
+
const exportToPdf = useCallback(
|
|
1622
|
+
async (html, overrides) => {
|
|
1623
|
+
if (typeof html !== "string" || html.trim().length === 0) {
|
|
1624
|
+
throw new Error("usePdfExport: html is required");
|
|
1625
|
+
}
|
|
1626
|
+
if (!ownerId) {
|
|
1627
|
+
const err = new Error("Sign in to save a PDF");
|
|
1628
|
+
setError(err);
|
|
1629
|
+
throw err;
|
|
1630
|
+
}
|
|
1631
|
+
const folderId =
|
|
1632
|
+
overrides && Object.prototype.hasOwnProperty.call(overrides, "folderId")
|
|
1633
|
+
? overrides.folderId
|
|
1634
|
+
: defaultFolderId;
|
|
1635
|
+
const fileName = overrides && overrides.fileName;
|
|
1636
|
+
const body = {
|
|
1637
|
+
html,
|
|
1638
|
+
space_type: String(spaceType || "project").toUpperCase(),
|
|
1639
|
+
owner_id: ownerId,
|
|
1640
|
+
};
|
|
1641
|
+
if (folderId) body.folder_id = folderId;
|
|
1642
|
+
if (fileName) body.file_name = fileName;
|
|
1643
|
+
setExporting(true);
|
|
1644
|
+
setError(null);
|
|
1645
|
+
try {
|
|
1646
|
+
const created = await filesRef.current.exportPdf(body);
|
|
1647
|
+
setLastExported(created || null);
|
|
1648
|
+
setExporting(false);
|
|
1649
|
+
return created;
|
|
1650
|
+
} catch (err) {
|
|
1651
|
+
setError(err);
|
|
1652
|
+
setExporting(false);
|
|
1653
|
+
throw err;
|
|
1654
|
+
}
|
|
1655
|
+
},
|
|
1656
|
+
[ownerId, defaultFolderId, spaceType],
|
|
1657
|
+
);
|
|
1658
|
+
|
|
1659
|
+
return { exportToPdf, exporting, error, lastExported };
|
|
1660
|
+
}
|
|
1661
|
+
|
|
1581
1662
|
/**
|
|
1582
1663
|
* Browse the end-user's Filestore folders. Returns { folders, loading, error,
|
|
1583
1664
|
* refetch }. Mirrors useFilestoreFiles for subfolder navigation: the widget
|
package/dist/index.d.ts
CHANGED
|
@@ -424,13 +424,13 @@ export interface WidgetContext<TProps = unknown> {
|
|
|
424
424
|
* Absent / `false` everywhere the host has not opted the widget into filling.
|
|
425
425
|
*/
|
|
426
426
|
fill?: boolean;
|
|
427
|
-
/** Active end-user identity,
|
|
427
|
+
/** Active end-user identity from the host-built context (camelCase, not a wire payload). `id` is null when anonymous. */
|
|
428
428
|
user: {
|
|
429
429
|
id: string | null;
|
|
430
430
|
email: string | null;
|
|
431
|
-
|
|
431
|
+
displayName: string | null;
|
|
432
432
|
roles: string[];
|
|
433
|
-
|
|
433
|
+
groupIds: string[];
|
|
434
434
|
};
|
|
435
435
|
workspace: {
|
|
436
436
|
id: string;
|
|
@@ -883,9 +883,9 @@ export function useI18n(): {
|
|
|
883
883
|
export function useUser(): {
|
|
884
884
|
id: string | null;
|
|
885
885
|
email: string | null;
|
|
886
|
-
|
|
886
|
+
displayName: string | null;
|
|
887
887
|
roles: string[];
|
|
888
|
-
|
|
888
|
+
groupIds: string[];
|
|
889
889
|
};
|
|
890
890
|
|
|
891
891
|
/**
|
package/dist/index.js
CHANGED
package/dist/index.native.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@colixsystems/widget-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.54.0",
|
|
4
4
|
"description": "Common widget interface for AppStudio. Implements WidgetManifest, WidgetContext, property schema, and helper hooks.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|