@colixsystems/widget-sdk 0.227.0 → 0.228.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 +23 -1
- package/dist/contract.cjs +41 -1
- package/dist/contract.js +41 -1
- package/dist/hooks.js +13 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +1 -0
- package/dist/index.native.js +1 -0
- package/dist/manifest.cjs +6 -0
- package/dist/manifest.js +6 -0
- package/package.json +1 -1
- package/src/contract.js +41 -1
package/README.md
CHANGED
|
@@ -84,7 +84,29 @@ See the design reference for the full architecture: [`docs/architecture/widget-m
|
|
|
84
84
|
|
|
85
85
|
## Status
|
|
86
86
|
|
|
87
|
-
`v0.
|
|
87
|
+
`v0.228.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**.
|
|
88
|
+
|
|
89
|
+
### What's new in 0.228.0 (contract 1.184.0)
|
|
90
|
+
|
|
91
|
+
**A widget can ask for the whole screen — manifest `prefersFitToScreen` and `useFitScreen()`.** A page section can be set to "Fit to screen": it runs edge to edge across the app's content area (no page margins, no width cap) and takes the rest of the screen below the sections above it, on every screen size, in the Player and in the exported app. Set `prefersFitToScreen: true` in your manifest when your widget is built for that — it scrolls its own content inside the height it is given and keeps its controls in view, like a messenger, a map or a full-height board. In a fit section the host then gives your widget a box exactly the height left; a widget without the field grows with its content there, and the page scrolls. A maker who drops your widget at the top level of a page then gets the setting turned on for that section (they can switch it off, and it stays off), and the AppStudio app-builder fits the section it plans your widget into. Leave it `false` or omit it otherwise.
|
|
92
|
+
|
|
93
|
+
When your widget is that section's surface, `useFill()` is `true` and so is the new `useFitScreen()`. Drop your own frame then — border, rounded corners, shadow — so the widget meets the screen's edges cleanly; the host has already removed your outer margin.
|
|
94
|
+
|
|
95
|
+
```jsx
|
|
96
|
+
import { useFill, useFitScreen, View } from "@colixsystems/widget-sdk";
|
|
97
|
+
|
|
98
|
+
export default function Board() {
|
|
99
|
+
const fill = useFill();
|
|
100
|
+
const edgeToEdge = useFitScreen();
|
|
101
|
+
return (
|
|
102
|
+
<View style={[fill ? { flex: 1, minHeight: 0 } : { height: 480 }, !edgeToEdge && { borderWidth: 1, borderRadius: 12 }]}>
|
|
103
|
+
{/* ... */}
|
|
104
|
+
</View>
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Additive: existing manifests omit the field and read `false`, and a host that never fits a widget leaves both hooks `false`. A published widget that must also run in an app whose Player is older than 0.228.0 reads the hook off a namespace import and treats a missing one as `false` (`import * as sdk from "@colixsystems/widget-sdk"; const useFitScreen = typeof sdk.useFitScreen === "function" ? sdk.useFitScreen : () => false;`, at module level): a named import of an export the host does not have stops the widget loading.
|
|
88
110
|
|
|
89
111
|
### What's new in 0.227.0 (contract 1.183.0)
|
|
90
112
|
|
package/dist/contract.cjs
CHANGED
|
@@ -991,6 +991,24 @@ const HOOKS = [
|
|
|
991
991
|
requiredContextSlice: ["fill"],
|
|
992
992
|
scopes: null,
|
|
993
993
|
},
|
|
994
|
+
{
|
|
995
|
+
name: "useFitScreen",
|
|
996
|
+
signature: "useFitScreen()",
|
|
997
|
+
description:
|
|
998
|
+
"Returns true when this widget is the surface of a page section set to " +
|
|
999
|
+
"\"Fit to screen\": the section runs edge to edge across the app's " +
|
|
1000
|
+
"content area and takes the rest of the screen, so the widget should " +
|
|
1001
|
+
"drop its own frame (border, rounded corners, shadow) and meet the " +
|
|
1002
|
+
"edges cleanly. useFill() is true as well then, and the host has already " +
|
|
1003
|
+
"removed the widget's outer margin. Defaults to false wherever the host " +
|
|
1004
|
+
"has not fitted the widget, so calling it is always safe. The SAME value " +
|
|
1005
|
+
"is injected by the web Player and the native export.",
|
|
1006
|
+
returnShape: {
|
|
1007
|
+
"(returns)": "boolean",
|
|
1008
|
+
},
|
|
1009
|
+
requiredContextSlice: ["fitScreen"],
|
|
1010
|
+
scopes: null,
|
|
1011
|
+
},
|
|
994
1012
|
{
|
|
995
1013
|
name: "useChildRenderer",
|
|
996
1014
|
signature: "useChildRenderer()",
|
|
@@ -3572,6 +3590,13 @@ const MANIFEST_SCHEMA = {
|
|
|
3572
3590
|
"Optional (default false). TRUE when every platform entry also exports useBadgeCount(props): a hook returning the count the widget puts on its page's menu entry with usePageBadge, so the app keeps that badge live while the page is closed. The host runs counters for installed marketplace widgets (the workspace's own published widgets included); the platform's built-in widgets declare none. It calls the hook with the instance's resolved props, inside the widget's own context; the hook returns a whole number, or null while the count is not known yet. It only reads, and the host enforces that: the counter's datastore and directory expose only their read methods (plus realtime subscriptions) and notification mutes only get/list, while writes, typing signals, payments, notifications.send, files, assets, AI agents, translation, link previews, device capabilities, identification and account actions all answer as unavailable. It also renders nothing, navigates nowhere, emits no events or toasts, marks nothing read, and calls none of usePageBadge, useScreenTitle, useSectionEmpty or useWidgetRoute's setter. The linter refuses a declared counter whose entry has no useBadgeCount export. The AppStudio widget agent leaves this unset: a generated widget never declares a badge counter.",
|
|
3573
3591
|
default: false,
|
|
3574
3592
|
},
|
|
3593
|
+
prefersFitToScreen: {
|
|
3594
|
+
type: "boolean",
|
|
3595
|
+
required: false,
|
|
3596
|
+
description:
|
|
3597
|
+
"Optional (default false). TRUE when the widget is built to own the rest of the screen: it scrolls its own content and keeps its controls in view, like a messenger, a map or a full-height board. Dropping the widget at the top level of a page in the Builder turns that section's \"Fit to screen\" setting on (the maker can switch it off, and it stays off), and the app-builder fits the section it plans the widget into. A fit section runs edge to edge across the content area and takes the rest of the screen; the widget learns it through useFill() and useFitScreen(), and the host gives it a box exactly the height left, which it scrolls inside (a widget without the field grows with its content there, and the page scrolls). Set it only for a widget that honours useFill() and scrolls inside the height it is given; leave it false (or omit) for everything else.",
|
|
3598
|
+
default: false,
|
|
3599
|
+
},
|
|
3575
3600
|
events: {
|
|
3576
3601
|
type: "object[]",
|
|
3577
3602
|
required: true,
|
|
@@ -3647,6 +3672,16 @@ const WIDGET_CONTEXT_SHAPE = {
|
|
|
3647
3672
|
required: false,
|
|
3648
3673
|
fields: {},
|
|
3649
3674
|
},
|
|
3675
|
+
// sc-11348 — optional host hint backing useFitScreen(): the widget is the
|
|
3676
|
+
// surface of a section set to Fit to screen, so it drops its own frame.
|
|
3677
|
+
fitScreen: {
|
|
3678
|
+
description:
|
|
3679
|
+
"Optional host layout hint (boolean). True when this widget is the " +
|
|
3680
|
+
"surface of a page section set to Fit to screen: edge to edge, the rest " +
|
|
3681
|
+
"of the screen. Backs useFitScreen(); defaults to false when absent.",
|
|
3682
|
+
required: false,
|
|
3683
|
+
fields: {},
|
|
3684
|
+
},
|
|
3650
3685
|
user: {
|
|
3651
3686
|
description:
|
|
3652
3687
|
"Signed-in user, host-built context object (camelCase: { id, email, displayName, photoUrl, roles, groupIds }) — NOT a wire payload, so it is the one camelCase island among the hooks. photoUrl is the user's own profile photo as an absolute URL, or null. email is null for an account created without one. Not a data-client.",
|
|
@@ -5938,7 +5973,12 @@ const CONTRACT = deepFreeze({
|
|
|
5938
5973
|
// `copyOf: { via, column }` (a server-kept copy read through one), and
|
|
5939
5974
|
// a table may declare `constraints` (`unique` with `unlessRelated`,
|
|
5940
5975
|
// `no-overlap`, `related-open`, `related-index`).
|
|
5941
|
-
|
|
5976
|
+
// 1.184.0: additive (sc-11348) — OPTIONAL manifest field
|
|
5977
|
+
// `prefersFitToScreen` (dropping the widget at a page's top level turns
|
|
5978
|
+
// that section's Fit to screen on), and `useFitScreen()` with its
|
|
5979
|
+
// optional `fitScreen` host hint: the widget is a fit section's surface,
|
|
5980
|
+
// so it drops its own frame. Existing manifests and hosts read false.
|
|
5981
|
+
version: "1.184.0",
|
|
5942
5982
|
sharedTranslationKeys: SHARED_TRANSLATION_KEYS,
|
|
5943
5983
|
hooks: HOOKS,
|
|
5944
5984
|
primitives: PRIMITIVES,
|
package/dist/contract.js
CHANGED
|
@@ -991,6 +991,24 @@ const HOOKS = [
|
|
|
991
991
|
requiredContextSlice: ["fill"],
|
|
992
992
|
scopes: null,
|
|
993
993
|
},
|
|
994
|
+
{
|
|
995
|
+
name: "useFitScreen",
|
|
996
|
+
signature: "useFitScreen()",
|
|
997
|
+
description:
|
|
998
|
+
"Returns true when this widget is the surface of a page section set to " +
|
|
999
|
+
"\"Fit to screen\": the section runs edge to edge across the app's " +
|
|
1000
|
+
"content area and takes the rest of the screen, so the widget should " +
|
|
1001
|
+
"drop its own frame (border, rounded corners, shadow) and meet the " +
|
|
1002
|
+
"edges cleanly. useFill() is true as well then, and the host has already " +
|
|
1003
|
+
"removed the widget's outer margin. Defaults to false wherever the host " +
|
|
1004
|
+
"has not fitted the widget, so calling it is always safe. The SAME value " +
|
|
1005
|
+
"is injected by the web Player and the native export.",
|
|
1006
|
+
returnShape: {
|
|
1007
|
+
"(returns)": "boolean",
|
|
1008
|
+
},
|
|
1009
|
+
requiredContextSlice: ["fitScreen"],
|
|
1010
|
+
scopes: null,
|
|
1011
|
+
},
|
|
994
1012
|
{
|
|
995
1013
|
name: "useChildRenderer",
|
|
996
1014
|
signature: "useChildRenderer()",
|
|
@@ -3568,6 +3586,13 @@ const MANIFEST_SCHEMA = {
|
|
|
3568
3586
|
"Optional (default false). TRUE when every platform entry also exports useBadgeCount(props): a hook returning the count the widget puts on its page's menu entry with usePageBadge, so the app keeps that badge live while the page is closed. The host runs counters for installed marketplace widgets (the workspace's own published widgets included); the platform's built-in widgets declare none. It calls the hook with the instance's resolved props, inside the widget's own context; the hook returns a whole number, or null while the count is not known yet. It only reads, and the host enforces that: the counter's datastore and directory expose only their read methods (plus realtime subscriptions) and notification mutes only get/list, while writes, typing signals, payments, notifications.send, files, assets, AI agents, translation, link previews, device capabilities, identification and account actions all answer as unavailable. It also renders nothing, navigates nowhere, emits no events or toasts, marks nothing read, and calls none of usePageBadge, useScreenTitle, useSectionEmpty or useWidgetRoute's setter. The linter refuses a declared counter whose entry has no useBadgeCount export. The AppStudio widget agent leaves this unset: a generated widget never declares a badge counter.",
|
|
3569
3587
|
default: false,
|
|
3570
3588
|
},
|
|
3589
|
+
prefersFitToScreen: {
|
|
3590
|
+
type: "boolean",
|
|
3591
|
+
required: false,
|
|
3592
|
+
description:
|
|
3593
|
+
"Optional (default false). TRUE when the widget is built to own the rest of the screen: it scrolls its own content and keeps its controls in view, like a messenger, a map or a full-height board. Dropping the widget at the top level of a page in the Builder turns that section's \"Fit to screen\" setting on (the maker can switch it off, and it stays off), and the app-builder fits the section it plans the widget into. A fit section runs edge to edge across the content area and takes the rest of the screen; the widget learns it through useFill() and useFitScreen(), and the host gives it a box exactly the height left, which it scrolls inside (a widget without the field grows with its content there, and the page scrolls). Set it only for a widget that honours useFill() and scrolls inside the height it is given; leave it false (or omit) for everything else.",
|
|
3594
|
+
default: false,
|
|
3595
|
+
},
|
|
3571
3596
|
events: {
|
|
3572
3597
|
type: "object[]",
|
|
3573
3598
|
required: true,
|
|
@@ -3643,6 +3668,16 @@ const WIDGET_CONTEXT_SHAPE = {
|
|
|
3643
3668
|
required: false,
|
|
3644
3669
|
fields: {},
|
|
3645
3670
|
},
|
|
3671
|
+
// sc-11348 — optional host hint backing useFitScreen(): the widget is the
|
|
3672
|
+
// surface of a section set to Fit to screen, so it drops its own frame.
|
|
3673
|
+
fitScreen: {
|
|
3674
|
+
description:
|
|
3675
|
+
"Optional host layout hint (boolean). True when this widget is the " +
|
|
3676
|
+
"surface of a page section set to Fit to screen: edge to edge, the rest " +
|
|
3677
|
+
"of the screen. Backs useFitScreen(); defaults to false when absent.",
|
|
3678
|
+
required: false,
|
|
3679
|
+
fields: {},
|
|
3680
|
+
},
|
|
3646
3681
|
user: {
|
|
3647
3682
|
description:
|
|
3648
3683
|
"Signed-in user, host-built context object (camelCase: { id, email, displayName, photoUrl, roles, groupIds }) — NOT a wire payload, so it is the one camelCase island among the hooks. photoUrl is the user's own profile photo as an absolute URL, or null. email is null for an account created without one. Not a data-client.",
|
|
@@ -5934,7 +5969,12 @@ const CONTRACT = deepFreeze({
|
|
|
5934
5969
|
// `copyOf: { via, column }` (a server-kept copy read through one), and
|
|
5935
5970
|
// a table may declare `constraints` (`unique` with `unlessRelated`,
|
|
5936
5971
|
// `no-overlap`, `related-open`, `related-index`).
|
|
5937
|
-
|
|
5972
|
+
// 1.184.0: additive (sc-11348) — OPTIONAL manifest field
|
|
5973
|
+
// `prefersFitToScreen` (dropping the widget at a page's top level turns
|
|
5974
|
+
// that section's Fit to screen on), and `useFitScreen()` with its
|
|
5975
|
+
// optional `fitScreen` host hint: the widget is a fit section's surface,
|
|
5976
|
+
// so it drops its own frame. Existing manifests and hosts read false.
|
|
5977
|
+
version: "1.184.0",
|
|
5938
5978
|
sharedTranslationKeys: SHARED_TRANSLATION_KEYS,
|
|
5939
5979
|
hooks: HOOKS,
|
|
5940
5980
|
primitives: PRIMITIVES,
|
package/dist/hooks.js
CHANGED
|
@@ -488,6 +488,19 @@ export function useFill() {
|
|
|
488
488
|
return ctx.fill === true;
|
|
489
489
|
}
|
|
490
490
|
|
|
491
|
+
/**
|
|
492
|
+
* Returns `true` when this widget is the surface of a page section set to
|
|
493
|
+
* "Fit to screen": the section runs edge to edge across the app's content
|
|
494
|
+
* area and takes the rest of the screen. Drop the widget's own frame then —
|
|
495
|
+
* border, rounded corners, shadow — so it meets the edges cleanly; `useFill()`
|
|
496
|
+
* is `true` as well, and the host has already removed the outer margin.
|
|
497
|
+
* Defaults to `false`, and both hosts inject the same value.
|
|
498
|
+
*/
|
|
499
|
+
export function useFitScreen() {
|
|
500
|
+
const ctx = useWidgetContextOrThrow("useFitScreen");
|
|
501
|
+
return ctx.fitScreen === true;
|
|
502
|
+
}
|
|
503
|
+
|
|
491
504
|
/**
|
|
492
505
|
* Returns the host's child-node renderer:
|
|
493
506
|
* { renderNode(node) }.
|
package/dist/index.d.ts
CHANGED
|
@@ -462,6 +462,13 @@ export interface WidgetManifest {
|
|
|
462
462
|
* while the widget's page is closed so its menu badge stays live.
|
|
463
463
|
*/
|
|
464
464
|
badgeCounter?: boolean;
|
|
465
|
+
/**
|
|
466
|
+
* Optional (sc-11348, default false). True when the widget owns the rest of
|
|
467
|
+
* the screen (a messenger, a map): dropping it at the top level of a page
|
|
468
|
+
* turns that section's "Fit to screen" on. Honour `useFill()` and
|
|
469
|
+
* `useFitScreen()` with it.
|
|
470
|
+
*/
|
|
471
|
+
prefersFitToScreen?: boolean;
|
|
465
472
|
}
|
|
466
473
|
|
|
467
474
|
/**
|
|
@@ -786,6 +793,12 @@ export interface WidgetContext<TProps = unknown> {
|
|
|
786
793
|
* Absent / `false` everywhere the host has not opted the widget into filling.
|
|
787
794
|
*/
|
|
788
795
|
fill?: boolean;
|
|
796
|
+
/**
|
|
797
|
+
* sc-11348 — optional host hint backing `useFitScreen()`: `true` when this
|
|
798
|
+
* widget is the surface of a section set to Fit to screen (edge to edge,
|
|
799
|
+
* the rest of the screen). Absent / `false` everywhere else.
|
|
800
|
+
*/
|
|
801
|
+
fitScreen?: boolean;
|
|
789
802
|
/** Active end-user identity from the host-built context (camelCase, not a wire payload). `id` is null when anonymous. */
|
|
790
803
|
user: {
|
|
791
804
|
id: string | null;
|
|
@@ -2139,6 +2152,14 @@ export function useAnonymousAccount(): AnonymousAccountApi;
|
|
|
2139
2152
|
*/
|
|
2140
2153
|
export function useFill(): boolean;
|
|
2141
2154
|
|
|
2155
|
+
/**
|
|
2156
|
+
* sc-11348 — returns `true` when this widget is the surface of a page section
|
|
2157
|
+
* set to "Fit to screen": it runs edge to edge and takes the rest of the
|
|
2158
|
+
* screen, so drop your own frame (border, rounded corners, shadow).
|
|
2159
|
+
* `useFill()` is `true` too. Defaults to `false`; the same on web and native.
|
|
2160
|
+
*/
|
|
2161
|
+
export function useFitScreen(): boolean;
|
|
2162
|
+
|
|
2142
2163
|
/**
|
|
2143
2164
|
* The host-provided navigation surface. `goTo(pageId, params?)` navigates
|
|
2144
2165
|
* to an internal app page; `goBack()` pops the stack. `goToStartPage()`
|
package/dist/index.js
CHANGED
package/dist/index.native.js
CHANGED
package/dist/manifest.cjs
CHANGED
|
@@ -331,6 +331,12 @@ function validateManifest(m) {
|
|
|
331
331
|
"manifest.badgeCounter must be a boolean when present",
|
|
332
332
|
);
|
|
333
333
|
|
|
334
|
+
pushIf(
|
|
335
|
+
errors,
|
|
336
|
+
manifest.prefersFitToScreen === undefined || typeof manifest.prefersFitToScreen === "boolean",
|
|
337
|
+
"manifest.prefersFitToScreen must be a boolean when present",
|
|
338
|
+
);
|
|
339
|
+
|
|
334
340
|
return errors.length === 0 ? { ok: true } : { ok: false, errors };
|
|
335
341
|
}
|
|
336
342
|
|
package/dist/manifest.js
CHANGED
|
@@ -377,6 +377,12 @@ function validateManifest(m) {
|
|
|
377
377
|
"manifest.badgeCounter must be a boolean when present",
|
|
378
378
|
);
|
|
379
379
|
|
|
380
|
+
pushIf(
|
|
381
|
+
errors,
|
|
382
|
+
manifest.prefersFitToScreen === undefined || typeof manifest.prefersFitToScreen === "boolean",
|
|
383
|
+
"manifest.prefersFitToScreen must be a boolean when present",
|
|
384
|
+
);
|
|
385
|
+
|
|
380
386
|
return errors.length === 0 ? { ok: true } : { ok: false, errors };
|
|
381
387
|
}
|
|
382
388
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@colixsystems/widget-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.228.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",
|
package/src/contract.js
CHANGED
|
@@ -991,6 +991,24 @@ const HOOKS = [
|
|
|
991
991
|
requiredContextSlice: ["fill"],
|
|
992
992
|
scopes: null,
|
|
993
993
|
},
|
|
994
|
+
{
|
|
995
|
+
name: "useFitScreen",
|
|
996
|
+
signature: "useFitScreen()",
|
|
997
|
+
description:
|
|
998
|
+
"Returns true when this widget is the surface of a page section set to " +
|
|
999
|
+
"\"Fit to screen\": the section runs edge to edge across the app's " +
|
|
1000
|
+
"content area and takes the rest of the screen, so the widget should " +
|
|
1001
|
+
"drop its own frame (border, rounded corners, shadow) and meet the " +
|
|
1002
|
+
"edges cleanly. useFill() is true as well then, and the host has already " +
|
|
1003
|
+
"removed the widget's outer margin. Defaults to false wherever the host " +
|
|
1004
|
+
"has not fitted the widget, so calling it is always safe. The SAME value " +
|
|
1005
|
+
"is injected by the web Player and the native export.",
|
|
1006
|
+
returnShape: {
|
|
1007
|
+
"(returns)": "boolean",
|
|
1008
|
+
},
|
|
1009
|
+
requiredContextSlice: ["fitScreen"],
|
|
1010
|
+
scopes: null,
|
|
1011
|
+
},
|
|
994
1012
|
{
|
|
995
1013
|
name: "useChildRenderer",
|
|
996
1014
|
signature: "useChildRenderer()",
|
|
@@ -3568,6 +3586,13 @@ const MANIFEST_SCHEMA = {
|
|
|
3568
3586
|
"Optional (default false). TRUE when every platform entry also exports useBadgeCount(props): a hook returning the count the widget puts on its page's menu entry with usePageBadge, so the app keeps that badge live while the page is closed. The host runs counters for installed marketplace widgets (the workspace's own published widgets included); the platform's built-in widgets declare none. It calls the hook with the instance's resolved props, inside the widget's own context; the hook returns a whole number, or null while the count is not known yet. It only reads, and the host enforces that: the counter's datastore and directory expose only their read methods (plus realtime subscriptions) and notification mutes only get/list, while writes, typing signals, payments, notifications.send, files, assets, AI agents, translation, link previews, device capabilities, identification and account actions all answer as unavailable. It also renders nothing, navigates nowhere, emits no events or toasts, marks nothing read, and calls none of usePageBadge, useScreenTitle, useSectionEmpty or useWidgetRoute's setter. The linter refuses a declared counter whose entry has no useBadgeCount export. The AppStudio widget agent leaves this unset: a generated widget never declares a badge counter.",
|
|
3569
3587
|
default: false,
|
|
3570
3588
|
},
|
|
3589
|
+
prefersFitToScreen: {
|
|
3590
|
+
type: "boolean",
|
|
3591
|
+
required: false,
|
|
3592
|
+
description:
|
|
3593
|
+
"Optional (default false). TRUE when the widget is built to own the rest of the screen: it scrolls its own content and keeps its controls in view, like a messenger, a map or a full-height board. Dropping the widget at the top level of a page in the Builder turns that section's \"Fit to screen\" setting on (the maker can switch it off, and it stays off), and the app-builder fits the section it plans the widget into. A fit section runs edge to edge across the content area and takes the rest of the screen; the widget learns it through useFill() and useFitScreen(), and the host gives it a box exactly the height left, which it scrolls inside (a widget without the field grows with its content there, and the page scrolls). Set it only for a widget that honours useFill() and scrolls inside the height it is given; leave it false (or omit) for everything else.",
|
|
3594
|
+
default: false,
|
|
3595
|
+
},
|
|
3571
3596
|
events: {
|
|
3572
3597
|
type: "object[]",
|
|
3573
3598
|
required: true,
|
|
@@ -3643,6 +3668,16 @@ const WIDGET_CONTEXT_SHAPE = {
|
|
|
3643
3668
|
required: false,
|
|
3644
3669
|
fields: {},
|
|
3645
3670
|
},
|
|
3671
|
+
// sc-11348 — optional host hint backing useFitScreen(): the widget is the
|
|
3672
|
+
// surface of a section set to Fit to screen, so it drops its own frame.
|
|
3673
|
+
fitScreen: {
|
|
3674
|
+
description:
|
|
3675
|
+
"Optional host layout hint (boolean). True when this widget is the " +
|
|
3676
|
+
"surface of a page section set to Fit to screen: edge to edge, the rest " +
|
|
3677
|
+
"of the screen. Backs useFitScreen(); defaults to false when absent.",
|
|
3678
|
+
required: false,
|
|
3679
|
+
fields: {},
|
|
3680
|
+
},
|
|
3646
3681
|
user: {
|
|
3647
3682
|
description:
|
|
3648
3683
|
"Signed-in user, host-built context object (camelCase: { id, email, displayName, photoUrl, roles, groupIds }) — NOT a wire payload, so it is the one camelCase island among the hooks. photoUrl is the user's own profile photo as an absolute URL, or null. email is null for an account created without one. Not a data-client.",
|
|
@@ -5934,7 +5969,12 @@ const CONTRACT = deepFreeze({
|
|
|
5934
5969
|
// `copyOf: { via, column }` (a server-kept copy read through one), and
|
|
5935
5970
|
// a table may declare `constraints` (`unique` with `unlessRelated`,
|
|
5936
5971
|
// `no-overlap`, `related-open`, `related-index`).
|
|
5937
|
-
|
|
5972
|
+
// 1.184.0: additive (sc-11348) — OPTIONAL manifest field
|
|
5973
|
+
// `prefersFitToScreen` (dropping the widget at a page's top level turns
|
|
5974
|
+
// that section's Fit to screen on), and `useFitScreen()` with its
|
|
5975
|
+
// optional `fitScreen` host hint: the widget is a fit section's surface,
|
|
5976
|
+
// so it drops its own frame. Existing manifests and hosts read false.
|
|
5977
|
+
version: "1.184.0",
|
|
5938
5978
|
sharedTranslationKeys: SHARED_TRANSLATION_KEYS,
|
|
5939
5979
|
hooks: HOOKS,
|
|
5940
5980
|
primitives: PRIMITIVES,
|