@colixsystems/widget-sdk 0.259.0 → 0.260.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 +5 -1
- package/dist/accordion.native.js +2 -1
- package/dist/banner.native.js +2 -1
- package/dist/bounded-text.native.js +29 -0
- package/dist/button.native.js +2 -1
- package/dist/chart.native.js +2 -1
- package/dist/checkbox.native.js +2 -1
- package/dist/chip.native.js +2 -1
- package/dist/confirm-dialog.native.js +3 -3
- package/dist/contract.cjs +22 -18
- package/dist/contract.js +23 -18
- package/dist/data-table.native.js +2 -1
- package/dist/datetimepicker.native.js +2 -1
- package/dist/detail-parts.native.js +2 -1
- package/dist/emoji-picker.native.js +2 -1
- package/dist/file-upload.native.js +2 -1
- package/dist/form.native.js +2 -1
- package/dist/index.d.ts +2 -0
- package/dist/linter.cjs +1 -1
- package/dist/list.native.js +2 -1
- package/dist/loading.native.js +2 -1
- package/dist/markdown-input.native.js +2 -1
- package/dist/modal.native.js +1 -1
- package/dist/popover.native.js +2 -1
- package/dist/primitives.native.js +2 -2
- package/dist/radio-group.native.js +2 -1
- package/dist/richtext.native.js +2 -1
- package/dist/search-field.native.js +2 -1
- package/dist/select.native.js +2 -1
- package/dist/sortable.native.js +2 -1
- package/dist/surface-theme.js +2 -2
- package/dist/switch.native.js +2 -1
- package/dist/tabs.native.js +2 -1
- package/dist/text-field.native.js +2 -1
- package/package.json +2 -1
- package/src/contract.js +23 -18
package/README.md
CHANGED
|
@@ -85,7 +85,11 @@ See the design reference for the full architecture: [`docs/architecture/widget-m
|
|
|
85
85
|
|
|
86
86
|
## Status
|
|
87
87
|
|
|
88
|
-
`v0.
|
|
88
|
+
`v0.260.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**.
|
|
89
|
+
|
|
90
|
+
### What's new in 0.260.0 (contract 1.211.0)
|
|
91
|
+
|
|
92
|
+
**Text on a phone grows with the device's text-size setting only up to 1.3×** (`CONTRACT.maxFontSizeMultiplier`). React Native multiplies every font size by that setting and a browser has no equivalent, so the Player and the Builder canvas always show 1×; unbounded, a heading that fits there overflowed on a phone set to a large text size. The native `<Text>` and `<TextInput>` (and every SDK component built on them) now carry the bound, so accessibility scaling still works but a layout only has to survive 1.3×. Pass your own `maxFontSizeMultiplier` to change it for one element.
|
|
89
93
|
|
|
90
94
|
### What's new in 0.259.0 (contract 1.210.0)
|
|
91
95
|
|
package/dist/accordion.native.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// `<Accordion>` / `<AccordionItem>` (native). Binds ./accordion-view.js to
|
|
2
2
|
// React Native's own primitives; only the import differs from ./accordion.js.
|
|
3
3
|
|
|
4
|
-
import { View,
|
|
4
|
+
import { View, Pressable } from "react-native";
|
|
5
|
+
import { Text } from "./bounded-text.native.js";
|
|
5
6
|
import { makeAccordion } from "./accordion-view.js";
|
|
6
7
|
|
|
7
8
|
export const { Accordion, AccordionItem } = makeAccordion({ View, Text, Pressable });
|
package/dist/banner.native.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// `<Banner>` (native). Binds ./banner-view.js to React Native's own
|
|
2
2
|
// primitives; only the import differs from ./banner.js.
|
|
3
3
|
|
|
4
|
-
import { View,
|
|
4
|
+
import { View, Pressable } from "react-native";
|
|
5
|
+
import { Text } from "./bounded-text.native.js";
|
|
5
6
|
import { makeBanner } from "./banner-view.js";
|
|
6
7
|
|
|
7
8
|
export const Banner = makeBanner({ View, Text, Pressable });
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// sc-9168 — native Text / TextInput, bounded to the contract's font-scale cap.
|
|
2
|
+
//
|
|
3
|
+
// React Native multiplies every font size by the device's font-scale setting;
|
|
4
|
+
// a browser has no equivalent (page zoom scales the whole layout, so nothing
|
|
5
|
+
// overflows), which is why this file has no web twin and the Player and the
|
|
6
|
+
// Builder canvas render at scale 1.0. Unbounded, a layout that fits there
|
|
7
|
+
// overflows on a phone set to a large text size. The cap keeps accessibility
|
|
8
|
+
// scaling working up to that bound; a caller's own prop still wins.
|
|
9
|
+
//
|
|
10
|
+
// Every SDK native module takes Text / TextInput from here, never from
|
|
11
|
+
// `react-native` directly — bounded-text-native.test.js enforces it.
|
|
12
|
+
import React from "react";
|
|
13
|
+
import { Text as RNText, TextInput as RNTextInput } from "react-native";
|
|
14
|
+
import { CONTRACT } from "./contract.js";
|
|
15
|
+
|
|
16
|
+
function bounded(Component, displayName) {
|
|
17
|
+
const Bounded = React.forwardRef(function BoundedText(props, ref) {
|
|
18
|
+
return React.createElement(Component, {
|
|
19
|
+
maxFontSizeMultiplier: CONTRACT.maxFontSizeMultiplier,
|
|
20
|
+
...props,
|
|
21
|
+
ref,
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
Bounded.displayName = displayName;
|
|
25
|
+
return Bounded;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const Text = bounded(RNText, "Text");
|
|
29
|
+
export const TextInput = bounded(RNTextInput, "TextInput");
|
package/dist/button.native.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
// Native, the expo-linear-gradient `<Gradient>` and the native `<Spinner>`;
|
|
3
3
|
// only the imports differ from ./button.js.
|
|
4
4
|
|
|
5
|
-
import { View,
|
|
5
|
+
import { View, Pressable, StyleSheet, Platform } from "react-native";
|
|
6
|
+
import { Text } from "./bounded-text.native.js";
|
|
6
7
|
import { Gradient } from "./gradient.native.js";
|
|
7
8
|
import { Spinner } from "./loading.native.js";
|
|
8
9
|
import { makeButton, BUTTON_VARIANTS } from "./button-view.js";
|
package/dist/chart.native.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// `<Chart>` (native). Binds ./chart-view.js to React Native and
|
|
2
2
|
// react-native-svg; only the imports differ from ./chart.js.
|
|
3
3
|
|
|
4
|
-
import { View
|
|
4
|
+
import { View } from "react-native";
|
|
5
|
+
import { Text } from "./bounded-text.native.js";
|
|
5
6
|
import Svg, { G, Path, Line, Circle, Text as SvgText } from "react-native-svg";
|
|
6
7
|
import { Skeleton } from "./loading.native.js";
|
|
7
8
|
import { EmptyState } from "./list.native.js";
|
package/dist/checkbox.native.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// `<Checkbox>` (native). Binds ./checkbox-view.js to React Native's own
|
|
2
2
|
// primitives; only the import differs from ./checkbox.js.
|
|
3
3
|
|
|
4
|
-
import { View,
|
|
4
|
+
import { View, Pressable } from "react-native";
|
|
5
|
+
import { Text } from "./bounded-text.native.js";
|
|
5
6
|
import { makeCheckbox } from "./checkbox-view.js";
|
|
6
7
|
|
|
7
8
|
export const Checkbox = makeCheckbox({ View, Text, Pressable });
|
package/dist/chip.native.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// `<Chip>` / `<ChipGroup>` (native). Binds ./chip-view.js to React Native's own
|
|
2
2
|
// primitives; only the import differs from ./chip.js.
|
|
3
3
|
|
|
4
|
-
import { View,
|
|
4
|
+
import { View, Pressable } from "react-native";
|
|
5
|
+
import { Text } from "./bounded-text.native.js";
|
|
5
6
|
import { makeChip } from "./chip-view.js";
|
|
6
7
|
|
|
7
8
|
export const { Chip, ChipGroup } = makeChip({ View, Text, Pressable });
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
// `<ConfirmDialog>` (native). Binds ./confirm-dialog-view.js to
|
|
2
|
-
//
|
|
1
|
+
// `<ConfirmDialog>` (native). Binds ./confirm-dialog-view.js to the bounded
|
|
2
|
+
// native Text and the native `<Modal>`, `<Button>` and `<Spinner>`; only the
|
|
3
3
|
// imports differ from ./confirm-dialog.js.
|
|
4
4
|
|
|
5
|
-
import { Text } from "
|
|
5
|
+
import { Text } from "./bounded-text.native.js";
|
|
6
6
|
import { makeConfirmDialog } from "./confirm-dialog-view.js";
|
|
7
7
|
import { Modal } from "./modal.native.js";
|
|
8
8
|
import { Button } from "./button.native.js";
|
package/dist/contract.cjs
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
// The
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
// Keep edits in lockstep between `contract.cjs` and `contract.js`. The
|
|
9
|
-
// SDK build script copies both into `dist/`.
|
|
1
|
+
// GENERATED from contract.js by scripts/contract-cjs.js — DO NOT EDIT.
|
|
2
|
+
// Change contract.js, then run `npm run generate:contract` in packages/widget-sdk.
|
|
3
|
+
|
|
4
|
+
// The widget SDK contract: the ONE source the linter, the AI agents, the
|
|
5
|
+
// compiler and both hosts read. `contract.cjs` is GENERATED from `contract.js`
|
|
6
|
+
// (`npm run generate:contract`) for CommonJS consumers — never edit it by hand;
|
|
7
|
+
// contract-cjs-generated.test.js fails when it is stale.
|
|
10
8
|
|
|
11
9
|
// REQ-AI-AGENT-DESIGN (sc-3696): the ONE cross-platform elevation vocabulary.
|
|
12
10
|
// `shadow*` applies on iOS + react-native-web, `elevation` drives Android.
|
|
@@ -2645,7 +2643,7 @@ const HOOKS = [
|
|
|
2645
2643
|
scopes: ["users.write:*"],
|
|
2646
2644
|
},
|
|
2647
2645
|
// REQ-BANKID-AUTH — link / unlink a BankID identity to the signed-in
|
|
2648
|
-
// app-user. Self-service + JWT-gated (no widget scope).
|
|
2646
|
+
// app-user. Self-service + JWT-gated (no widget scope).
|
|
2649
2647
|
{
|
|
2650
2648
|
name: "useBankIdLink",
|
|
2651
2649
|
signature: "useBankIdLink()",
|
|
@@ -2681,7 +2679,7 @@ const HOOKS = [
|
|
|
2681
2679
|
scopes: null,
|
|
2682
2680
|
},
|
|
2683
2681
|
// REQ-IDENT (sc-4313) — identify a visitor who is NOT signed in and keep the
|
|
2684
|
-
// result. Anonymous by design (no widget scope, no session).
|
|
2682
|
+
// result. Anonymous by design (no widget scope, no session).
|
|
2685
2683
|
{
|
|
2686
2684
|
name: "useIdentification",
|
|
2687
2685
|
signature: "useIdentification(options)",
|
|
@@ -2732,7 +2730,7 @@ const HOOKS = [
|
|
|
2732
2730
|
scopes: null,
|
|
2733
2731
|
},
|
|
2734
2732
|
// REQ-ACL-06 / REQ-ACL-RELINHERIT-05 — per-record VirtualPermission
|
|
2735
|
-
// management for a single record.
|
|
2733
|
+
// management for a single record.
|
|
2736
2734
|
{
|
|
2737
2735
|
name: "useRecordPermissions",
|
|
2738
2736
|
signature: "useRecordPermissions(tableId, recordId)",
|
|
@@ -2865,7 +2863,7 @@ const HOOKS = [
|
|
|
2865
2863
|
requiredContextSlice: ["datastore.records"],
|
|
2866
2864
|
scopes: ["datastore.read:<table>"],
|
|
2867
2865
|
},
|
|
2868
|
-
// REQ-WSDK-PLATFORM §6 — Tier A SDK hooks.
|
|
2866
|
+
// REQ-WSDK-PLATFORM §6 — Tier A SDK hooks.
|
|
2869
2867
|
{
|
|
2870
2868
|
name: "useClipboard",
|
|
2871
2869
|
signature: "useClipboard()",
|
|
@@ -4217,14 +4215,14 @@ const WIDGET_CONTEXT_SHAPE = {
|
|
|
4217
4215
|
required: true,
|
|
4218
4216
|
fields: { requestPayment: "function", getPayment: "function" },
|
|
4219
4217
|
},
|
|
4220
|
-
// sc-890 — backs useSendNotification().
|
|
4218
|
+
// sc-890 — backs useSendNotification().
|
|
4221
4219
|
notifications: {
|
|
4222
4220
|
description:
|
|
4223
4221
|
"Injected @colixsystems/notifications-client instance (sc-890). { send(body) -> Promise<notification>, mutes: { get, set, clear } }. send backs useSendNotification(); requires the notifications.send:appUser scope. The host POSTs the body snake_case verbatim ({ recipient_user_id, title, body, link?, payload? }) to /notifications/send and returns the created notification row; the call is imperative (a send never fires on mount). mutes backs useRecordMute() and useRecordMutes() (sc-10268): get({ table_id, record_id }) / set({ table_id, record_id, muted_until }) -> { muted, muted_until }, clear({ table_id, record_id }) -> undefined, list({ table_id, limit?, offset? }) -> { data: [{ record_id, muted_until }], meta }. mutes is optional — a host without it (the Builder canvas preview) leaves useRecordMute() reading not muted.",
|
|
4224
4222
|
required: true,
|
|
4225
4223
|
fields: { send: "function", mutes: "object" },
|
|
4226
4224
|
},
|
|
4227
|
-
// REQ-IDENT (sc-4313) — backs useIdentification().
|
|
4225
|
+
// REQ-IDENT (sc-4313) — backs useIdentification().
|
|
4228
4226
|
identification: {
|
|
4229
4227
|
description:
|
|
4230
4228
|
"Injected @colixsystems/identification-client instance (REQ-IDENT). { available() -> Promise<{ available, providers }>, start(body) -> Promise<order>, get(id) -> Promise<state>, cancel(id) -> Promise<state> }. Backs useIdentification(); no widget scope and no signed-in user required — identifying a NOT-signed-in visitor is the point, so the endpoints are anonymous. Bodies and rows are snake_case verbatim. A completed identification exposes name + personal_number_masked + a stable subject_hash; the RAW personal number is never reachable from a widget (it lives behind a studio-admin endpoint).",
|
|
@@ -4265,7 +4263,7 @@ const WIDGET_CONTEXT_SHAPE = {
|
|
|
4265
4263
|
error: "function",
|
|
4266
4264
|
},
|
|
4267
4265
|
},
|
|
4268
|
-
// REQ-WSDK-PLATFORM §6 — backs useToast().
|
|
4266
|
+
// REQ-WSDK-PLATFORM §6 — backs useToast().
|
|
4269
4267
|
toast: {
|
|
4270
4268
|
description:
|
|
4271
4269
|
"Optional host toast slot. { showToast({ kind, message }): void }. " +
|
|
@@ -4709,7 +4707,7 @@ const VETTED_IMPORTS = [
|
|
|
4709
4707
|
// `allowedBareImports` (so the loader's shim⊆vetted guard treats them as
|
|
4710
4708
|
// vetted) WITHOUT bloating the rich `VETTED_IMPORTS` reference the AI prompt /
|
|
4711
4709
|
// Developer guide enumerate — the SAME treatment `react/jsx-runtime` gets, but
|
|
4712
|
-
// kept out of the author-facing list.
|
|
4710
|
+
// kept out of the author-facing list.
|
|
4713
4711
|
const CORE_INFRA_BARE_IMPORTS = ["react-dom", "react-dom/client"];
|
|
4714
4712
|
|
|
4715
4713
|
// Back-compat shape — every existing consumer (widgetLoader, the static
|
|
@@ -6379,7 +6377,9 @@ const CONTRACT = deepFreeze({
|
|
|
6379
6377
|
// `<testID>-option-<id>`.
|
|
6380
6378
|
// 1.210.0: behaviour (sc-12245) — `<Avatar url>` falls back to the
|
|
6381
6379
|
// initials when its picture fails to load. No API change.
|
|
6382
|
-
|
|
6380
|
+
// 1.211.0: additive (sc-9168) — `maxFontSizeMultiplier`: native `<Text>` /
|
|
6381
|
+
// `<TextInput>` follow the device font scale up to this bound.
|
|
6382
|
+
version: "1.211.0",
|
|
6383
6383
|
sharedTranslationKeys: SHARED_TRANSLATION_KEYS,
|
|
6384
6384
|
hooks: HOOKS,
|
|
6385
6385
|
primitives: PRIMITIVES,
|
|
@@ -6408,6 +6408,10 @@ const CONTRACT = deepFreeze({
|
|
|
6408
6408
|
bundleExportContract: BUNDLE_EXPORT_CONTRACT,
|
|
6409
6409
|
// sc-10829 — the hook a `badgeCounter: true` entry exports by name.
|
|
6410
6410
|
badgeCounterExport: "useBadgeCount",
|
|
6411
|
+
// sc-9168 — the most native text grows with the device font-scale setting.
|
|
6412
|
+
// Above it a layout sized against the Player overflows; the browser has no
|
|
6413
|
+
// such setting to preview it with.
|
|
6414
|
+
maxFontSizeMultiplier: 1.3,
|
|
6411
6415
|
bannedApis: BANNED_APIS,
|
|
6412
6416
|
vettedImports: VETTED_IMPORTS,
|
|
6413
6417
|
allowedBareImports: ALLOWED_BARE_IMPORTS,
|
package/dist/contract.js
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// export. The contract test asserts the two are identical (deep-equal) so
|
|
6
|
-
// drift between this file and the ESM source-of-truth is caught in CI.
|
|
7
|
-
//
|
|
8
|
-
// Keep edits in lockstep between `contract.cjs` and `contract.js`. The
|
|
9
|
-
// SDK build script copies both into `dist/`.
|
|
1
|
+
// The widget SDK contract: the ONE source the linter, the AI agents, the
|
|
2
|
+
// compiler and both hosts read. `contract.cjs` is GENERATED from `contract.js`
|
|
3
|
+
// (`npm run generate:contract`) for CommonJS consumers — never edit it by hand;
|
|
4
|
+
// contract-cjs-generated.test.js fails when it is stale.
|
|
10
5
|
|
|
11
6
|
// REQ-AI-AGENT-DESIGN (sc-3696): the ONE cross-platform elevation vocabulary.
|
|
12
7
|
// `shadow*` applies on iOS + react-native-web, `elevation` drives Android.
|
|
@@ -2645,7 +2640,7 @@ const HOOKS = [
|
|
|
2645
2640
|
scopes: ["users.write:*"],
|
|
2646
2641
|
},
|
|
2647
2642
|
// REQ-BANKID-AUTH — link / unlink a BankID identity to the signed-in
|
|
2648
|
-
// app-user. Self-service + JWT-gated (no widget scope).
|
|
2643
|
+
// app-user. Self-service + JWT-gated (no widget scope).
|
|
2649
2644
|
{
|
|
2650
2645
|
name: "useBankIdLink",
|
|
2651
2646
|
signature: "useBankIdLink()",
|
|
@@ -2681,7 +2676,7 @@ const HOOKS = [
|
|
|
2681
2676
|
scopes: null,
|
|
2682
2677
|
},
|
|
2683
2678
|
// REQ-IDENT (sc-4313) — identify a visitor who is NOT signed in and keep the
|
|
2684
|
-
// result. Anonymous by design (no widget scope, no session).
|
|
2679
|
+
// result. Anonymous by design (no widget scope, no session).
|
|
2685
2680
|
{
|
|
2686
2681
|
name: "useIdentification",
|
|
2687
2682
|
signature: "useIdentification(options)",
|
|
@@ -2732,7 +2727,7 @@ const HOOKS = [
|
|
|
2732
2727
|
scopes: null,
|
|
2733
2728
|
},
|
|
2734
2729
|
// REQ-ACL-06 / REQ-ACL-RELINHERIT-05 — per-record VirtualPermission
|
|
2735
|
-
// management for a single record.
|
|
2730
|
+
// management for a single record.
|
|
2736
2731
|
{
|
|
2737
2732
|
name: "useRecordPermissions",
|
|
2738
2733
|
signature: "useRecordPermissions(tableId, recordId)",
|
|
@@ -2865,7 +2860,7 @@ const HOOKS = [
|
|
|
2865
2860
|
requiredContextSlice: ["datastore.records"],
|
|
2866
2861
|
scopes: ["datastore.read:<table>"],
|
|
2867
2862
|
},
|
|
2868
|
-
// REQ-WSDK-PLATFORM §6 — Tier A SDK hooks.
|
|
2863
|
+
// REQ-WSDK-PLATFORM §6 — Tier A SDK hooks.
|
|
2869
2864
|
{
|
|
2870
2865
|
name: "useClipboard",
|
|
2871
2866
|
signature: "useClipboard()",
|
|
@@ -3701,6 +3696,10 @@ const ACTION_TRIGGER_TYPES = [
|
|
|
3701
3696
|
// Globals the action script runs against (the runner's surface) — distinct
|
|
3702
3697
|
// from the React/SDK widget surface, so the component import/banned-API
|
|
3703
3698
|
// linter does NOT scan action scripts.
|
|
3699
|
+
// sc-7877 deliberately does NOT add `directory` here. That global is
|
|
3700
|
+
// reachable only by a MARKETPLACE action whose install consented to a
|
|
3701
|
+
// `directory:` scope; a widget-declared action has no install, so
|
|
3702
|
+
// resolveForActionRow grants it nothing and the global is never defined.
|
|
3704
3703
|
const ACTION_SCRIPT_GLOBALS = [
|
|
3705
3704
|
"datastore",
|
|
3706
3705
|
"secrets",
|
|
@@ -4213,14 +4212,14 @@ const WIDGET_CONTEXT_SHAPE = {
|
|
|
4213
4212
|
required: true,
|
|
4214
4213
|
fields: { requestPayment: "function", getPayment: "function" },
|
|
4215
4214
|
},
|
|
4216
|
-
// sc-890 — backs useSendNotification().
|
|
4215
|
+
// sc-890 — backs useSendNotification().
|
|
4217
4216
|
notifications: {
|
|
4218
4217
|
description:
|
|
4219
4218
|
"Injected @colixsystems/notifications-client instance (sc-890). { send(body) -> Promise<notification>, mutes: { get, set, clear } }. send backs useSendNotification(); requires the notifications.send:appUser scope. The host POSTs the body snake_case verbatim ({ recipient_user_id, title, body, link?, payload? }) to /notifications/send and returns the created notification row; the call is imperative (a send never fires on mount). mutes backs useRecordMute() and useRecordMutes() (sc-10268): get({ table_id, record_id }) / set({ table_id, record_id, muted_until }) -> { muted, muted_until }, clear({ table_id, record_id }) -> undefined, list({ table_id, limit?, offset? }) -> { data: [{ record_id, muted_until }], meta }. mutes is optional — a host without it (the Builder canvas preview) leaves useRecordMute() reading not muted.",
|
|
4220
4219
|
required: true,
|
|
4221
4220
|
fields: { send: "function", mutes: "object" },
|
|
4222
4221
|
},
|
|
4223
|
-
// REQ-IDENT (sc-4313) — backs useIdentification().
|
|
4222
|
+
// REQ-IDENT (sc-4313) — backs useIdentification().
|
|
4224
4223
|
identification: {
|
|
4225
4224
|
description:
|
|
4226
4225
|
"Injected @colixsystems/identification-client instance (REQ-IDENT). { available() -> Promise<{ available, providers }>, start(body) -> Promise<order>, get(id) -> Promise<state>, cancel(id) -> Promise<state> }. Backs useIdentification(); no widget scope and no signed-in user required — identifying a NOT-signed-in visitor is the point, so the endpoints are anonymous. Bodies and rows are snake_case verbatim. A completed identification exposes name + personal_number_masked + a stable subject_hash; the RAW personal number is never reachable from a widget (it lives behind a studio-admin endpoint).",
|
|
@@ -4261,7 +4260,7 @@ const WIDGET_CONTEXT_SHAPE = {
|
|
|
4261
4260
|
error: "function",
|
|
4262
4261
|
},
|
|
4263
4262
|
},
|
|
4264
|
-
// REQ-WSDK-PLATFORM §6 — backs useToast().
|
|
4263
|
+
// REQ-WSDK-PLATFORM §6 — backs useToast().
|
|
4265
4264
|
toast: {
|
|
4266
4265
|
description:
|
|
4267
4266
|
"Optional host toast slot. { showToast({ kind, message }): void }. " +
|
|
@@ -4705,7 +4704,7 @@ const VETTED_IMPORTS = [
|
|
|
4705
4704
|
// `allowedBareImports` (so the loader's shim⊆vetted guard treats them as
|
|
4706
4705
|
// vetted) WITHOUT bloating the rich `VETTED_IMPORTS` reference the AI prompt /
|
|
4707
4706
|
// Developer guide enumerate — the SAME treatment `react/jsx-runtime` gets, but
|
|
4708
|
-
// kept out of the author-facing list.
|
|
4707
|
+
// kept out of the author-facing list.
|
|
4709
4708
|
const CORE_INFRA_BARE_IMPORTS = ["react-dom", "react-dom/client"];
|
|
4710
4709
|
|
|
4711
4710
|
// Back-compat shape — every existing consumer (widgetLoader, the static
|
|
@@ -6375,7 +6374,9 @@ const CONTRACT = deepFreeze({
|
|
|
6375
6374
|
// `<testID>-option-<id>`.
|
|
6376
6375
|
// 1.210.0: behaviour (sc-12245) — `<Avatar url>` falls back to the
|
|
6377
6376
|
// initials when its picture fails to load. No API change.
|
|
6378
|
-
|
|
6377
|
+
// 1.211.0: additive (sc-9168) — `maxFontSizeMultiplier`: native `<Text>` /
|
|
6378
|
+
// `<TextInput>` follow the device font scale up to this bound.
|
|
6379
|
+
version: "1.211.0",
|
|
6379
6380
|
sharedTranslationKeys: SHARED_TRANSLATION_KEYS,
|
|
6380
6381
|
hooks: HOOKS,
|
|
6381
6382
|
primitives: PRIMITIVES,
|
|
@@ -6404,6 +6405,10 @@ const CONTRACT = deepFreeze({
|
|
|
6404
6405
|
bundleExportContract: BUNDLE_EXPORT_CONTRACT,
|
|
6405
6406
|
// sc-10829 — the hook a `badgeCounter: true` entry exports by name.
|
|
6406
6407
|
badgeCounterExport: "useBadgeCount",
|
|
6408
|
+
// sc-9168 — the most native text grows with the device font-scale setting.
|
|
6409
|
+
// Above it a layout sized against the Player overflows; the browser has no
|
|
6410
|
+
// such setting to preview it with.
|
|
6411
|
+
maxFontSizeMultiplier: 1.3,
|
|
6407
6412
|
bannedApis: BANNED_APIS,
|
|
6408
6413
|
vettedImports: VETTED_IMPORTS,
|
|
6409
6414
|
allowedBareImports: ALLOWED_BARE_IMPORTS,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// `<DataTable>` (native). Binds ./data-table-view.js to React Native's own
|
|
2
2
|
// primitives and the native parts; only the imports differ from ./data-table.js.
|
|
3
3
|
|
|
4
|
-
import { View,
|
|
4
|
+
import { View, Pressable, ScrollView, Platform, AccessibilityInfo } from "react-native";
|
|
5
|
+
import { Text } from "./bounded-text.native.js";
|
|
5
6
|
import { List, ListRow, ListHeader, EmptyState } from "./list.native.js";
|
|
6
7
|
import { Skeleton } from "./loading.native.js";
|
|
7
8
|
import { Menu } from "./popover.native.js";
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
import React from "react";
|
|
7
7
|
// eslint-disable-next-line no-restricted-syntax
|
|
8
8
|
import RNDateTimePicker from "@react-native-community/datetimepicker";
|
|
9
|
-
import { View,
|
|
9
|
+
import { View, Pressable, Platform } from "react-native";
|
|
10
|
+
import { Text } from "./bounded-text.native.js";
|
|
10
11
|
import { makeDateTimePicker } from "./datetimepicker-view.js";
|
|
11
12
|
import { nowParts, partsToDate, valueToParts } from "./datetimepicker-format.js";
|
|
12
13
|
import { clampToBounds } from "./datetimepicker-calendar.js";
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
// ./detail-parts-view.js to React Native; only the imports differ from
|
|
3
3
|
// ./detail-parts.js.
|
|
4
4
|
|
|
5
|
-
import { View,
|
|
5
|
+
import { View, Image } from "react-native";
|
|
6
|
+
import { Text } from "./bounded-text.native.js";
|
|
6
7
|
import Svg, { Circle } from "react-native-svg";
|
|
7
8
|
import { makeDetailParts } from "./detail-parts-view.js";
|
|
8
9
|
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
// ./emoji-picker-view.js to React Native's own primitives plus the native
|
|
3
3
|
// `<Overlay>`. Only the imports differ from the web mirror (./emoji-picker.js).
|
|
4
4
|
|
|
5
|
-
import { View,
|
|
5
|
+
import { View, Pressable, ScrollView } from "react-native";
|
|
6
|
+
import { Text, TextInput } from "./bounded-text.native.js";
|
|
6
7
|
import { makeEmojiPicker } from "./emoji-picker-view.js";
|
|
7
8
|
import { Overlay } from "./overlay.native.js";
|
|
8
9
|
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
// native `<FilePicker>` (the OS document picker). No drop target: React Native
|
|
3
3
|
// has no events for files dragged onto an app, so the button is the control.
|
|
4
4
|
|
|
5
|
-
import { View,
|
|
5
|
+
import { View, Pressable, Platform } from "react-native";
|
|
6
|
+
import { Text } from "./bounded-text.native.js";
|
|
6
7
|
import { makeFileUpload } from "./file-upload-view.js";
|
|
7
8
|
import { FilePicker } from "./filepicker.native.js";
|
|
8
9
|
import { Button } from "./button.native.js";
|
package/dist/form.native.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
// (native). Binds ./form-view.js to React Native's own primitives and the
|
|
3
3
|
// native `<Grid>`; only the imports differ from ./form.js.
|
|
4
4
|
|
|
5
|
-
import { View,
|
|
5
|
+
import { View, Pressable, Platform } from "react-native";
|
|
6
|
+
import { Text } from "./bounded-text.native.js";
|
|
6
7
|
import { makeForm } from "./form-view.js";
|
|
7
8
|
import { Grid } from "./grid.native.js";
|
|
8
9
|
|
package/dist/index.d.ts
CHANGED
|
@@ -5868,6 +5868,8 @@ export interface AiWidgetContract {
|
|
|
5868
5868
|
readonly bundleExportContract: ReadonlyArray<ContractBundleShape>;
|
|
5869
5869
|
/** sc-10829 — the export name of a `badgeCounter: true` entry's hook. */
|
|
5870
5870
|
readonly badgeCounterExport: "useBadgeCount";
|
|
5871
|
+
/** The most native Text / TextInput grow with the device font-scale setting. */
|
|
5872
|
+
readonly maxFontSizeMultiplier: number;
|
|
5871
5873
|
readonly bannedApis: ReadonlyArray<ContractBannedApi>;
|
|
5872
5874
|
readonly allowedBareImports: ReadonlyArray<string>;
|
|
5873
5875
|
/** Bare specifiers the web host provides by exact name; a widget bundle never inlines them. */
|
package/dist/linter.cjs
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// The ESM `linter.js` is the source-of-truth. This file MUST mirror its
|
|
5
5
|
// rule set byte-for-byte — the contract test in packages/widget-sdk
|
|
6
6
|
// asserts the two are behaviour-equivalent. When you edit one, edit the
|
|
7
|
-
// other in the same PR.
|
|
7
|
+
// other in the same PR.
|
|
8
8
|
//
|
|
9
9
|
// The SDK build script copies both into `dist/`.
|
|
10
10
|
|
package/dist/list.native.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// `<List>`, `<ListRow>`, `<ListHeader>`, `<EmptyState>` (native). Binds
|
|
2
2
|
// ./list-view.js to React Native's own primitives; only the imports differ from ./list.js.
|
|
3
3
|
|
|
4
|
-
import { View,
|
|
4
|
+
import { View, Pressable } from "react-native";
|
|
5
|
+
import { Text } from "./bounded-text.native.js";
|
|
5
6
|
import { Card } from "./card.native.js";
|
|
6
7
|
import { makeList } from "./list-view.js";
|
|
7
8
|
|
package/dist/loading.native.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// `<Spinner>` and `<Skeleton>` (native). Binds ./loading-view.js to React
|
|
2
2
|
// Native's own primitives; only the import differs from ./loading.js.
|
|
3
3
|
|
|
4
|
-
import { View,
|
|
4
|
+
import { View, Animated, Easing, AccessibilityInfo } from "react-native";
|
|
5
|
+
import { Text } from "./bounded-text.native.js";
|
|
5
6
|
import { makeLoading } from "./loading-view.js";
|
|
6
7
|
|
|
7
8
|
export const { Spinner, Skeleton } = makeLoading(
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
// ./markdown-input-view.js to React Native's own primitives and the native
|
|
3
3
|
// `<RichText>`. Only the imports differ from the web mirror.
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { View, Pressable, ScrollView } from "react-native";
|
|
6
|
+
import { Text, TextInput } from "./bounded-text.native.js";
|
|
6
7
|
import { makeMarkdownInput } from "./markdown-input-view.js";
|
|
7
8
|
import { RichText } from "./richtext.native.js";
|
|
8
9
|
import { Modal } from "./modal.native.js";
|
package/dist/modal.native.js
CHANGED
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
import React from "react";
|
|
7
7
|
import {
|
|
8
8
|
View,
|
|
9
|
-
Text,
|
|
10
9
|
Pressable,
|
|
11
10
|
ScrollView,
|
|
12
11
|
KeyboardAvoidingView,
|
|
13
12
|
Platform,
|
|
14
13
|
} from "react-native";
|
|
14
|
+
import { Text } from "./bounded-text.native.js";
|
|
15
15
|
// Host-provided: the exported app pins it and mounts its provider at the root.
|
|
16
16
|
import { SafeAreaInsetsContext } from "react-native-safe-area-context";
|
|
17
17
|
import { makeModal } from "./modal-view.js";
|
package/dist/popover.native.js
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
// differ from ./popover.js, plus the safe-area inset a bottom sheet pads by.
|
|
4
4
|
|
|
5
5
|
import React from "react";
|
|
6
|
-
import { View,
|
|
6
|
+
import { View, Pressable, ScrollView, Platform, useWindowDimensions } from "react-native";
|
|
7
|
+
import { Text } from "./bounded-text.native.js";
|
|
7
8
|
// Host-provided: the exported app pins it and mounts its provider at the root.
|
|
8
9
|
import { SafeAreaInsetsContext } from "react-native-safe-area-context";
|
|
9
10
|
import { makePopover } from "./popover-view.js";
|
|
@@ -7,12 +7,10 @@
|
|
|
7
7
|
// `./primitives.js`.
|
|
8
8
|
|
|
9
9
|
export {
|
|
10
|
-
Text,
|
|
11
10
|
View,
|
|
12
11
|
Pressable,
|
|
13
12
|
Image,
|
|
14
13
|
ScrollView,
|
|
15
|
-
TextInput,
|
|
16
14
|
FlatList,
|
|
17
15
|
SectionList,
|
|
18
16
|
ActivityIndicator,
|
|
@@ -20,6 +18,8 @@ export {
|
|
|
20
18
|
StyleSheet,
|
|
21
19
|
Linking,
|
|
22
20
|
} from "react-native";
|
|
21
|
+
// sc-9168 — bounded to the device font-scale cap; no web twin (no such setting).
|
|
22
|
+
export { Text, TextInput } from "./bounded-text.native.js";
|
|
23
23
|
|
|
24
24
|
// REQ-WSDK-PLATFORM §6 — `<Icon>` is implemented in one file that runs on
|
|
25
25
|
// both platforms (lucide-react-native ships a working build for both).
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// `<RadioGroup>` (native). Binds ./radio-group-view.js to React Native's own
|
|
2
2
|
// primitives; only the import differs from ./radio-group.js.
|
|
3
3
|
|
|
4
|
-
import { View,
|
|
4
|
+
import { View, Pressable, Platform } from "react-native";
|
|
5
|
+
import { Text } from "./bounded-text.native.js";
|
|
5
6
|
import { makeRadioGroup } from "./radio-group-view.js";
|
|
6
7
|
|
|
7
8
|
export const RadioGroup = makeRadioGroup({ View, Text, Pressable, Platform });
|
package/dist/richtext.native.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
// ./richtext-view.js to React Native's own primitives. Only the import differs
|
|
3
3
|
// from the web mirror in ./richtext.js.
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { View, Image } from "react-native";
|
|
6
|
+
import { Text } from "./bounded-text.native.js";
|
|
6
7
|
import { makeRichText } from "./richtext-view.js";
|
|
7
8
|
|
|
8
9
|
export const RichText = makeRichText({ Text, View, Image });
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
// primitives and the native `<TextField>`; only the imports differ from
|
|
3
3
|
// ./search-field.js.
|
|
4
4
|
|
|
5
|
-
import { View,
|
|
5
|
+
import { View, Pressable } from "react-native";
|
|
6
|
+
import { Text } from "./bounded-text.native.js";
|
|
6
7
|
import { makeSearchField } from "./search-field-view.js";
|
|
7
8
|
import { TextField } from "./text-field.native.js";
|
|
8
9
|
|
package/dist/select.native.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
// primitives and the native `<Overlay>`, `<Button>`, `<Chip>`,
|
|
3
3
|
// `<SearchField>` and `<Spinner>`; only the imports differ from ./select.js.
|
|
4
4
|
|
|
5
|
-
import { View,
|
|
5
|
+
import { View, Pressable, ScrollView, Platform } from "react-native";
|
|
6
|
+
import { Text } from "./bounded-text.native.js";
|
|
6
7
|
import { makeSelect } from "./select-view.js";
|
|
7
8
|
import { Overlay } from "./overlay.native.js";
|
|
8
9
|
import { Button } from "./button.native.js";
|
package/dist/sortable.native.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
// Native's own primitives; only the imports and the handle style differ from
|
|
3
3
|
// ./sortable.js.
|
|
4
4
|
|
|
5
|
-
import { View,
|
|
5
|
+
import { View, ScrollView, Animated, PanResponder, Platform, AccessibilityInfo } from "react-native";
|
|
6
|
+
import { Text } from "./bounded-text.native.js";
|
|
6
7
|
import { List, ListRow } from "./list.native.js";
|
|
7
8
|
import { Card } from "./card.native.js";
|
|
8
9
|
import { Menu } from "./popover.native.js";
|
package/dist/surface-theme.js
CHANGED
|
@@ -26,8 +26,8 @@ import {
|
|
|
26
26
|
* derived from an image, so its subtree keeps what it inherited and the scrim
|
|
27
27
|
* plus an explicit light text colour carries the hero.
|
|
28
28
|
*
|
|
29
|
-
* The web Player
|
|
30
|
-
*
|
|
29
|
+
* The web Player and the export's generated layout renderer both call this,
|
|
30
|
+
* so the two hosts cannot differ here (CLAUDE.md §8).
|
|
31
31
|
*/
|
|
32
32
|
export function surfaceAwareTheme(tenantTheme, backgroundColor) {
|
|
33
33
|
const surfaceTokens = deriveSurfaceTokens(backgroundColor);
|
package/dist/switch.native.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// `<Switch>` (native). Binds ./switch-view.js to React Native's own
|
|
2
2
|
// primitives; only the import differs from ./switch.js.
|
|
3
3
|
|
|
4
|
-
import { View,
|
|
4
|
+
import { View, Pressable, Switch as PlatformSwitch } from "react-native";
|
|
5
|
+
import { Text } from "./bounded-text.native.js";
|
|
5
6
|
import { makeSwitch } from "./switch-view.js";
|
|
6
7
|
|
|
7
8
|
export const Switch = makeSwitch({ View, Text, Pressable, Switch: PlatformSwitch });
|
package/dist/tabs.native.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// `<Tabs>` (native). Binds ./tabs-view.js to React Native's own primitives;
|
|
2
2
|
// only the import differs from ./tabs.js.
|
|
3
3
|
|
|
4
|
-
import { View,
|
|
4
|
+
import { View, Pressable, ScrollView } from "react-native";
|
|
5
|
+
import { Text } from "./bounded-text.native.js";
|
|
5
6
|
import { makeTabs } from "./tabs-view.js";
|
|
6
7
|
|
|
7
8
|
export const Tabs = makeTabs({ View, Text, Pressable, ScrollView });
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// `<TextField>` (native). Binds ./text-field-view.js to React Native's own
|
|
2
2
|
// primitives; only the import differs from ./text-field.js.
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { View, Pressable } from "react-native";
|
|
5
|
+
import { TextInput, Text } from "./bounded-text.native.js";
|
|
5
6
|
import { makeTextField } from "./text-field-view.js";
|
|
6
7
|
|
|
7
8
|
export const TextField = makeTextField({ TextInput, View, Text, Pressable });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@colixsystems/widget-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.260.0",
|
|
4
4
|
"description": "Common widget interface for AppStudio. Implements WidgetManifest, WidgetContext, property schema, and helper hooks.",
|
|
5
5
|
"homepage": "https://github.com/Colix-AB/AppStudio",
|
|
6
6
|
"type": "module",
|
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
],
|
|
57
57
|
"scripts": {
|
|
58
58
|
"build": "node scripts/build.js",
|
|
59
|
+
"generate:contract": "node scripts/contract-cjs.js",
|
|
59
60
|
"test": "node --test \"src/__tests__/*.test.js\""
|
|
60
61
|
},
|
|
61
62
|
"engines": {
|
package/src/contract.js
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// export. The contract test asserts the two are identical (deep-equal) so
|
|
6
|
-
// drift between this file and the ESM source-of-truth is caught in CI.
|
|
7
|
-
//
|
|
8
|
-
// Keep edits in lockstep between `contract.cjs` and `contract.js`. The
|
|
9
|
-
// SDK build script copies both into `dist/`.
|
|
1
|
+
// The widget SDK contract: the ONE source the linter, the AI agents, the
|
|
2
|
+
// compiler and both hosts read. `contract.cjs` is GENERATED from `contract.js`
|
|
3
|
+
// (`npm run generate:contract`) for CommonJS consumers — never edit it by hand;
|
|
4
|
+
// contract-cjs-generated.test.js fails when it is stale.
|
|
10
5
|
|
|
11
6
|
// REQ-AI-AGENT-DESIGN (sc-3696): the ONE cross-platform elevation vocabulary.
|
|
12
7
|
// `shadow*` applies on iOS + react-native-web, `elevation` drives Android.
|
|
@@ -2645,7 +2640,7 @@ const HOOKS = [
|
|
|
2645
2640
|
scopes: ["users.write:*"],
|
|
2646
2641
|
},
|
|
2647
2642
|
// REQ-BANKID-AUTH — link / unlink a BankID identity to the signed-in
|
|
2648
|
-
// app-user. Self-service + JWT-gated (no widget scope).
|
|
2643
|
+
// app-user. Self-service + JWT-gated (no widget scope).
|
|
2649
2644
|
{
|
|
2650
2645
|
name: "useBankIdLink",
|
|
2651
2646
|
signature: "useBankIdLink()",
|
|
@@ -2681,7 +2676,7 @@ const HOOKS = [
|
|
|
2681
2676
|
scopes: null,
|
|
2682
2677
|
},
|
|
2683
2678
|
// REQ-IDENT (sc-4313) — identify a visitor who is NOT signed in and keep the
|
|
2684
|
-
// result. Anonymous by design (no widget scope, no session).
|
|
2679
|
+
// result. Anonymous by design (no widget scope, no session).
|
|
2685
2680
|
{
|
|
2686
2681
|
name: "useIdentification",
|
|
2687
2682
|
signature: "useIdentification(options)",
|
|
@@ -2732,7 +2727,7 @@ const HOOKS = [
|
|
|
2732
2727
|
scopes: null,
|
|
2733
2728
|
},
|
|
2734
2729
|
// REQ-ACL-06 / REQ-ACL-RELINHERIT-05 — per-record VirtualPermission
|
|
2735
|
-
// management for a single record.
|
|
2730
|
+
// management for a single record.
|
|
2736
2731
|
{
|
|
2737
2732
|
name: "useRecordPermissions",
|
|
2738
2733
|
signature: "useRecordPermissions(tableId, recordId)",
|
|
@@ -2865,7 +2860,7 @@ const HOOKS = [
|
|
|
2865
2860
|
requiredContextSlice: ["datastore.records"],
|
|
2866
2861
|
scopes: ["datastore.read:<table>"],
|
|
2867
2862
|
},
|
|
2868
|
-
// REQ-WSDK-PLATFORM §6 — Tier A SDK hooks.
|
|
2863
|
+
// REQ-WSDK-PLATFORM §6 — Tier A SDK hooks.
|
|
2869
2864
|
{
|
|
2870
2865
|
name: "useClipboard",
|
|
2871
2866
|
signature: "useClipboard()",
|
|
@@ -3701,6 +3696,10 @@ const ACTION_TRIGGER_TYPES = [
|
|
|
3701
3696
|
// Globals the action script runs against (the runner's surface) — distinct
|
|
3702
3697
|
// from the React/SDK widget surface, so the component import/banned-API
|
|
3703
3698
|
// linter does NOT scan action scripts.
|
|
3699
|
+
// sc-7877 deliberately does NOT add `directory` here. That global is
|
|
3700
|
+
// reachable only by a MARKETPLACE action whose install consented to a
|
|
3701
|
+
// `directory:` scope; a widget-declared action has no install, so
|
|
3702
|
+
// resolveForActionRow grants it nothing and the global is never defined.
|
|
3704
3703
|
const ACTION_SCRIPT_GLOBALS = [
|
|
3705
3704
|
"datastore",
|
|
3706
3705
|
"secrets",
|
|
@@ -4213,14 +4212,14 @@ const WIDGET_CONTEXT_SHAPE = {
|
|
|
4213
4212
|
required: true,
|
|
4214
4213
|
fields: { requestPayment: "function", getPayment: "function" },
|
|
4215
4214
|
},
|
|
4216
|
-
// sc-890 — backs useSendNotification().
|
|
4215
|
+
// sc-890 — backs useSendNotification().
|
|
4217
4216
|
notifications: {
|
|
4218
4217
|
description:
|
|
4219
4218
|
"Injected @colixsystems/notifications-client instance (sc-890). { send(body) -> Promise<notification>, mutes: { get, set, clear } }. send backs useSendNotification(); requires the notifications.send:appUser scope. The host POSTs the body snake_case verbatim ({ recipient_user_id, title, body, link?, payload? }) to /notifications/send and returns the created notification row; the call is imperative (a send never fires on mount). mutes backs useRecordMute() and useRecordMutes() (sc-10268): get({ table_id, record_id }) / set({ table_id, record_id, muted_until }) -> { muted, muted_until }, clear({ table_id, record_id }) -> undefined, list({ table_id, limit?, offset? }) -> { data: [{ record_id, muted_until }], meta }. mutes is optional — a host without it (the Builder canvas preview) leaves useRecordMute() reading not muted.",
|
|
4220
4219
|
required: true,
|
|
4221
4220
|
fields: { send: "function", mutes: "object" },
|
|
4222
4221
|
},
|
|
4223
|
-
// REQ-IDENT (sc-4313) — backs useIdentification().
|
|
4222
|
+
// REQ-IDENT (sc-4313) — backs useIdentification().
|
|
4224
4223
|
identification: {
|
|
4225
4224
|
description:
|
|
4226
4225
|
"Injected @colixsystems/identification-client instance (REQ-IDENT). { available() -> Promise<{ available, providers }>, start(body) -> Promise<order>, get(id) -> Promise<state>, cancel(id) -> Promise<state> }. Backs useIdentification(); no widget scope and no signed-in user required — identifying a NOT-signed-in visitor is the point, so the endpoints are anonymous. Bodies and rows are snake_case verbatim. A completed identification exposes name + personal_number_masked + a stable subject_hash; the RAW personal number is never reachable from a widget (it lives behind a studio-admin endpoint).",
|
|
@@ -4261,7 +4260,7 @@ const WIDGET_CONTEXT_SHAPE = {
|
|
|
4261
4260
|
error: "function",
|
|
4262
4261
|
},
|
|
4263
4262
|
},
|
|
4264
|
-
// REQ-WSDK-PLATFORM §6 — backs useToast().
|
|
4263
|
+
// REQ-WSDK-PLATFORM §6 — backs useToast().
|
|
4265
4264
|
toast: {
|
|
4266
4265
|
description:
|
|
4267
4266
|
"Optional host toast slot. { showToast({ kind, message }): void }. " +
|
|
@@ -4705,7 +4704,7 @@ const VETTED_IMPORTS = [
|
|
|
4705
4704
|
// `allowedBareImports` (so the loader's shim⊆vetted guard treats them as
|
|
4706
4705
|
// vetted) WITHOUT bloating the rich `VETTED_IMPORTS` reference the AI prompt /
|
|
4707
4706
|
// Developer guide enumerate — the SAME treatment `react/jsx-runtime` gets, but
|
|
4708
|
-
// kept out of the author-facing list.
|
|
4707
|
+
// kept out of the author-facing list.
|
|
4709
4708
|
const CORE_INFRA_BARE_IMPORTS = ["react-dom", "react-dom/client"];
|
|
4710
4709
|
|
|
4711
4710
|
// Back-compat shape — every existing consumer (widgetLoader, the static
|
|
@@ -6375,7 +6374,9 @@ const CONTRACT = deepFreeze({
|
|
|
6375
6374
|
// `<testID>-option-<id>`.
|
|
6376
6375
|
// 1.210.0: behaviour (sc-12245) — `<Avatar url>` falls back to the
|
|
6377
6376
|
// initials when its picture fails to load. No API change.
|
|
6378
|
-
|
|
6377
|
+
// 1.211.0: additive (sc-9168) — `maxFontSizeMultiplier`: native `<Text>` /
|
|
6378
|
+
// `<TextInput>` follow the device font scale up to this bound.
|
|
6379
|
+
version: "1.211.0",
|
|
6379
6380
|
sharedTranslationKeys: SHARED_TRANSLATION_KEYS,
|
|
6380
6381
|
hooks: HOOKS,
|
|
6381
6382
|
primitives: PRIMITIVES,
|
|
@@ -6404,6 +6405,10 @@ const CONTRACT = deepFreeze({
|
|
|
6404
6405
|
bundleExportContract: BUNDLE_EXPORT_CONTRACT,
|
|
6405
6406
|
// sc-10829 — the hook a `badgeCounter: true` entry exports by name.
|
|
6406
6407
|
badgeCounterExport: "useBadgeCount",
|
|
6408
|
+
// sc-9168 — the most native text grows with the device font-scale setting.
|
|
6409
|
+
// Above it a layout sized against the Player overflows; the browser has no
|
|
6410
|
+
// such setting to preview it with.
|
|
6411
|
+
maxFontSizeMultiplier: 1.3,
|
|
6407
6412
|
bannedApis: BANNED_APIS,
|
|
6408
6413
|
vettedImports: VETTED_IMPORTS,
|
|
6409
6414
|
allowedBareImports: ALLOWED_BARE_IMPORTS,
|