@colixsystems/widget-sdk 0.21.1 → 0.23.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 +29 -1
- package/dist/contract.cjs +103 -1
- package/dist/contract.js +103 -1
- package/dist/index.d.ts +15 -0
- package/dist/property-schema.js +25 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -45,7 +45,35 @@ See the design reference for the full architecture: [`docs/architecture/widget-m
|
|
|
45
45
|
|
|
46
46
|
## Status
|
|
47
47
|
|
|
48
|
-
`v0.
|
|
48
|
+
`v0.23.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**.
|
|
49
|
+
|
|
50
|
+
### What's new in 0.23.0
|
|
51
|
+
|
|
52
|
+
**Curated cross-platform package expansion to the vetted import allowlist (REQ-WSDK-PKG-EXPAND).**
|
|
53
|
+
|
|
54
|
+
- The linter's vetted import allowlist (`CONTRACT.vettedImports`) gains a curated set of popular React Native packages, each of which runs on **both** web and native (directly, or via a documented platform-split counterpart):
|
|
55
|
+
- **`react-native-reanimated`** (`web`/`native`) — declarative animations.
|
|
56
|
+
- **`react-native-gesture-handler`** (`web`/`native`) — native-driven touch gestures.
|
|
57
|
+
- **`react-native-safe-area-context`** (`web`/`native`) — safe-area insets.
|
|
58
|
+
- **`@shopify/flash-list`** (`web`/`native`) — high-performance virtualised list.
|
|
59
|
+
- **`react-native-paper`** (`web`/`native`) — Material Design components.
|
|
60
|
+
- **`react-native-vector-icons`** (`web`/`native`) — icon font families.
|
|
61
|
+
- **`@react-native-community/slider`** (`web`/`native`) — slider input.
|
|
62
|
+
- **`expo-linear-gradient`** (`web`/`native`) — the cross-platform gradient.
|
|
63
|
+
- **`lottie-react-native`** (`native`) + **`lottie-react`** (`web`) — Lottie animations, split-impl.
|
|
64
|
+
- **`react-native-webview`** (`native`) — embedded web content (pair with an `<iframe>` on web).
|
|
65
|
+
- **Parity (CLAUDE.md §3):** the compiler now pins the native-module members in the exported Expo app's `package.json` and emits the **`react-native-reanimated/plugin`** in `babel.config.js` **unconditionally** (previously only for the sidebar-drawer shell), so a baked widget that imports any of these resolves and bundles on native exactly as it renders in the web Player.
|
|
66
|
+
- **`CONTRACT.version` → `1.13.0`** (additive: new vetted import entries only). No existing export, type, manifest field, hook, or banned-API list changed.
|
|
67
|
+
|
|
68
|
+
### What's new in 0.22.0
|
|
69
|
+
|
|
70
|
+
**New `valueRef` propertySchema type — bind a widget to a single value in the datastore (REQ-WDG-VALUEREF).**
|
|
71
|
+
|
|
72
|
+
- **`valueRef`** is a composite picker: the Studio Properties Panel renders three cascading dropdowns — pick a **table**, then a **record**, then a **column** — and the bound widget resolves the one cell. It is the discoverable replacement for hand-typing a `tableRef` + a raw record-id `string` + a `columnRef` separately (the old Field Value shape).
|
|
73
|
+
- **Persisted value is an object** `{ tableId, recordId, column }` (new `ValueRefBinding` type), unlike every other ref type, which is a bare string. A widget reads it with `useDatastoreRecord(value.tableId, value.recordId)` then `record[value.column]`; any missing piece means "no value".
|
|
74
|
+
- **tenant-copy** remaps `tableId` to the copied table and **nulls `recordId`** (records are business data and are never copied), so a copied workspace shows the widget's fallback until the new operator re-picks a record. `column` (a name) is preserved verbatim.
|
|
75
|
+
- The built-in **Field Value** widget now uses `valueRef` (back-compatible: already-saved Field Value widgets that stored `tableId`/`recordId`/`column` as separate props keep rendering).
|
|
76
|
+
- **`CONTRACT.version` → `1.12.0`** (additive: one new optional propertySchema type). No existing export or type changed signature.
|
|
49
77
|
|
|
50
78
|
### What's new in 0.21.1
|
|
51
79
|
|
package/dist/contract.cjs
CHANGED
|
@@ -913,6 +913,89 @@ const VETTED_IMPORTS = [
|
|
|
913
913
|
description:
|
|
914
914
|
"Native haptic feedback. Pair with navigator.vibrate in widget.web.jsx.",
|
|
915
915
|
},
|
|
916
|
+
// REQ-WSDK-PKG-EXPAND — curated cross-platform package expansion. Each entry
|
|
917
|
+
// below runs on web AND native (directly, or via the documented platform-split
|
|
918
|
+
// counterpart). Native-module packages additionally carry a pinned version in
|
|
919
|
+
// the compiler's generatePackageJson so a baked marketplace widget resolves in
|
|
920
|
+
// the Expo export (CLAUDE.md §3 parity). See the `adding-vetted-packages` skill
|
|
921
|
+
// for the full add checklist (contract ×2, version bump, compiler pin, docs).
|
|
922
|
+
{
|
|
923
|
+
specifier: "react-native-reanimated",
|
|
924
|
+
platforms: ["web", "native"],
|
|
925
|
+
category: "animation",
|
|
926
|
+
description:
|
|
927
|
+
"Declarative, performant animations. Works on both platforms; the export always emits the required react-native-reanimated/plugin in babel.config.js so a widget using worklets bundles on native.",
|
|
928
|
+
},
|
|
929
|
+
{
|
|
930
|
+
specifier: "react-native-gesture-handler",
|
|
931
|
+
platforms: ["web", "native"],
|
|
932
|
+
category: "gesture",
|
|
933
|
+
description:
|
|
934
|
+
"Native-driven touch gestures (pan, pinch, swipe, long-press). Works on both platforms; wrap interactive trees in GestureHandlerRootView.",
|
|
935
|
+
},
|
|
936
|
+
{
|
|
937
|
+
specifier: "react-native-safe-area-context",
|
|
938
|
+
platforms: ["web", "native"],
|
|
939
|
+
category: "layout",
|
|
940
|
+
description:
|
|
941
|
+
"Safe-area insets (notch / status bar). useSafeAreaInsets() returns zeros on web and the real insets on native, so the same layout code is safe on both.",
|
|
942
|
+
},
|
|
943
|
+
{
|
|
944
|
+
specifier: "@shopify/flash-list",
|
|
945
|
+
platforms: ["web", "native"],
|
|
946
|
+
category: "list",
|
|
947
|
+
description:
|
|
948
|
+
"High-performance virtualised list with a FlatList-compatible API. Prefer it over FlatList for long datasets; renders on both platforms.",
|
|
949
|
+
},
|
|
950
|
+
{
|
|
951
|
+
specifier: "react-native-paper",
|
|
952
|
+
platforms: ["web", "native"],
|
|
953
|
+
category: "ui",
|
|
954
|
+
description:
|
|
955
|
+
"Material Design component library built on react-native + react-native-web, so the same components render identically on both platforms.",
|
|
956
|
+
},
|
|
957
|
+
{
|
|
958
|
+
specifier: "react-native-vector-icons",
|
|
959
|
+
platforms: ["web", "native"],
|
|
960
|
+
category: "iconography",
|
|
961
|
+
description:
|
|
962
|
+
"Icon font families (MaterialIcons, FontAwesome, Ionicons, …). Works on both platforms; prefer the SDK's <Icon> (lucide) primitive for the common case.",
|
|
963
|
+
},
|
|
964
|
+
{
|
|
965
|
+
specifier: "@react-native-community/slider",
|
|
966
|
+
platforms: ["web", "native"],
|
|
967
|
+
category: "input",
|
|
968
|
+
description:
|
|
969
|
+
"Cross-platform slider input. Controlled — value + onValueChange. Works on both platforms.",
|
|
970
|
+
},
|
|
971
|
+
{
|
|
972
|
+
specifier: "expo-linear-gradient",
|
|
973
|
+
platforms: ["web", "native"],
|
|
974
|
+
category: "drawing",
|
|
975
|
+
description:
|
|
976
|
+
"Linear-gradient fill (<LinearGradient colors={[...]} />). The cross-platform gradient — works on both platforms (react-native-linear-gradient is native-only; prefer this).",
|
|
977
|
+
},
|
|
978
|
+
{
|
|
979
|
+
specifier: "lottie-react-native",
|
|
980
|
+
platforms: ["native"],
|
|
981
|
+
category: "animation",
|
|
982
|
+
description:
|
|
983
|
+
"After Effects (Bodymovin) JSON animations. Native-only; pair with lottie-react in widget.web.jsx for the web variant.",
|
|
984
|
+
},
|
|
985
|
+
{
|
|
986
|
+
specifier: "lottie-react",
|
|
987
|
+
platforms: ["web"],
|
|
988
|
+
category: "animation",
|
|
989
|
+
description:
|
|
990
|
+
"Web Lottie player. Web-only counterpart to lottie-react-native; bundle it into widget.web.jsx.",
|
|
991
|
+
},
|
|
992
|
+
{
|
|
993
|
+
specifier: "react-native-webview",
|
|
994
|
+
platforms: ["native"],
|
|
995
|
+
category: "media",
|
|
996
|
+
description:
|
|
997
|
+
"Embeds web content in a native WebView. Native-only; on web render an <iframe> (or a View with the URL) in widget.web.jsx.",
|
|
998
|
+
},
|
|
916
999
|
];
|
|
917
1000
|
|
|
918
1001
|
// Back-compat shape — every existing consumer (widgetLoader, the static
|
|
@@ -1034,7 +1117,26 @@ const CONTRACT = deepFreeze({
|
|
|
1034
1117
|
// widgets in coral until a first save persisted the blue — a divergence
|
|
1035
1118
|
// between the unsaved and saved-defaults render. Aligning the canonical
|
|
1036
1119
|
// tokens removes it (no shape/signature change — default-value fix only).
|
|
1037
|
-
|
|
1120
|
+
//
|
|
1121
|
+
// 1.12.0: additive (REQ-WDG-VALUEREF) — new `valueRef` propertySchema type.
|
|
1122
|
+
// A composite "single value from the datastore" picker whose persisted
|
|
1123
|
+
// value is an object `{ tableId, recordId, column }` (every other ref
|
|
1124
|
+
// type is a bare string). The Studio Properties Panel renders three
|
|
1125
|
+
// cascading dropdowns; tenant-copy remaps `tableId` and nulls `recordId`
|
|
1126
|
+
// (records are business data, never copied). No existing type changed
|
|
1127
|
+
// shape, so this is additive — minor bump on the pre-1.0 channel.
|
|
1128
|
+
//
|
|
1129
|
+
// 1.13.0: additive (REQ-WSDK-PKG-EXPAND) — the vetted import allowlist gains
|
|
1130
|
+
// a curated cross-platform package set: react-native-reanimated,
|
|
1131
|
+
// react-native-gesture-handler, react-native-safe-area-context,
|
|
1132
|
+
// @shopify/flash-list, react-native-paper, react-native-vector-icons,
|
|
1133
|
+
// @react-native-community/slider, expo-linear-gradient, react-native-webview,
|
|
1134
|
+
// and lottie-react-native (+ lottie-react as its web counterpart). No
|
|
1135
|
+
// existing entry changed shape and no other contract field moved, so this
|
|
1136
|
+
// is additive — minor bump on the pre-1.0 channel. The compiler pins the
|
|
1137
|
+
// native-module members in the exported Expo app's package.json and now
|
|
1138
|
+
// always emits the react-native-reanimated/plugin (CLAUDE.md §3 parity).
|
|
1139
|
+
version: "1.13.0",
|
|
1038
1140
|
hooks: HOOKS,
|
|
1039
1141
|
primitives: PRIMITIVES,
|
|
1040
1142
|
manifestSchema: MANIFEST_SCHEMA,
|
package/dist/contract.js
CHANGED
|
@@ -896,6 +896,89 @@ const VETTED_IMPORTS = [
|
|
|
896
896
|
description:
|
|
897
897
|
"Native haptic feedback. Pair with navigator.vibrate in widget.web.jsx.",
|
|
898
898
|
},
|
|
899
|
+
// REQ-WSDK-PKG-EXPAND — curated cross-platform package expansion. Each entry
|
|
900
|
+
// below runs on web AND native (directly, or via the documented platform-split
|
|
901
|
+
// counterpart). Native-module packages additionally carry a pinned version in
|
|
902
|
+
// the compiler's generatePackageJson so a baked marketplace widget resolves in
|
|
903
|
+
// the Expo export (CLAUDE.md §3 parity). See the `adding-vetted-packages` skill
|
|
904
|
+
// for the full add checklist (contract ×2, version bump, compiler pin, docs).
|
|
905
|
+
{
|
|
906
|
+
specifier: "react-native-reanimated",
|
|
907
|
+
platforms: ["web", "native"],
|
|
908
|
+
category: "animation",
|
|
909
|
+
description:
|
|
910
|
+
"Declarative, performant animations. Works on both platforms; the export always emits the required react-native-reanimated/plugin in babel.config.js so a widget using worklets bundles on native.",
|
|
911
|
+
},
|
|
912
|
+
{
|
|
913
|
+
specifier: "react-native-gesture-handler",
|
|
914
|
+
platforms: ["web", "native"],
|
|
915
|
+
category: "gesture",
|
|
916
|
+
description:
|
|
917
|
+
"Native-driven touch gestures (pan, pinch, swipe, long-press). Works on both platforms; wrap interactive trees in GestureHandlerRootView.",
|
|
918
|
+
},
|
|
919
|
+
{
|
|
920
|
+
specifier: "react-native-safe-area-context",
|
|
921
|
+
platforms: ["web", "native"],
|
|
922
|
+
category: "layout",
|
|
923
|
+
description:
|
|
924
|
+
"Safe-area insets (notch / status bar). useSafeAreaInsets() returns zeros on web and the real insets on native, so the same layout code is safe on both.",
|
|
925
|
+
},
|
|
926
|
+
{
|
|
927
|
+
specifier: "@shopify/flash-list",
|
|
928
|
+
platforms: ["web", "native"],
|
|
929
|
+
category: "list",
|
|
930
|
+
description:
|
|
931
|
+
"High-performance virtualised list with a FlatList-compatible API. Prefer it over FlatList for long datasets; renders on both platforms.",
|
|
932
|
+
},
|
|
933
|
+
{
|
|
934
|
+
specifier: "react-native-paper",
|
|
935
|
+
platforms: ["web", "native"],
|
|
936
|
+
category: "ui",
|
|
937
|
+
description:
|
|
938
|
+
"Material Design component library built on react-native + react-native-web, so the same components render identically on both platforms.",
|
|
939
|
+
},
|
|
940
|
+
{
|
|
941
|
+
specifier: "react-native-vector-icons",
|
|
942
|
+
platforms: ["web", "native"],
|
|
943
|
+
category: "iconography",
|
|
944
|
+
description:
|
|
945
|
+
"Icon font families (MaterialIcons, FontAwesome, Ionicons, …). Works on both platforms; prefer the SDK's <Icon> (lucide) primitive for the common case.",
|
|
946
|
+
},
|
|
947
|
+
{
|
|
948
|
+
specifier: "@react-native-community/slider",
|
|
949
|
+
platforms: ["web", "native"],
|
|
950
|
+
category: "input",
|
|
951
|
+
description:
|
|
952
|
+
"Cross-platform slider input. Controlled — value + onValueChange. Works on both platforms.",
|
|
953
|
+
},
|
|
954
|
+
{
|
|
955
|
+
specifier: "expo-linear-gradient",
|
|
956
|
+
platforms: ["web", "native"],
|
|
957
|
+
category: "drawing",
|
|
958
|
+
description:
|
|
959
|
+
"Linear-gradient fill (<LinearGradient colors={[...]} />). The cross-platform gradient — works on both platforms (react-native-linear-gradient is native-only; prefer this).",
|
|
960
|
+
},
|
|
961
|
+
{
|
|
962
|
+
specifier: "lottie-react-native",
|
|
963
|
+
platforms: ["native"],
|
|
964
|
+
category: "animation",
|
|
965
|
+
description:
|
|
966
|
+
"After Effects (Bodymovin) JSON animations. Native-only; pair with lottie-react in widget.web.jsx for the web variant.",
|
|
967
|
+
},
|
|
968
|
+
{
|
|
969
|
+
specifier: "lottie-react",
|
|
970
|
+
platforms: ["web"],
|
|
971
|
+
category: "animation",
|
|
972
|
+
description:
|
|
973
|
+
"Web Lottie player. Web-only counterpart to lottie-react-native; bundle it into widget.web.jsx.",
|
|
974
|
+
},
|
|
975
|
+
{
|
|
976
|
+
specifier: "react-native-webview",
|
|
977
|
+
platforms: ["native"],
|
|
978
|
+
category: "media",
|
|
979
|
+
description:
|
|
980
|
+
"Embeds web content in a native WebView. Native-only; on web render an <iframe> (or a View with the URL) in widget.web.jsx.",
|
|
981
|
+
},
|
|
899
982
|
];
|
|
900
983
|
|
|
901
984
|
const ALLOWED_BARE_IMPORTS = VETTED_IMPORTS.map((v) => v.specifier);
|
|
@@ -987,7 +1070,26 @@ const CONTRACT = deepFreeze({
|
|
|
987
1070
|
// widgets in coral until a first save persisted the blue — a divergence
|
|
988
1071
|
// between the unsaved and saved-defaults render. Aligning the canonical
|
|
989
1072
|
// tokens removes it (no shape/signature change — default-value fix only).
|
|
990
|
-
|
|
1073
|
+
//
|
|
1074
|
+
// 1.12.0: additive (REQ-WDG-VALUEREF) — new `valueRef` propertySchema type.
|
|
1075
|
+
// A composite "single value from the datastore" picker whose persisted
|
|
1076
|
+
// value is an object `{ tableId, recordId, column }` (every other ref
|
|
1077
|
+
// type is a bare string). The Studio Properties Panel renders three
|
|
1078
|
+
// cascading dropdowns; tenant-copy remaps `tableId` and nulls `recordId`
|
|
1079
|
+
// (records are business data, never copied). No existing type changed
|
|
1080
|
+
// shape, so this is additive — minor bump on the pre-1.0 channel.
|
|
1081
|
+
//
|
|
1082
|
+
// 1.13.0: additive (REQ-WSDK-PKG-EXPAND) — the vetted import allowlist gains
|
|
1083
|
+
// a curated cross-platform package set: react-native-reanimated,
|
|
1084
|
+
// react-native-gesture-handler, react-native-safe-area-context,
|
|
1085
|
+
// @shopify/flash-list, react-native-paper, react-native-vector-icons,
|
|
1086
|
+
// @react-native-community/slider, expo-linear-gradient, react-native-webview,
|
|
1087
|
+
// and lottie-react-native (+ lottie-react as its web counterpart). No
|
|
1088
|
+
// existing entry changed shape and no other contract field moved, so this
|
|
1089
|
+
// is additive — minor bump on the pre-1.0 channel. The compiler pins the
|
|
1090
|
+
// native-module members in the exported Expo app's package.json and now
|
|
1091
|
+
// always emits the react-native-reanimated/plugin (CLAUDE.md §3 parity).
|
|
1092
|
+
version: "1.13.0",
|
|
991
1093
|
hooks: HOOKS,
|
|
992
1094
|
primitives: PRIMITIVES,
|
|
993
1095
|
manifestSchema: MANIFEST_SCHEMA,
|
package/dist/index.d.ts
CHANGED
|
@@ -29,6 +29,10 @@ export type WidgetPropertyType =
|
|
|
29
29
|
| "tableRef"
|
|
30
30
|
| "columnRef"
|
|
31
31
|
| "recordBinding"
|
|
32
|
+
// REQ-WDG-VALUEREF: composite "single value from the datastore" picker.
|
|
33
|
+
// Persisted value is `{ tableId, recordId, column }`; the bound widget
|
|
34
|
+
// resolves the one cell.
|
|
35
|
+
| "valueRef"
|
|
32
36
|
// REQ-USERMGMT M4 / §4.8: Group picker that emits a bare
|
|
33
37
|
// AppUserGroup UUID into the page JSON.
|
|
34
38
|
| "groupRef"
|
|
@@ -56,6 +60,17 @@ export interface WidgetPropertyDef {
|
|
|
56
60
|
|
|
57
61
|
export type WidgetPropertySchema = Record<string, WidgetPropertyDef>;
|
|
58
62
|
|
|
63
|
+
/**
|
|
64
|
+
* REQ-WDG-VALUEREF: the persisted value of a `valueRef` property. Each
|
|
65
|
+
* field is optional while the author is mid-pick; a widget treats any
|
|
66
|
+
* missing piece as "no value".
|
|
67
|
+
*/
|
|
68
|
+
export interface ValueRefBinding {
|
|
69
|
+
tableId?: string;
|
|
70
|
+
recordId?: string;
|
|
71
|
+
column?: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
59
74
|
export interface WidgetEventDescriptor {
|
|
60
75
|
name: string;
|
|
61
76
|
description?: string;
|
package/dist/property-schema.js
CHANGED
|
@@ -6,6 +6,14 @@ const VALID_TYPES = new Set([
|
|
|
6
6
|
"color", "icon", "image",
|
|
7
7
|
"select", "multiselect",
|
|
8
8
|
"tableRef", "columnRef", "recordBinding",
|
|
9
|
+
// REQ-WDG-VALUEREF: `valueRef` is a composite "single value from the
|
|
10
|
+
// datastore" picker. Unlike the bare-string refs above, its persisted
|
|
11
|
+
// value is an OBJECT `{ tableId, recordId, column }` — the author picks a
|
|
12
|
+
// table, then a record, then a column, and the bound widget resolves the
|
|
13
|
+
// one cell. The Studio Properties Panel renders three cascading dropdowns
|
|
14
|
+
// (`ValueRefEditor`). tenant-copy remaps `tableId` and NULLS `recordId`
|
|
15
|
+
// (records are business data, never copied) — see tenant-copy.service.js.
|
|
16
|
+
"valueRef",
|
|
9
17
|
// REQ-USERMGMT M4 / §4.8: `groupRef` is a Group picker that emits a bare
|
|
10
18
|
// AppUserGroup UUID into the page JSON. Renders via `GroupSelector` in
|
|
11
19
|
// the Studio Properties Panel. REQ-GEN-07 compliance: no typed UUIDs —
|
|
@@ -134,6 +142,23 @@ function coerceLeaf(def, value, path, errors) {
|
|
|
134
142
|
return value;
|
|
135
143
|
}
|
|
136
144
|
return value.map((item, i) => coerceLeaf(def.items, item, `${path}[${i}]`, errors));
|
|
145
|
+
case "valueRef": {
|
|
146
|
+
// REQ-WDG-VALUEREF: a `{ tableId, recordId, column }` binding. Each
|
|
147
|
+
// sub-field is an optional string (a half-configured binding is valid
|
|
148
|
+
// while the author is still picking); the bound widget treats any
|
|
149
|
+
// missing piece as "no value" and shows its fallback.
|
|
150
|
+
if (!isPlainObject(value)) {
|
|
151
|
+
errors.push(`${path}: expected object`);
|
|
152
|
+
return value;
|
|
153
|
+
}
|
|
154
|
+
for (const sub of ["tableId", "recordId", "column"]) {
|
|
155
|
+
const v = value[sub];
|
|
156
|
+
if (v !== undefined && v !== null && typeof v !== "string") {
|
|
157
|
+
errors.push(`${path}.${sub}: expected string`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return value;
|
|
161
|
+
}
|
|
137
162
|
case "object": {
|
|
138
163
|
if (!isPlainObject(value)) {
|
|
139
164
|
errors.push(`${path}: expected object`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@colixsystems/widget-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.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",
|