@colixsystems/widget-sdk 0.56.0 → 0.58.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 CHANGED
@@ -52,11 +52,19 @@ See the design reference for the full architecture: [`docs/architecture/widget-m
52
52
 
53
53
  ## Status
54
54
 
55
- `v0.55.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**.
55
+ `v0.58.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.58.0
58
+
59
+ **Filter the directory by group (sc-2964).** `useDirectory(query?)` and `useUsers(query?)` gain an optional `group_id` on the query object (`{ q?, role?, is_active?, group_id?, limit?, offset? }`). Pass the `id` of a `useGroups()` row to list only that group's members — pair it with a group picker to build "members of group X". A `group_id` from another tenant or a non-existent one returns an empty roster, never a cross-tenant member. The `DirectoryQuery` / `UsersQuery` types add `group_id?: string`; existing callers pass no `group_id` and see the full roster. No scope, manifest field, import, or hook signature changed — `CONTRACT` is unchanged; the query flows verbatim through the injected `@colixsystems/directory-client` on both the web Player and the native Expo export.
60
+
61
+ ### What's new in 0.57.0
62
+
63
+ **A `required: true` `tableRef` must ship a matching `datastoreTemplate` table (sc-2791).** A widget property that the author cannot skip — a `tableRef` you mark `required: true` — must have a table to bind on install, or the end user has nothing to pick and the widget can't load its data. The marketplace analyzer now enforces this at publish: the check `manifest.requiredTableRefsHaveTemplate` rejects a manifest whose `datastoreTemplate.tables` count is fewer than its `required` `tableRef` property count, naming the offending properties. Two ways to clear it: seed a `datastoreTemplate` table for each required `tableRef` (the default — the widget owns its data), OR make the property **optional** when it binds a table the app already owns (shared data the user names). This tightens the existing "always ship a `datastoreTemplate` for a data widget" guidance into an enforced rule for the `required` case. No export, type, or hook changed shape — additive publish-gate + documentation. `CONTRACT` is unchanged (no new field).
56
64
 
57
65
  ### What's new in 0.55.0
58
66
 
59
- **Dynamic record selection for `valueRef` (sc-2327).** The `valueRef` binding gains an optional `mode` field: `"static"` (the default — pin a specific `recordId`, the only prior behaviour) or `"latest"` (resolve the most recently created row live, sorting on the host-managed `created_at` descending with `limit: 1`; `recordId` is ignored). The built-in Field Value widget reads it to offer a "Latest entry" that updates as records are added, with no per-host code — the same baked widget source and the same injected `@colixsystems/datastore-client` run on the web Player and the native Expo export. The `ValueRefBinding` type adds `mode?: "static" | "latest"`. Existing bindings carry no `mode` and read as static. `CONTRACT.version` → `1.39.0`. Additive — no existing field changed shape.
67
+ **Dynamic record selection for `valueRef` (sc-2327).** The `valueRef` binding gains an optional `mode` field: `"static"` (the default — pin a specific `recordId`, the only prior behaviour) or `"latest"` (resolve the most recently created row live, sorting on the host-managed `created_at` descending with `limit: 1`; `recordId` is ignored). The built-in Data Value widget reads it to offer a "Latest entry" that updates as records are added, with no per-host code — the same baked widget source and the same injected `@colixsystems/datastore-client` run on the web Player and the native Expo export. The `ValueRefBinding` type adds `mode?: "static" | "latest"`. Existing bindings carry no `mode` and read as static. `CONTRACT.version` → `1.39.0`. Additive — no existing field changed shape.
60
68
 
61
69
  ### What's new in 0.56.0
62
70
 
@@ -127,7 +135,7 @@ See the design reference for the full architecture: [`docs/architecture/widget-m
127
135
 
128
136
  ### What's new in 0.42.0
129
137
 
130
- **RELATION columns hydrate with a display label (sc-1181).** Record reads now return `{ id, label }` for ONE_TO_ONE / ONE_TO_MANY and `[{ id, label }, ...]` for MANY_TO_MANY (empty array when no links) — `label` is the value of the column pointed at by the new optional `display_column_id` on `DatastoreSchemaColumn`, or, when unset, the first STRING/TEXT column on the target table. Widgets should render `record.<rel>.label` (or `record.<rel>.map(r => r.label).join(", ")` for M:M) directly; `.id` is still there for the foreign-key case. The cell-formatting helpers in the built-in `DataList` and `FieldValue` widgets already walk arrays and prefer `label` over `name` / `id` — author widgets that need the same can copy that pattern. `CONTRACT.version` is unchanged.
138
+ **RELATION columns hydrate with a display label (sc-1181).** Record reads now return `{ id, label }` for ONE_TO_ONE / ONE_TO_MANY and `[{ id, label }, ...]` for MANY_TO_MANY (empty array when no links) — `label` is the value of the column pointed at by the new optional `display_column_id` on `DatastoreSchemaColumn`, or, when unset, the first STRING/TEXT column on the target table. Widgets should render `record.<rel>.label` (or `record.<rel>.map(r => r.label).join(", ")` for M:M) directly; `.id` is still there for the foreign-key case. The cell-formatting helpers in the built-in `DataList` and `DataValue` widgets already walk arrays and prefer `label` over `name` / `id` — author widgets that need the same can copy that pattern. `CONTRACT.version` is unchanged.
131
139
 
132
140
  ### What's new in 0.41.0
133
141
 
@@ -254,10 +262,10 @@ Also: `useFileSignatures(fileIds)` is now **self-scoped** (the caller's own sign
254
262
 
255
263
  **New `valueRef` propertySchema type — bind a widget to a single value in the datastore (REQ-WDG-VALUEREF).**
256
264
 
257
- - **`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).
265
+ - **`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 Data Value shape).
258
266
  - **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".
259
267
  - **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.
260
- - 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).
268
+ - The built-in **Data Value** widget now uses `valueRef` (back-compatible: already-saved Data Value widgets that stored `tableId`/`recordId`/`column` as separate props keep rendering).
261
269
  - **`CONTRACT.version` → `1.12.0`** (additive: one new optional propertySchema type). No existing export or type changed signature.
