@colixsystems/widget-sdk 0.10.0 → 0.12.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 +12 -2
- package/dist/contract.cjs +52 -0
- package/dist/contract.js +52 -0
- package/dist/hooks.js +165 -0
- package/dist/index.d.ts +60 -0
- package/dist/index.js +4 -0
- package/dist/index.native.js +4 -0
- package/dist/primitives.js +5 -0
- package/dist/primitives.native.js +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,7 +6,17 @@ See the design reference for the full architecture: [`docs/architecture/widget-m
|
|
|
6
6
|
|
|
7
7
|
## Status
|
|
8
8
|
|
|
9
|
-
`v0.
|
|
9
|
+
`v0.12.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**.
|
|
10
|
+
|
|
11
|
+
### What's new in 0.12.0
|
|
12
|
+
|
|
13
|
+
- **`useDatastoreRecord(tableId, recordId)` is wired.** Returns `{ data, loading, error, refetch }` for a single record fetched through the host's `records(table).get(id)`. Sister to `useDatastoreQuery`; mirrors its ref discipline so `refetch` stays a stable callback identity. A 404 surfaces as `DatastoreError.code === "NOT_FOUND"`. Additive.
|
|
14
|
+
- **`useFile(fileId)` is wired** + new `WidgetContext.files` slice. Returns `{ url, file, loading, error, refetch }` — the `url` is an absolute URL the widget can drop straight into `<Image source>`. Backed by a new `files.get(fileId)` host facade (web: `widgetHostFiles` through `api/client`; native: `hostFiles` in the export's `widgetHost.js`). Additive.
|
|
15
|
+
|
|
16
|
+
### What's new in 0.11.0
|
|
17
|
+
|
|
18
|
+
- **`useNavigation()` is wired.** Returns the host-provided navigation surface `{ goTo, goBack, push, replace, back, currentRoute }` for internal page-to-page navigation. Missing methods degrade to no-ops on the Studio canvas preview. Additive.
|
|
19
|
+
- **`Linking` primitive re-exported.** `Linking.openURL(url)` opens an external URL with the OS handler — web (`react-native-web`) maps to `window.open` / `location.href`; native hands off to the system. Use this for external URLs; use `useNavigation().goTo(pageId)` for internal pages.
|
|
10
20
|
|
|
11
21
|
### What's new in 0.10.0
|
|
12
22
|
|
|
@@ -75,7 +85,7 @@ import { defineWidget, validateManifest, useDatastoreQuery, Text, View } from "@
|
|
|
75
85
|
|
|
76
86
|
- `defineWidget({ manifest, component })` — validates the manifest and produces a widget module the host can register.
|
|
77
87
|
- `validateManifest(m)` / `validatePropertySchema(s)` / `validateProps(schema, props)` — shape validation; no third-party deps.
|
|
78
|
-
- `useDatastoreQuery`, `useDatastoreMutation`, `useDirectory`, `useWidgetEvent`, `usePayments`, `useTheme`, `useI18n`, `useUser` — hooks that read from the host-provided `WidgetContext`. `useDirectory(query?)` returns `{ users, loading, error, refetch }` (each user `{ id, name, role }`) and requires the `directory.read:users` scope. `usePayments()` returns `{ requestPayment, getPayment }` and requires the `payments.charge:appUser` scope; `requestPayment(...)` rejects with a `PaymentError`. `useUser()` returns the active end-user identity `{ id, email, displayName, roles, groupIds }` (`id` is `null` for anonymous / preview).
|
|
88
|
+
- `useDatastoreQuery`, `useDatastoreRecord`, `useDatastoreMutation`, `useDirectory`, `useFile`, `useWidgetEvent`, `usePayments`, `useTheme`, `useI18n`, `useUser`, `useNavigation` — hooks that read from the host-provided `WidgetContext`. `useDirectory(query?)` returns `{ users, loading, error, refetch }` (each user `{ id, name, role }`) and requires the `directory.read:users` scope. `usePayments()` returns `{ requestPayment, getPayment }` and requires the `payments.charge:appUser` scope; `requestPayment(...)` rejects with a `PaymentError`. `useUser()` returns the active end-user identity `{ id, email, displayName, roles, groupIds }` (`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). `useFile(fileId)` returns `{ url, file, loading, error, refetch }` — the `url` is an absolute URL composed against the host's API base.
|
|
79
89
|
- `Text`, `View`, `Pressable`, `Image`, `ScrollView`, `TextInput`, `FlatList`, `SectionList`, `ActivityIndicator`, `Switch`, `StyleSheet` — re-exported from `react-native`. The web build aliases `react-native` to `react-native-web` so widgets render in the browser without any per-platform code; the exported Expo app's Metro bundler resolves the real `react-native` library. See https://reactnative.dev/docs/ for per-component props.
|
|
80
90
|
- `WidgetContextProvider` — React context provider that the host (Studio, Player, exported app) wraps widgets with.
|
|
81
91
|
|
package/dist/contract.cjs
CHANGED
|
@@ -68,6 +68,45 @@ const HOOKS = [
|
|
|
68
68
|
requiredContextSlice: ["user"],
|
|
69
69
|
scopes: null,
|
|
70
70
|
},
|
|
71
|
+
{
|
|
72
|
+
name: "useNavigation",
|
|
73
|
+
signature: "useNavigation()",
|
|
74
|
+
returnShape: {
|
|
75
|
+
goTo: "(pageId: string, params?: object) => void",
|
|
76
|
+
goBack: "() => void",
|
|
77
|
+
push: "(pageId: string, params?: object) => void",
|
|
78
|
+
replace: "(pageId: string, params?: object) => void",
|
|
79
|
+
back: "() => void",
|
|
80
|
+
currentRoute: "{ pageId: string, params: object }",
|
|
81
|
+
},
|
|
82
|
+
requiredContextSlice: ["navigation"],
|
|
83
|
+
scopes: null,
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: "useDatastoreRecord",
|
|
87
|
+
signature: "useDatastoreRecord(tableId, recordId)",
|
|
88
|
+
returnShape: {
|
|
89
|
+
data: "Record | null",
|
|
90
|
+
loading: "boolean",
|
|
91
|
+
error: "DatastoreError | null",
|
|
92
|
+
refetch: "() => Promise<void>",
|
|
93
|
+
},
|
|
94
|
+
requiredContextSlice: ["datastore.records"],
|
|
95
|
+
scopes: ["datastore.read:<table>"],
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: "useFile",
|
|
99
|
+
signature: "useFile(fileId)",
|
|
100
|
+
returnShape: {
|
|
101
|
+
url: "string | null",
|
|
102
|
+
file: "{ id, url, storedFilename, mimeType, sizeBytes, ... } | null",
|
|
103
|
+
loading: "boolean",
|
|
104
|
+
error: "DatastoreError | null",
|
|
105
|
+
refetch: "() => Promise<void>",
|
|
106
|
+
},
|
|
107
|
+
requiredContextSlice: ["files.get"],
|
|
108
|
+
scopes: null,
|
|
109
|
+
},
|
|
71
110
|
{
|
|
72
111
|
name: "useDatastoreQuery",
|
|
73
112
|
signature: "useDatastoreQuery(tableId, options?)",
|
|
@@ -209,6 +248,13 @@ const PRIMITIVES = [
|
|
|
209
248
|
rnComponent: "StyleSheet",
|
|
210
249
|
docsUrl: "https://reactnative.dev/docs/stylesheet",
|
|
211
250
|
},
|
|
251
|
+
{
|
|
252
|
+
name: "Linking",
|
|
253
|
+
description:
|
|
254
|
+
"Static API for external links. `Linking.openURL(url)` opens a URL with the OS handler (web: window.open / location.href via react-native-web). `canOpenURL` reports whether the scheme is registered. See https://reactnative.dev/docs/linking.",
|
|
255
|
+
rnComponent: "Linking",
|
|
256
|
+
docsUrl: "https://reactnative.dev/docs/linking",
|
|
257
|
+
},
|
|
212
258
|
];
|
|
213
259
|
|
|
214
260
|
const CATEGORIES = [
|
|
@@ -355,6 +401,12 @@ const WIDGET_CONTEXT_SHAPE = {
|
|
|
355
401
|
required: true,
|
|
356
402
|
fields: { listUsers: "function" },
|
|
357
403
|
},
|
|
404
|
+
files: {
|
|
405
|
+
description:
|
|
406
|
+
"Read-only asset resolver. { get(fileId) -> Promise<{ id, url, storedFilename, mimeType, sizeBytes, ... }> }. Backs useFile(); resolves an asset id to an absolute URL the widget can drop into an <Image source>. The url field is always an absolute URL composed against the host's API base.",
|
|
407
|
+
required: true,
|
|
408
|
+
fields: { get: "function" },
|
|
409
|
+
},
|
|
358
410
|
events: {
|
|
359
411
|
description: "{ emit(name, payload) }.",
|
|
360
412
|
required: true,
|
package/dist/contract.js
CHANGED
|
@@ -68,6 +68,45 @@ const HOOKS = [
|
|
|
68
68
|
requiredContextSlice: ["user"],
|
|
69
69
|
scopes: null,
|
|
70
70
|
},
|
|
71
|
+
{
|
|
72
|
+
name: "useNavigation",
|
|
73
|
+
signature: "useNavigation()",
|
|
74
|
+
returnShape: {
|
|
75
|
+
goTo: "(pageId: string, params?: object) => void",
|
|
76
|
+
goBack: "() => void",
|
|
77
|
+
push: "(pageId: string, params?: object) => void",
|
|
78
|
+
replace: "(pageId: string, params?: object) => void",
|
|
79
|
+
back: "() => void",
|
|
80
|
+
currentRoute: "{ pageId: string, params: object }",
|
|
81
|
+
},
|
|
82
|
+
requiredContextSlice: ["navigation"],
|
|
83
|
+
scopes: null,
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: "useDatastoreRecord",
|
|
87
|
+
signature: "useDatastoreRecord(tableId, recordId)",
|
|
88
|
+
returnShape: {
|
|
89
|
+
data: "Record | null",
|
|
90
|
+
loading: "boolean",
|
|
91
|
+
error: "DatastoreError | null",
|
|
92
|
+
refetch: "() => Promise<void>",
|
|
93
|
+
},
|
|
94
|
+
requiredContextSlice: ["datastore.records"],
|
|
95
|
+
scopes: ["datastore.read:<table>"],
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: "useFile",
|
|
99
|
+
signature: "useFile(fileId)",
|
|
100
|
+
returnShape: {
|
|
101
|
+
url: "string | null",
|
|
102
|
+
file: "{ id, url, storedFilename, mimeType, sizeBytes, ... } | null",
|
|
103
|
+
loading: "boolean",
|
|
104
|
+
error: "DatastoreError | null",
|
|
105
|
+
refetch: "() => Promise<void>",
|
|
106
|
+
},
|
|
107
|
+
requiredContextSlice: ["files.get"],
|
|
108
|
+
scopes: null,
|
|
109
|
+
},
|
|
71
110
|
{
|
|
72
111
|
name: "useDatastoreQuery",
|
|
73
112
|
signature: "useDatastoreQuery(tableId, options?)",
|
|
@@ -204,6 +243,13 @@ const PRIMITIVES = [
|
|
|
204
243
|
rnComponent: "StyleSheet",
|
|
205
244
|
docsUrl: "https://reactnative.dev/docs/stylesheet",
|
|
206
245
|
},
|
|
246
|
+
{
|
|
247
|
+
name: "Linking",
|
|
248
|
+
description:
|
|
249
|
+
"Static API for external links. `Linking.openURL(url)` opens a URL with the OS handler (web: window.open / location.href via react-native-web). `canOpenURL` reports whether the scheme is registered. See https://reactnative.dev/docs/linking.",
|
|
250
|
+
rnComponent: "Linking",
|
|
251
|
+
docsUrl: "https://reactnative.dev/docs/linking",
|
|
252
|
+
},
|
|
207
253
|
];
|
|
208
254
|
|
|
209
255
|
const CATEGORIES = [
|
|
@@ -349,6 +395,12 @@ const WIDGET_CONTEXT_SHAPE = {
|
|
|
349
395
|
required: true,
|
|
350
396
|
fields: { listUsers: "function" },
|
|
351
397
|
},
|
|
398
|
+
files: {
|
|
399
|
+
description:
|
|
400
|
+
"Read-only asset resolver. { get(fileId) -> Promise<{ id, url, storedFilename, mimeType, sizeBytes, ... }> }. Backs useFile(); resolves an asset id to an absolute URL the widget can drop into an <Image source>. The url field is always an absolute URL composed against the host's API base.",
|
|
401
|
+
required: true,
|
|
402
|
+
fields: { get: "function" },
|
|
403
|
+
},
|
|
352
404
|
events: {
|
|
353
405
|
description: "{ emit(name, payload) }.",
|
|
354
406
|
required: true,
|
package/dist/hooks.js
CHANGED
|
@@ -219,6 +219,153 @@ export function useDatastoreQuery(table, query) {
|
|
|
219
219
|
return { data, loading, error, refetch };
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
+
/**
|
|
223
|
+
* Stateful single-record query hook. Returns { data, loading, error, refetch }
|
|
224
|
+
* where `data` is one row (`null` until loaded, never an array).
|
|
225
|
+
*
|
|
226
|
+
* The host's datastore client exposes `records(table).get(id)` which
|
|
227
|
+
* resolves to a single record object. We hold the result in component
|
|
228
|
+
* state and re-fetch when [table, id] changes. `refetch` re-runs the
|
|
229
|
+
* call on demand.
|
|
230
|
+
*
|
|
231
|
+
* When `table` OR `recordId` is falsy (e.g. the author hasn't bound the
|
|
232
|
+
* record id yet), the hook resolves to { data: null, loading: false,
|
|
233
|
+
* error: null, refetch } so the widget can render its empty state
|
|
234
|
+
* without throwing. A 404 surfaces as a DatastoreError with
|
|
235
|
+
* `code: "NOT_FOUND"`.
|
|
236
|
+
*/
|
|
237
|
+
export function useDatastoreRecord(table, recordId) {
|
|
238
|
+
const ctx = useWidgetContextOrThrow("useDatastoreRecord");
|
|
239
|
+
if (!ctx.datastore || typeof ctx.datastore.records !== "function") {
|
|
240
|
+
throw new Error(
|
|
241
|
+
"useDatastoreRecord: host did not inject a datastore client",
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
const ready = Boolean(table && recordId);
|
|
245
|
+
const [data, setData] = useState(null);
|
|
246
|
+
const [loading, setLoading] = useState(ready);
|
|
247
|
+
const [error, setError] = useState(null);
|
|
248
|
+
|
|
249
|
+
// Same ref discipline as useDatastoreQuery — `ctx` is a fresh object
|
|
250
|
+
// identity on every host render, so we hold the live inputs in refs
|
|
251
|
+
// to keep `refetch` a stable callback.
|
|
252
|
+
const tableRef = useRef(table);
|
|
253
|
+
const recordIdRef = useRef(recordId);
|
|
254
|
+
const recordsRef = useRef(ctx.datastore.records);
|
|
255
|
+
tableRef.current = table;
|
|
256
|
+
recordIdRef.current = recordId;
|
|
257
|
+
recordsRef.current = ctx.datastore.records;
|
|
258
|
+
|
|
259
|
+
const runRef = useRef(0);
|
|
260
|
+
|
|
261
|
+
const doFetch = useCallback(async () => {
|
|
262
|
+
const myRun = ++runRef.current;
|
|
263
|
+
const t = tableRef.current;
|
|
264
|
+
const id = recordIdRef.current;
|
|
265
|
+
if (!t || !id) {
|
|
266
|
+
setLoading(false);
|
|
267
|
+
setError(null);
|
|
268
|
+
setData(null);
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
setLoading(true);
|
|
272
|
+
setError(null);
|
|
273
|
+
try {
|
|
274
|
+
const ns = recordsRef.current(t);
|
|
275
|
+
const row = await ns.get(id);
|
|
276
|
+
if (runRef.current !== myRun) return;
|
|
277
|
+
setData(row || null);
|
|
278
|
+
setLoading(false);
|
|
279
|
+
} catch (err) {
|
|
280
|
+
if (runRef.current !== myRun) return;
|
|
281
|
+
setError(toDatastoreError(err));
|
|
282
|
+
setLoading(false);
|
|
283
|
+
}
|
|
284
|
+
}, []);
|
|
285
|
+
|
|
286
|
+
useEffect(() => {
|
|
287
|
+
doFetch();
|
|
288
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
289
|
+
}, [table, recordId]);
|
|
290
|
+
|
|
291
|
+
const refetch = useCallback(async () => {
|
|
292
|
+
await doFetch();
|
|
293
|
+
}, [doFetch]);
|
|
294
|
+
|
|
295
|
+
return { data, loading, error, refetch };
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Stateful file-asset resolver hook. Returns { url, file, loading, error,
|
|
300
|
+
* refetch }.
|
|
301
|
+
*
|
|
302
|
+
* The host's file client exposes `files.get(fileId)` which resolves to
|
|
303
|
+
* `{ url, ...meta }` — the absolute URL is composed against the host's
|
|
304
|
+
* API base so the widget can drop it straight into an `<Image source>`
|
|
305
|
+
* without knowing where the API lives. A missing/soft-deleted asset
|
|
306
|
+
* surfaces as `{ url: null, error: <DatastoreError NOT_FOUND> }`.
|
|
307
|
+
*
|
|
308
|
+
* When `fileId` is falsy the hook collapses to { url: null, file: null,
|
|
309
|
+
* loading: false, error: null, refetch } without a network round-trip,
|
|
310
|
+
* so a widget rendering before the author has bound an asset stays
|
|
311
|
+
* loop-free.
|
|
312
|
+
*/
|
|
313
|
+
export function useFile(fileId) {
|
|
314
|
+
const ctx = useWidgetContextOrThrow("useFile");
|
|
315
|
+
if (!ctx.files || typeof ctx.files.get !== "function") {
|
|
316
|
+
throw new Error("useFile: host did not inject a files client");
|
|
317
|
+
}
|
|
318
|
+
const ready = Boolean(fileId);
|
|
319
|
+
const [file, setFile] = useState(null);
|
|
320
|
+
const [loading, setLoading] = useState(ready);
|
|
321
|
+
const [error, setError] = useState(null);
|
|
322
|
+
|
|
323
|
+
const fileIdRef = useRef(fileId);
|
|
324
|
+
const getRef = useRef(ctx.files.get);
|
|
325
|
+
fileIdRef.current = fileId;
|
|
326
|
+
getRef.current = ctx.files.get;
|
|
327
|
+
|
|
328
|
+
const runRef = useRef(0);
|
|
329
|
+
|
|
330
|
+
const doFetch = useCallback(async () => {
|
|
331
|
+
const myRun = ++runRef.current;
|
|
332
|
+
const id = fileIdRef.current;
|
|
333
|
+
if (!id) {
|
|
334
|
+
setLoading(false);
|
|
335
|
+
setError(null);
|
|
336
|
+
setFile(null);
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
setLoading(true);
|
|
340
|
+
setError(null);
|
|
341
|
+
try {
|
|
342
|
+
const f = await getRef.current(id);
|
|
343
|
+
if (runRef.current !== myRun) return;
|
|
344
|
+
setFile(f || null);
|
|
345
|
+
setLoading(false);
|
|
346
|
+
} catch (err) {
|
|
347
|
+
if (runRef.current !== myRun) return;
|
|
348
|
+
setError(toDatastoreError(err));
|
|
349
|
+
setLoading(false);
|
|
350
|
+
}
|
|
351
|
+
}, []);
|
|
352
|
+
|
|
353
|
+
useEffect(() => {
|
|
354
|
+
doFetch();
|
|
355
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
356
|
+
}, [fileId]);
|
|
357
|
+
|
|
358
|
+
const refetch = useCallback(async () => {
|
|
359
|
+
await doFetch();
|
|
360
|
+
}, [doFetch]);
|
|
361
|
+
|
|
362
|
+
const url =
|
|
363
|
+
file && typeof file.url === "string" && file.url.length > 0
|
|
364
|
+
? file.url
|
|
365
|
+
: null;
|
|
366
|
+
return { url, file, loading, error, refetch };
|
|
367
|
+
}
|
|
368
|
+
|
|
222
369
|
/**
|
|
223
370
|
* Datastore mutation hook. Returns { create, update, delete }, each method
|
|
224
371
|
* returning a Promise. Rejected promises throw a DatastoreError carrying a
|
|
@@ -370,6 +517,24 @@ export function useUser() {
|
|
|
370
517
|
return ctx.user;
|
|
371
518
|
}
|
|
372
519
|
|
|
520
|
+
/**
|
|
521
|
+
* Returns the host-provided navigation surface:
|
|
522
|
+
* `{ goTo, goBack, push, replace, back, currentRoute }`.
|
|
523
|
+
*
|
|
524
|
+
* `goTo(pageId, params?)` navigates to an internal app page. `goBack()`
|
|
525
|
+
* pops the stack. `push` / `replace` / `back` are aliases that map to
|
|
526
|
+
* the platform's native navigator (react-router on web, react-navigation
|
|
527
|
+
* on native). Missing methods degrade to no-ops on the Studio canvas
|
|
528
|
+
* preview, where there is no live router.
|
|
529
|
+
*
|
|
530
|
+
* For EXTERNAL URLs use the `Linking` primitive — `Linking.openURL(url)`
|
|
531
|
+
* works on both platforms.
|
|
532
|
+
*/
|
|
533
|
+
export function useNavigation() {
|
|
534
|
+
const ctx = useWidgetContextOrThrow("useNavigation");
|
|
535
|
+
return ctx.navigation;
|
|
536
|
+
}
|
|
537
|
+
|
|
373
538
|
/**
|
|
374
539
|
* Structured error thrown by `usePayments` callbacks. Carries a stable
|
|
375
540
|
* `code` so widgets can branch without parsing message strings.
|
package/dist/index.d.ts
CHANGED
|
@@ -363,6 +363,40 @@ export function usePayments(): PaymentsApi;
|
|
|
363
363
|
|
|
364
364
|
export function useTheme(): ThemeTokens;
|
|
365
365
|
|
|
366
|
+
/**
|
|
367
|
+
* Stateful single-record fetch hook. Returns `{ data, loading, error,
|
|
368
|
+
* refetch }`. `data` is one row or `null` (never an array).
|
|
369
|
+
*/
|
|
370
|
+
export function useDatastoreRecord(
|
|
371
|
+
tableId: string | null | undefined,
|
|
372
|
+
recordId: string | null | undefined,
|
|
373
|
+
): {
|
|
374
|
+
data: unknown | null;
|
|
375
|
+
loading: boolean;
|
|
376
|
+
error: DatastoreError | null;
|
|
377
|
+
refetch(): Promise<void>;
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Stateful file-asset resolver hook. Returns `{ url, file, loading, error,
|
|
382
|
+
* refetch }`. The `url` is an absolute URL composed against the host's API
|
|
383
|
+
* base; safe to pass straight to `<Image source>`.
|
|
384
|
+
*/
|
|
385
|
+
export function useFile(fileId: string | null | undefined): {
|
|
386
|
+
url: string | null;
|
|
387
|
+
file: {
|
|
388
|
+
id: string;
|
|
389
|
+
url: string;
|
|
390
|
+
storedFilename?: string;
|
|
391
|
+
mimeType?: string;
|
|
392
|
+
sizeBytes?: number;
|
|
393
|
+
[k: string]: unknown;
|
|
394
|
+
} | null;
|
|
395
|
+
loading: boolean;
|
|
396
|
+
error: DatastoreError | null;
|
|
397
|
+
refetch(): Promise<void>;
|
|
398
|
+
};
|
|
399
|
+
|
|
366
400
|
export function useI18n(): {
|
|
367
401
|
locale: string;
|
|
368
402
|
t(key: string, fallback?: string): string;
|
|
@@ -381,6 +415,32 @@ export function useUser(): {
|
|
|
381
415
|
groupIds: string[];
|
|
382
416
|
};
|
|
383
417
|
|
|
418
|
+
/**
|
|
419
|
+
* The host-provided navigation surface. `goTo(pageId, params?)` navigates
|
|
420
|
+
* to an internal app page; `goBack()` pops the stack. Missing methods
|
|
421
|
+
* degrade to no-ops on the Studio canvas preview where no live router is
|
|
422
|
+
* mounted. For external URLs use the `Linking` primitive.
|
|
423
|
+
*/
|
|
424
|
+
export function useNavigation(): {
|
|
425
|
+
goTo(pageId: string, params?: Record<string, unknown>): void;
|
|
426
|
+
goBack(): void;
|
|
427
|
+
push(pageId: string, params?: Record<string, unknown>): void;
|
|
428
|
+
replace(pageId: string, params?: Record<string, unknown>): void;
|
|
429
|
+
back(): void;
|
|
430
|
+
currentRoute: { pageId: string; params: Record<string, unknown> };
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Static API for external URLs. `openURL(url)` opens a URL with the OS
|
|
435
|
+
* handler (web: react-native-web maps to `window.open` / `location.href`;
|
|
436
|
+
* native: hands off to the system). `canOpenURL` reports whether the
|
|
437
|
+
* scheme is registered.
|
|
438
|
+
*/
|
|
439
|
+
export const Linking: {
|
|
440
|
+
openURL(url: string): Promise<unknown>;
|
|
441
|
+
canOpenURL(url: string): Promise<boolean>;
|
|
442
|
+
};
|
|
443
|
+
|
|
384
444
|
/**
|
|
385
445
|
* Error class thrown by useDatastoreMutation callbacks (and surfaced by
|
|
386
446
|
* useDatastoreQuery in its `error` slot). The `code` is a stable
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,8 @@ export {
|
|
|
10
10
|
DatastoreError,
|
|
11
11
|
PaymentError,
|
|
12
12
|
useDatastoreQuery,
|
|
13
|
+
useDatastoreRecord,
|
|
14
|
+
useFile,
|
|
13
15
|
useDatastoreMutation,
|
|
14
16
|
useDirectory,
|
|
15
17
|
useWidgetEvent,
|
|
@@ -17,6 +19,7 @@ export {
|
|
|
17
19
|
useTheme,
|
|
18
20
|
useI18n,
|
|
19
21
|
useUser,
|
|
22
|
+
useNavigation,
|
|
20
23
|
} from "./hooks.js";
|
|
21
24
|
export {
|
|
22
25
|
Text,
|
|
@@ -30,6 +33,7 @@ export {
|
|
|
30
33
|
ActivityIndicator,
|
|
31
34
|
Switch,
|
|
32
35
|
StyleSheet,
|
|
36
|
+
Linking,
|
|
33
37
|
} from "./primitives.js";
|
|
34
38
|
export { lintSource, bannedIdentifiers } from "./linter.js";
|
|
35
39
|
export { CONTRACT, isHookAllowed, requiredContextKeys } from "./contract.js";
|
package/dist/index.native.js
CHANGED
|
@@ -10,6 +10,8 @@ export {
|
|
|
10
10
|
DatastoreError,
|
|
11
11
|
PaymentError,
|
|
12
12
|
useDatastoreQuery,
|
|
13
|
+
useDatastoreRecord,
|
|
14
|
+
useFile,
|
|
13
15
|
useDatastoreMutation,
|
|
14
16
|
useDirectory,
|
|
15
17
|
useWidgetEvent,
|
|
@@ -17,6 +19,7 @@ export {
|
|
|
17
19
|
useTheme,
|
|
18
20
|
useI18n,
|
|
19
21
|
useUser,
|
|
22
|
+
useNavigation,
|
|
20
23
|
} from "./hooks.js";
|
|
21
24
|
export {
|
|
22
25
|
Text,
|
|
@@ -30,6 +33,7 @@ export {
|
|
|
30
33
|
ActivityIndicator,
|
|
31
34
|
Switch,
|
|
32
35
|
StyleSheet,
|
|
36
|
+
Linking,
|
|
33
37
|
} from "./primitives.native.js";
|
|
34
38
|
export { lintSource, bannedIdentifiers } from "./linter.js";
|
|
35
39
|
export { CONTRACT, isHookAllowed, requiredContextKeys } from "./contract.js";
|
package/dist/primitives.js
CHANGED
|
@@ -55,3 +55,8 @@ export const SectionList = ReactNative.SectionList;
|
|
|
55
55
|
export const ActivityIndicator = ReactNative.ActivityIndicator;
|
|
56
56
|
export const Switch = ReactNative.Switch;
|
|
57
57
|
export const StyleSheet = ReactNative.StyleSheet;
|
|
58
|
+
// Static API (not a component): `Linking.openURL(url)` opens an external
|
|
59
|
+
// URL — on web react-native-web uses window.open / location.href, on native
|
|
60
|
+
// the OS hands it off to the system handler. `canOpenURL` reports whether
|
|
61
|
+
// the URL scheme is registered.
|
|
62
|
+
export const Linking = ReactNative.Linking;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@colixsystems/widget-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.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",
|