@colixsystems/widget-sdk 0.123.0 → 0.125.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 +28 -1
- package/dist/contract.cjs +26 -15
- package/dist/contract.js +26 -15
- package/dist/host.d.ts +0 -6
- package/dist/index.d.ts +5 -1
- package/dist/navigation.cjs +10 -19
- package/dist/navigation.js +10 -19
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -70,7 +70,34 @@ See the design reference for the full architecture: [`docs/architecture/widget-m
|
|
|
70
70
|
|
|
71
71
|
## Status
|
|
72
72
|
|
|
73
|
-
`v0.
|
|
73
|
+
`v0.125.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**.
|
|
74
|
+
|
|
75
|
+
### What's new in 0.125.0 (contract 1.97.0)
|
|
76
|
+
|
|
77
|
+
**A `top-bar` app no longer chooses which row carries its menu — `CONTRACT.themeTopBarMenuStyles` is REMOVED and `normaliseNavigation` returns `menuType` alone (sc-7044).** 0.120.0 gave the shape two menu rows to pick between: `links`, the row of text links beside the brand it had always drawn, and `tabs`, a dedicated tab row beneath the bar. `links` turned out to be the site-mode header's own row — literally the same `header` nav variant, sitting in the Studio beside "Show a header on site-mode pages" and its "Menu links" toggle, so an author was offered three adjacent settings that render the same thing. The tab row is the one that reads as an app's global navigation, so it is now the only one.
|
|
78
|
+
|
|
79
|
+
A host branches on `menuType` alone:
|
|
80
|
+
|
|
81
|
+
- `CONTRACT.themeTopBarMenuStyles` is gone, and so is the `ThemeTopBarMenuStyle` type. `ResolvedNavigation` is `{ menuType }`.
|
|
82
|
+
- `resolveTopBarTokens` is UNCHANGED — the whole `topBar` tab vocabulary (`tabStyle`, `contentSurface`, `tabIndicatorWidth`, `tabCornerRadius`, `tabPaddingX` / `tabPaddingY`, `tabBackgroundColor`, `tabActiveBackgroundColor`) now applies to every `top-bar` app rather than only to one that opted into tabs.
|
|
83
|
+
- A stored `navigation.topBarMenuStyle` is **inert**, not migrated. Nothing reads it, so no backfill runs; a `top-bar` app that never chose `tabs` renders the tab row from this version on.
|
|
84
|
+
|
|
85
|
+
**BREAKING, host-integration surface only** — a host that destructured `topBarMenuStyle` must stop. Nothing a widget author imports moved: no hook, primitive, manifest field or `propertySchema` type changed. `CONTRACT.version` → `1.97.0`.
|
|
86
|
+
|
|
87
|
+
### What's new in 0.124.0 (contract 1.96.0)
|
|
88
|
+
|
|
89
|
+
**A `filterList` condition can scope itself to the signed-in app-user (sc-6282).** `valueMode` used to be `literal` or `relativeDate`, so every filter value was a constant chosen at build time. "Show only my rows" was therefore not something a no-code author could express — it needed a custom widget reading `ctx.user` and filtering client-side, which put the scoping decision in code the server does not enforce.
|
|
90
|
+
|
|
91
|
+
Two actor-scoped modes join the vocabulary:
|
|
92
|
+
|
|
93
|
+
- **`currentUser`** on a `USER` column — the rows whose user column is the caller.
|
|
94
|
+
- **`currentUserGroup`** on a `USER_GROUP` column — the rows assigned to any group the caller belongs to (live groups only; a tombstoned group surfaces nothing).
|
|
95
|
+
|
|
96
|
+
Both **carry no value**. The condition sends the `me` sentinel and the backend resolves the identity from the request actor, so a tampered widget config cannot redirect the sentinel at another user, and a caller with no session matches **nothing** rather than every row. Valid with `eq` / `neq` only — any other operator is rejected as `INVALID_FILTER`, rather than quietly answering "mine".
|
|
97
|
+
|
|
98
|
+
To be precise about what this is: it scopes what the widget **displays**. It is not an access-control boundary — a signed-in user can always ask for the unfiltered list, so row privacy has to come from the table's record ACL (a creator-only template). Use the two together. `eq` reads as "mine", `neq` as "not mine". In the Studio the author gets a signed-in-user checkbox on the row, offered only for the column type that can carry an identity.
|
|
99
|
+
|
|
100
|
+
Additive — `literal` and `relativeDate` conditions are unchanged, and an author-supplied `value` is simply ignored by the new modes. `CONTRACT.version` → `1.96.0`.
|
|
74
101
|
|
|
75
102
|
### What's new in 0.123.0 (contract unchanged at 1.95.0)
|
|
76
103
|
|
package/dist/contract.cjs
CHANGED
|
@@ -216,7 +216,7 @@ const THEME_MENU_TYPES = Object.freeze({
|
|
|
216
216
|
"top-bar": Object.freeze({
|
|
217
217
|
name: "Top bar",
|
|
218
218
|
summary:
|
|
219
|
-
"A
|
|
219
|
+
"A tab row beneath the app header at every width -- icon and label per page, scrolling sideways when it runs out of room. No rail at any width.",
|
|
220
220
|
maxItems: null,
|
|
221
221
|
quickBarMaxItems: null,
|
|
222
222
|
}),
|
|
@@ -228,18 +228,6 @@ const THEME_MENU_TYPES = Object.freeze({
|
|
|
228
228
|
quickBarMaxItems: null,
|
|
229
229
|
}),
|
|
230
230
|
});
|
|
231
|
-
const THEME_TOP_BAR_MENU_STYLES = Object.freeze({
|
|
232
|
-
links: Object.freeze({
|
|
233
|
-
name: "Links",
|
|
234
|
-
summary:
|
|
235
|
-
"Text links beside the brand, dropping to their own row only when a phone leaves them no space.",
|
|
236
|
-
}),
|
|
237
|
-
tabs: Object.freeze({
|
|
238
|
-
name: "Tabs",
|
|
239
|
-
summary:
|
|
240
|
-
"A dedicated tab row under the bar at every width -- icon and label per page, marked by the brand, scrolling sideways when it runs out of room.",
|
|
241
|
-
}),
|
|
242
|
-
});
|
|
243
231
|
const THEME_SPACING_SCALE = Object.freeze({
|
|
244
232
|
min: 0.5,
|
|
245
233
|
max: 2,
|
|
@@ -3655,7 +3643,31 @@ const CONTRACT = deepFreeze({
|
|
|
3655
3643
|
// be opened rejects UNSUPPORTED rather than falling back to a file dialog:
|
|
3656
3644
|
// the gesture is already spent on the permission prompt, and a file input
|
|
3657
3645
|
// clicked outside it would never open.
|
|
3658
|
-
|
|
3646
|
+
// 1.96.0: additive (sc-6282) -- the `filterList` propertySchema type gains
|
|
3647
|
+
// two actor-scoped `valueMode`s beside `literal` / `relativeDate`:
|
|
3648
|
+
// `currentUser` (a USER column) and `currentUserGroup` (a USER_GROUP
|
|
3649
|
+
// column) scope a condition to the signed-in app-user, so an author can
|
|
3650
|
+
// build "only my rows" / "only my organization's rows" without a custom
|
|
3651
|
+
// widget reading `ctx.user`. Both DISCARD the condition's `value` and
|
|
3652
|
+
// send the `me` sentinel; the backend resolves the identity from the
|
|
3653
|
+
// request actor, so the sentinel cannot be redirected at another user, and
|
|
3654
|
+
// wherever it cannot be resolved -- no signed-in app-user, a renamed or
|
|
3655
|
+
// encrypted column -- it matches NOTHING rather than falling back to every
|
|
3656
|
+
// row. Valid with `eq` ("mine") and `neq` ("carries none of my
|
|
3657
|
+
// identities", which includes an unassigned row) only; any other operator
|
|
3658
|
+
// is rejected as INVALID_FILTER. It scopes what a widget DISPLAYS -- row
|
|
3659
|
+
// privacy remains the record ACL's job. Existing `literal` and
|
|
3660
|
+
// `relativeDate` conditions are untouched -- minor bump on the pre-1.0
|
|
3661
|
+
// channel.
|
|
3662
|
+
// 1.97.0: BREAKING (sc-7044) -- `themeTopBarMenuStyles` is REMOVED and
|
|
3663
|
+
// `normaliseNavigation` no longer returns `topBarMenuStyle`. A `top-bar`
|
|
3664
|
+
// app has ONE menu shape: the tab row beneath the bar. The `links` style
|
|
3665
|
+
// drew the menu on the same row-of-text-links the site-mode header draws,
|
|
3666
|
+
// so the Studio offered three adjacent settings that an author could not
|
|
3667
|
+
// tell apart. A host now branches on `menuType` alone; a stored
|
|
3668
|
+
// `navigation.topBarMenuStyle` is inert rather than migrated, so a
|
|
3669
|
+
// `top-bar` app that never chose `tabs` moves to the tab row.
|
|
3670
|
+
version: "1.97.0",
|
|
3659
3671
|
sharedTranslationKeys: SHARED_TRANSLATION_KEYS,
|
|
3660
3672
|
hooks: HOOKS,
|
|
3661
3673
|
primitives: PRIMITIVES,
|
|
@@ -3672,7 +3684,6 @@ const CONTRACT = deepFreeze({
|
|
|
3672
3684
|
themeComponentGradient: THEME_COMPONENT_GRADIENT,
|
|
3673
3685
|
themeSpacingScale: THEME_SPACING_SCALE,
|
|
3674
3686
|
themeMenuTypes: THEME_MENU_TYPES,
|
|
3675
|
-
themeTopBarMenuStyles: THEME_TOP_BAR_MENU_STYLES,
|
|
3676
3687
|
themeWidgetStyles: THEME_WIDGET_STYLES,
|
|
3677
3688
|
widgetContextShape: WIDGET_CONTEXT_SHAPE,
|
|
3678
3689
|
bundleExportContract: BUNDLE_EXPORT_CONTRACT,
|
package/dist/contract.js
CHANGED
|
@@ -216,7 +216,7 @@ const THEME_MENU_TYPES = Object.freeze({
|
|
|
216
216
|
"top-bar": Object.freeze({
|
|
217
217
|
name: "Top bar",
|
|
218
218
|
summary:
|
|
219
|
-
"A
|
|
219
|
+
"A tab row beneath the app header at every width -- icon and label per page, scrolling sideways when it runs out of room. No rail at any width.",
|
|
220
220
|
maxItems: null,
|
|
221
221
|
quickBarMaxItems: null,
|
|
222
222
|
}),
|
|
@@ -228,18 +228,6 @@ const THEME_MENU_TYPES = Object.freeze({
|
|
|
228
228
|
quickBarMaxItems: null,
|
|
229
229
|
}),
|
|
230
230
|
});
|
|
231
|
-
const THEME_TOP_BAR_MENU_STYLES = Object.freeze({
|
|
232
|
-
links: Object.freeze({
|
|
233
|
-
name: "Links",
|
|
234
|
-
summary:
|
|
235
|
-
"Text links beside the brand, dropping to their own row only when a phone leaves them no space.",
|
|
236
|
-
}),
|
|
237
|
-
tabs: Object.freeze({
|
|
238
|
-
name: "Tabs",
|
|
239
|
-
summary:
|
|
240
|
-
"A dedicated tab row under the bar at every width -- icon and label per page, marked by the brand, scrolling sideways when it runs out of room.",
|
|
241
|
-
}),
|
|
242
|
-
});
|
|
243
231
|
const THEME_SPACING_SCALE = Object.freeze({
|
|
244
232
|
min: 0.5,
|
|
245
233
|
max: 2,
|
|
@@ -3655,7 +3643,31 @@ const CONTRACT = deepFreeze({
|
|
|
3655
3643
|
// be opened rejects UNSUPPORTED rather than falling back to a file dialog:
|
|
3656
3644
|
// the gesture is already spent on the permission prompt, and a file input
|
|
3657
3645
|
// clicked outside it would never open.
|
|
3658
|
-
|
|
3646
|
+
// 1.96.0: additive (sc-6282) -- the `filterList` propertySchema type gains
|
|
3647
|
+
// two actor-scoped `valueMode`s beside `literal` / `relativeDate`:
|
|
3648
|
+
// `currentUser` (a USER column) and `currentUserGroup` (a USER_GROUP
|
|
3649
|
+
// column) scope a condition to the signed-in app-user, so an author can
|
|
3650
|
+
// build "only my rows" / "only my organization's rows" without a custom
|
|
3651
|
+
// widget reading `ctx.user`. Both DISCARD the condition's `value` and
|
|
3652
|
+
// send the `me` sentinel; the backend resolves the identity from the
|
|
3653
|
+
// request actor, so the sentinel cannot be redirected at another user, and
|
|
3654
|
+
// wherever it cannot be resolved -- no signed-in app-user, a renamed or
|
|
3655
|
+
// encrypted column -- it matches NOTHING rather than falling back to every
|
|
3656
|
+
// row. Valid with `eq` ("mine") and `neq` ("carries none of my
|
|
3657
|
+
// identities", which includes an unassigned row) only; any other operator
|
|
3658
|
+
// is rejected as INVALID_FILTER. It scopes what a widget DISPLAYS -- row
|
|
3659
|
+
// privacy remains the record ACL's job. Existing `literal` and
|
|
3660
|
+
// `relativeDate` conditions are untouched -- minor bump on the pre-1.0
|
|
3661
|
+
// channel.
|
|
3662
|
+
// 1.97.0: BREAKING (sc-7044) -- `themeTopBarMenuStyles` is REMOVED and
|
|
3663
|
+
// `normaliseNavigation` no longer returns `topBarMenuStyle`. A `top-bar`
|
|
3664
|
+
// app has ONE menu shape: the tab row beneath the bar. The `links` style
|
|
3665
|
+
// drew the menu on the same row-of-text-links the site-mode header draws,
|
|
3666
|
+
// so the Studio offered three adjacent settings that an author could not
|
|
3667
|
+
// tell apart. A host now branches on `menuType` alone; a stored
|
|
3668
|
+
// `navigation.topBarMenuStyle` is inert rather than migrated, so a
|
|
3669
|
+
// `top-bar` app that never chose `tabs` moves to the tab row.
|
|
3670
|
+
version: "1.97.0",
|
|
3659
3671
|
sharedTranslationKeys: SHARED_TRANSLATION_KEYS,
|
|
3660
3672
|
hooks: HOOKS,
|
|
3661
3673
|
primitives: PRIMITIVES,
|
|
@@ -3672,7 +3684,6 @@ const CONTRACT = deepFreeze({
|
|
|
3672
3684
|
themeComponentGradient: THEME_COMPONENT_GRADIENT,
|
|
3673
3685
|
themeSpacingScale: THEME_SPACING_SCALE,
|
|
3674
3686
|
themeMenuTypes: THEME_MENU_TYPES,
|
|
3675
|
-
themeTopBarMenuStyles: THEME_TOP_BAR_MENU_STYLES,
|
|
3676
3687
|
themeWidgetStyles: THEME_WIDGET_STYLES,
|
|
3677
3688
|
widgetContextShape: WIDGET_CONTEXT_SHAPE,
|
|
3678
3689
|
bundleExportContract: BUNDLE_EXPORT_CONTRACT,
|
package/dist/host.d.ts
CHANGED
|
@@ -155,14 +155,8 @@ export function createToastController(
|
|
|
155
155
|
|
|
156
156
|
export type ThemeMenuType = "sidebar" | "top-bar" | "bottom-tabs";
|
|
157
157
|
|
|
158
|
-
// How a `top-bar` app draws its menu — closed by
|
|
159
|
-
// `CONTRACT.themeTopBarMenuStyles`. Meaningless on the other two shapes, where
|
|
160
|
-
// the resolver always reports "links".
|
|
161
|
-
export type ThemeTopBarMenuStyle = "links" | "tabs";
|
|
162
|
-
|
|
163
158
|
export interface ResolvedNavigation {
|
|
164
159
|
menuType: ThemeMenuType;
|
|
165
|
-
topBarMenuStyle: ThemeTopBarMenuStyle;
|
|
166
160
|
}
|
|
167
161
|
|
|
168
162
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -65,7 +65,11 @@ export type WidgetPropertyType =
|
|
|
65
65
|
// builder. Persisted value is `Array<{ column, operator, value, valueMode }>`
|
|
66
66
|
// matching the ?filter[col]=op:value contract; columns resolve from a
|
|
67
67
|
// sibling tableRef (defaults to the form-root `tableId`, override via
|
|
68
|
-
// `ui.tableProp`).
|
|
68
|
+
// `ui.tableProp`). `valueMode` is `literal` (the default), `relativeDate`
|
|
69
|
+
// (ordering operators on a DATE column — `value` is "N days ago"), or the
|
|
70
|
+
// sc-6282 actor-scoped pair `currentUser` (USER column) / `currentUserGroup`
|
|
71
|
+
// (USER_GROUP column), which drop `value` and let the SERVER scope the
|
|
72
|
+
// condition to the signed-in app-user.
|
|
69
73
|
| "filterList";
|
|
70
74
|
|
|
71
75
|
export interface WidgetPropertyDef {
|
package/dist/navigation.cjs
CHANGED
|
@@ -30,9 +30,6 @@ const { CONTRACT, isHexColor } = require("./contract.cjs");
|
|
|
30
30
|
// Absent or unknown resolves here, so every app authored before menu types
|
|
31
31
|
// existed renders and compiles byte-identically.
|
|
32
32
|
const DEFAULT_MENU_TYPE = "sidebar";
|
|
33
|
-
// Today's row of text links, so an app that never made the choice draws exactly
|
|
34
|
-
// what it drew before it existed.
|
|
35
|
-
const DEFAULT_TOP_BAR_MENU_STYLE = "links";
|
|
36
33
|
|
|
37
34
|
function isPlainObject(value) {
|
|
38
35
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
@@ -45,8 +42,7 @@ function isPlainObject(value) {
|
|
|
45
42
|
* yields the default sidebar rather than something a host has to guard against.
|
|
46
43
|
*
|
|
47
44
|
* @param {unknown} navigation — the raw `theme_config.navigation` value.
|
|
48
|
-
* @returns {{ menuType: string
|
|
49
|
-
* navigation structure.
|
|
45
|
+
* @returns {{ menuType: string }} the resolved navigation structure.
|
|
50
46
|
*/
|
|
51
47
|
function normaliseNavigation(navigation) {
|
|
52
48
|
const block = isPlainObject(navigation) ? navigation : {};
|
|
@@ -55,16 +51,11 @@ function normaliseNavigation(navigation) {
|
|
|
55
51
|
typeof raw === "string" && Object.hasOwn(CONTRACT.themeMenuTypes, raw)
|
|
56
52
|
? raw
|
|
57
53
|
: DEFAULT_MENU_TYPE;
|
|
58
|
-
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
typeof rawStyle === "string" &&
|
|
64
|
-
Object.hasOwn(CONTRACT.themeTopBarMenuStyles, rawStyle)
|
|
65
|
-
? rawStyle
|
|
66
|
-
: DEFAULT_TOP_BAR_MENU_STYLE;
|
|
67
|
-
return { menuType, topBarMenuStyle };
|
|
54
|
+
// sc-7044: the SHAPE is the whole answer. A `top-bar` app used to also choose
|
|
55
|
+
// which row carried its menu, and the `links` option drew the site header's
|
|
56
|
+
// own row of text links — a second way to say the same thing. The tab row is
|
|
57
|
+
// the only shape now, so a stored `topBarMenuStyle` is read by nobody.
|
|
58
|
+
return { menuType };
|
|
68
59
|
}
|
|
69
60
|
|
|
70
61
|
/**
|
|
@@ -339,8 +330,8 @@ function resolveTopBarTokens(theme) {
|
|
|
339
330
|
// `underline` keeps the tab in the bar's surface and marks it with an
|
|
340
331
|
// indicator. `attached` makes it a real folder tab: it takes the CONTENT's
|
|
341
332
|
// surface and sits over the row's divider, so the tab and the page beneath
|
|
342
|
-
// read as one plane. Meaningless
|
|
343
|
-
//
|
|
333
|
+
// read as one plane. Meaningless on a shape that draws no tab row — a host
|
|
334
|
+
// reads it only where it has tabs to draw.
|
|
344
335
|
tabStyle: topBar.tabStyle === "attached" ? "attached" : "underline",
|
|
345
336
|
// The surface an `attached` tab AND its content panel share. One value for
|
|
346
337
|
// both, so the join cannot come apart: whatever the current tab is painted,
|
|
@@ -369,8 +360,8 @@ function resolveTopBarTokens(theme) {
|
|
|
369
360
|
tabPaddingX: tabSpaceOr(topBar.tabPaddingX, DEFAULT_TAB_PADDING_X),
|
|
370
361
|
tabPaddingY: tabSpaceOr(topBar.tabPaddingY, DEFAULT_TAB_PADDING_Y),
|
|
371
362
|
// A tab's own surface, authored or nothing. Null means the tab paints none
|
|
372
|
-
// and the bar shows through it, which is what
|
|
373
|
-
//
|
|
363
|
+
// and the bar shows through it, which is what the row did before the keys
|
|
364
|
+
// existed — so an app that never set them is unchanged.
|
|
374
365
|
tabBackgroundColor: hexOrNull(topBar.tabBackgroundColor),
|
|
375
366
|
// Only meaningful where the style draws no panel: under `attached` the
|
|
376
367
|
// active surface IS `contentSurface` above. Null under `underline` leaves
|
package/dist/navigation.js
CHANGED
|
@@ -21,9 +21,6 @@ import { CONTRACT, isHexColor } from "./contract.js";
|
|
|
21
21
|
// Absent or unknown resolves here, so every app authored before menu types
|
|
22
22
|
// existed renders and compiles byte-identically.
|
|
23
23
|
const DEFAULT_MENU_TYPE = "sidebar";
|
|
24
|
-
// Today's row of text links, so an app that never made the choice draws exactly
|
|
25
|
-
// what it drew before it existed.
|
|
26
|
-
const DEFAULT_TOP_BAR_MENU_STYLE = "links";
|
|
27
24
|
|
|
28
25
|
function isPlainObject(value) {
|
|
29
26
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
@@ -36,8 +33,7 @@ function isPlainObject(value) {
|
|
|
36
33
|
* yields the default sidebar rather than something a host has to guard against.
|
|
37
34
|
*
|
|
38
35
|
* @param {unknown} navigation — the raw `theme_config.navigation` value.
|
|
39
|
-
* @returns {{ menuType: string
|
|
40
|
-
* navigation structure.
|
|
36
|
+
* @returns {{ menuType: string }} the resolved navigation structure.
|
|
41
37
|
*/
|
|
42
38
|
export function normaliseNavigation(navigation) {
|
|
43
39
|
const block = isPlainObject(navigation) ? navigation : {};
|
|
@@ -46,16 +42,11 @@ export function normaliseNavigation(navigation) {
|
|
|
46
42
|
typeof raw === "string" && Object.hasOwn(CONTRACT.themeMenuTypes, raw)
|
|
47
43
|
? raw
|
|
48
44
|
: DEFAULT_MENU_TYPE;
|
|
49
|
-
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
typeof rawStyle === "string" &&
|
|
55
|
-
Object.hasOwn(CONTRACT.themeTopBarMenuStyles, rawStyle)
|
|
56
|
-
? rawStyle
|
|
57
|
-
: DEFAULT_TOP_BAR_MENU_STYLE;
|
|
58
|
-
return { menuType, topBarMenuStyle };
|
|
45
|
+
// sc-7044: the SHAPE is the whole answer. A `top-bar` app used to also choose
|
|
46
|
+
// which row carried its menu, and the `links` option drew the site header's
|
|
47
|
+
// own row of text links — a second way to say the same thing. The tab row is
|
|
48
|
+
// the only shape now, so a stored `topBarMenuStyle` is read by nobody.
|
|
49
|
+
return { menuType };
|
|
59
50
|
}
|
|
60
51
|
|
|
61
52
|
/**
|
|
@@ -330,8 +321,8 @@ export function resolveTopBarTokens(theme) {
|
|
|
330
321
|
// `underline` keeps the tab in the bar's surface and marks it with an
|
|
331
322
|
// indicator. `attached` makes it a real folder tab: it takes the CONTENT's
|
|
332
323
|
// surface and sits over the row's divider, so the tab and the page beneath
|
|
333
|
-
// read as one plane. Meaningless
|
|
334
|
-
//
|
|
324
|
+
// read as one plane. Meaningless on a shape that draws no tab row — a host
|
|
325
|
+
// reads it only where it has tabs to draw.
|
|
335
326
|
tabStyle: topBar.tabStyle === "attached" ? "attached" : "underline",
|
|
336
327
|
// The surface an `attached` tab AND its content panel share. One value for
|
|
337
328
|
// both, so the join cannot come apart: whatever the current tab is painted,
|
|
@@ -360,8 +351,8 @@ export function resolveTopBarTokens(theme) {
|
|
|
360
351
|
tabPaddingX: tabSpaceOr(topBar.tabPaddingX, DEFAULT_TAB_PADDING_X),
|
|
361
352
|
tabPaddingY: tabSpaceOr(topBar.tabPaddingY, DEFAULT_TAB_PADDING_Y),
|
|
362
353
|
// A tab's own surface, authored or nothing. Null means the tab paints none
|
|
363
|
-
// and the bar shows through it, which is what
|
|
364
|
-
//
|
|
354
|
+
// and the bar shows through it, which is what the row did before the keys
|
|
355
|
+
// existed — so an app that never set them is unchanged.
|
|
365
356
|
tabBackgroundColor: hexOrNull(topBar.tabBackgroundColor),
|
|
366
357
|
// Only meaningful where the style draws no panel: under `attached` the
|
|
367
358
|
// active surface IS `contentSurface` above. Null under `underline` leaves
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@colixsystems/widget-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.125.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",
|