262
270
 
263
271
  ### What's new in 0.21.1
@@ -450,6 +458,7 @@ A widget that works but looks unfinished is only half done. `useTheme()` is the
450
458
 
451
459
  - **Pull spacing and corners from tokens.** Use `theme.spacing` (`xs / sm / md / lg / xl`) for a consistent padding and gap rhythm, and `theme.radii` (`sm / md / lg / pill`) for corners. Don't hardcode raw pixel values.
452
460
  - **Build a hierarchy.** A clear title (large, bold, `colors.onSurface`), body text, and muted captions in `colors.onSurfaceMuted` — three weights, not one flat size. Reserve `colors.primary` (with `colors.onPrimary` for text on it) for the single most important action or metric.
461
+ - **Set the theme font on every `Text`.** React Native `Text` does not inherit `fontFamily` from a parent, so a text element that omits it falls back to the system font and ignores the workspace's configured font. Put `theme.typography.fontFamily` on every text style (a shared `StyleSheet` built from `theme` keeps it in one place) and size text with `theme.typography.sizes`.
453
462
  - **Contain and elevate.** Wrap a logical unit in a surface: `colors.surface` + padding + `radii.md` + a `colors.border` hairline or a subtle shadow. Use the status roles (`danger / success / warning / info`) for state.
454
463
  - **Respond to touch.** Give every `Pressable` a pressed state via the function-style `style={({ pressed }) => [base, pressed && { opacity: 0.7 }]}`.
455
464
  - **Use icons for clarity.** Pair a `lucide-react-native` icon with its label at a consistent size, coloured from the theme.
package/dist/contract.cjs CHANGED
@@ -1862,7 +1862,7 @@ const CONTRACT = deepFreeze({
1862
1862
  // an optional `mode` field: "static" (a pinned recordId, the default and
1863
1863
  // the only prior behaviour) or "latest" (the most recently created row,
1864
1864
  // resolved live by `created_at` desc with limit 1; recordId ignored). The
1865
- // Field Value widget reads it to show a live "latest entry". Existing
1865
+ // Data Value widget reads it to show a live "latest entry". Existing
1866
1866
  // bindings have no `mode` and read as static — additive, minor bump.
1867
1867
  version: "1.39.0",
1868
1868
  sharedTranslationKeys: SHARED_TRANSLATION_KEYS,
package/dist/contract.js CHANGED
@@ -1862,7 +1862,7 @@ const CONTRACT = deepFreeze({
1862
1862
  // an optional `mode` field: "static" (a pinned recordId, the default and
1863
1863
  // the only prior behaviour) or "latest" (the most recently created row,
1864
1864
  // resolved live by `created_at` desc with limit 1; recordId ignored). The
1865
- // Field Value widget reads it to show a live "latest entry". Existing
1865
+ // Data Value widget reads it to show a live "latest entry". Existing
1866
1866
  // bindings have no `mode` and read as static — additive, minor bump.
1867
1867
  version: "1.39.0",
1868
1868
  sharedTranslationKeys: SHARED_TRANSLATION_KEYS,
package/dist/hooks.js CHANGED
@@ -2221,8 +2221,10 @@ function toDirectoryError(err) {
2221
2221
  * users is NOT part of this surface; the directory is read-only here (see
2222
2222
  * useUsers for administration).
2223
2223
  *
2224
- * `query` is an optional `{ q?, role?, is_active?, limit?, offset? }`
2225
- * object passed through verbatim. The hook re-fetches whenever
2224
+ * `query` is an optional `{ q?, role?, is_active?, group_id?, limit?, offset? }`
2225
+ * object passed through verbatim. `group_id` (the `id` of a `useGroups()` row)
2226
+ * restricts the roster to that group's members — pair it with a group picker to
2227
+ * build "members of group X". The hook re-fetches whenever
2226
2228
  * `JSON.stringify(query)` changes and exposes `refetch` for on-demand
2227
2229
  * reloads (e.g. a chat roster refresh).
2228
2230
  *
@@ -2300,8 +2302,10 @@ export function useDirectory(query) {
2300
2302
  * invite, deactivate, reactivate}` — `list` resolves to the `{ data, meta }`
2301
2303
  * envelope VERBATIM, so we unwrap `res.data` (default `[]`). User rows are
2302
2304
  * snake_case (`id`, `name`, `email`, `role`, `is_active`, …) and bodies
2303
- * (e.g. `{ email, name, group_ids? }`) pass through verbatim. The list
2304
- * refetches whenever `JSON.stringify(query)` changes; the imperative methods
2305
+ * (e.g. `{ email, name, group_ids? }`) pass through verbatim. `query` is an
2306
+ * optional `{ q?, role?, is_active?, group_id?, limit?, offset? }`; `group_id`
2307
+ * (the `id` of a `useGroups()` row) narrows the list to that group's members.
2308
+ * The list refetches whenever `JSON.stringify(query)` changes; the imperative methods
2305
2309
  * reject with a `DirectoryError`. Reads require the `users.read:*` scope;
2306
2310
  * mutations additionally require `users.write:*`. The host's signed
2307
2311
  * `X-Widget-Scopes` header + a tenant-scoped SystemAcl `users.read` /
package/dist/index.d.ts CHANGED
@@ -585,6 +585,11 @@ export interface DirectoryQuery {
585
585
  role?: "USER" | "INTEGRATION" | "ALL";
586
586
  /** Filter by active state (snake_case on the wire). */
587
587
  is_active?: boolean;
588
+ /**
589
+ * Restrict the roster to members of one app-user group — the `id` of a
590
+ * `useGroups()` row. Pair with a group picker to build "members of group X".
591
+ */
592
+ group_id?: string;
588
593
  limit?: number;
589
594
  offset?: number;
590
595
  }
@@ -1082,6 +1087,8 @@ export interface UsersQuery {
1082
1087
  q?: string;
1083
1088
  role?: "USER" | "INTEGRATION" | "ALL";
1084
1089
  is_active?: boolean;
1090
+ /** Restrict to members of one app-user group — the `id` of a `useGroups()` row. */
1091
+ group_id?: string;
1085
1092
  limit?: number;
1086
1093
  offset?: number;
1087
1094
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@colixsystems/widget-sdk",
3
- "version": "0.56.0",
3
+ "version": "0.58.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",