@colixsystems/widget-sdk 0.120.0 → 0.121.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 +13 -1
- package/dist/contract.cjs +15 -1
- package/dist/contract.js +15 -1
- package/dist/host.d.ts +6 -2
- package/dist/navigation.cjs +58 -19
- package/dist/navigation.js +58 -19
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -72,6 +72,18 @@ See the design reference for the full architecture: [`docs/architecture/widget-m
|
|
|
72
72
|
|
|
73
73
|
`v0.119.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
74
|
|
|
75
|
+
### What's new in 0.121.0 (contract 1.93.0)
|
|
76
|
+
|
|
77
|
+
**An unset nav-chrome surface follows the PAGE, not a flat white — `resolveSidebarTokens` / `resolveTopBarTokens` (sc-6596).** 1.84.0 converged the two hosts' separately-written chrome defaults onto the web Player's `#ffffff`. Converging was right; the value was not. An app with a themed page and no explicit `sidebar`/`topBar` `backgroundColor` got bright white chrome beside the colour its author had picked — consistently on both hosts, and consistently wrong.
|
|
78
|
+
|
|
79
|
+
Both resolvers now resolve an unset `backgroundColor` to the colour the page actually shows: the app's `backgroundColor`, or a configured `backgroundGradient`'s start colour, falling back to the app default (`#f8fafc`) when the theme names neither. A gradient counts only when BOTH its stops are flat hex, which is what the hosts' own page readers require — a half-configured gradient paints nothing, so the chrome must not adopt its start colour. Per REQ-THEME-17 the page is read at FULL STRENGTH: a stored `#RRGGBBAA` reaches the chrome as its opaque base, because an alpha on the app's bottom layer composites against the host's canvas rather than anything the author chose.
|
|
80
|
+
|
|
81
|
+
This is deliberately NOT the rule an `attached` top-bar tab follows. A tab JOINED to the page refuses a translucent page rather than approximate it; chrome sitting BESIDE the page follows what the page renders. Both read one shared chain, which differs by exactly that rule.
|
|
82
|
+
|
|
83
|
+
An explicitly coloured rail or bar is unaffected. An app that themed nothing moves from `#ffffff` to the `#f8fafc` its page already was. The footer strip is untouched and still floors at white — it keeps `resolveFooterTokens`' raw-or-null shape and wants this same treatment next.
|
|
84
|
+
|
|
85
|
+
**Behaviour change, not additive:** no signature, field or export moved — only what a host renders for an unset chrome surface. Host-integration surface only; nothing a widget imports changed. `CONTRACT.version` → `1.93.0`.
|
|
86
|
+
|
|
75
87
|
### What's new in 0.120.0 (contract 1.92.0)
|
|
76
88
|
|
|
77
89
|
**A `top-bar` app chooses which ROW its menu lives in, and how that row looks — `CONTRACT.themeTopBarMenuStyles` plus the `topBar` tab vocabulary (REQ-NAV-STRUCTURE).** The shape drew its menu as text links beside the brand, sharing the bar's one row wherever there was space. That reads as part of the header rather than as the app's global navigation. `topBarMenuStyle` now picks between `links` (that row, unchanged) and `tabs` — a dedicated tab row under the bar at every width, icon and label per page, scrolling sideways rather than dropping one. `normaliseNavigation` returns it beside `menuType`, so one resolver still answers both questions and the Player and the export cannot disagree about which row an app draws. Absent, unknown, or set on any other shape resolves to `links`.
|
|
@@ -257,7 +269,7 @@ return <View style={[styles.card, spacingStyle(padding, "padding")]} />;
|
|
|
257
269
|
|
|
258
270
|
**`resolveSidebarTokens` and `resolveTopBarTokens` — the rail's and the app bar's tokens, resolved once for both hosts (sc-6289).** The footer strip got a shared resolver in 1.71.0; the two chrome parts beside it did not, so their defaults lived inline in the web Player and again in the compiler — and had drifted. An unset `sidebar.backgroundColor` painted the app background in the Expo export where the Player painted it white, so a dark app shipped a dark drawer beside a white rail; an unset `topBar.textColor` painted the app name slate in the export where the Player has always used the brand colour.
|
|
259
271
|
|
|
260
|
-
Both resolvers now own their defaults, which are what the web Player renders, so the export follows the appearance the author approved in the Studio rather than the other way round. Unlike `resolveFooterTokens`, the colours are never `null` — a default that lives in the resolver cannot drift, and one that lived in each host already had. `borderColor` stays nullable: the colour is the divider's switch.
|
|
272
|
+
Both resolvers now own their defaults, which at this version are what the web Player renders, so the export follows the appearance the author approved in the Studio rather than the other way round. (**Superseded in 1.93.0** for `backgroundColor` alone: the shared default became the page's own colour, moving both hosts rather than only the export.) Unlike `resolveFooterTokens`, the colours are never `null` — a default that lives in the resolver cannot drift, and one that lived in each host already had. `borderColor` stays nullable: the colour is the divider's switch.
|
|
261
273
|
|
|
262
274
|
The top bar resolves **two** text colours. An unthemed bar paints its icons slate and its app name in the brand colour, and React Navigation's single `headerTintColor` cannot say both — so `tintColor` and `titleColor` are separate, and an authored `topBar.textColor` drives both. `show` is deliberately not among them: it depends on the menu type rather than the theme, and REQ-THEME-14 makes it a no-op on native.
|
|
263
275
|
|
package/dist/contract.cjs
CHANGED
|
@@ -3589,7 +3589,21 @@ const CONTRACT = deepFreeze({
|
|
|
3589
3589
|
// the Player and the export cannot disagree about which row an app draws.
|
|
3590
3590
|
// Absent, unknown, or set on any other shape resolves to `links`, so every
|
|
3591
3591
|
// app authored before the choice existed renders and compiles identically.
|
|
3592
|
-
|
|
3592
|
+
// 1.93.0: BEHAVIOUR (sc-6596) -- `resolveSidebarTokens` and
|
|
3593
|
+
// `resolveTopBarTokens` resolve an UNSET `backgroundColor` to the page's
|
|
3594
|
+
// own surface instead of a flat `#ffffff`. No signature or field changed;
|
|
3595
|
+
// what a host RENDERS for an unset chrome surface did. 1.84.0 converged
|
|
3596
|
+
// the two hosts' separately-written defaults onto the Player's white,
|
|
3597
|
+
// which fixed the drift and kept the wrong value: a themed app got a dark
|
|
3598
|
+
// page and bright white chrome on both hosts. The surface now comes from
|
|
3599
|
+
// `chromeSurface`, which shares its chain with the `attached` tab's
|
|
3600
|
+
// `pageSurface` and differs in exactly one rule: a gradient contributes
|
|
3601
|
+
// its start colour to both, but chrome reads a translucent app background
|
|
3602
|
+
// at FULL STRENGTH (trimmed to its opaque base, REQ-THEME-17) where a tab
|
|
3603
|
+
// JOINED to the page refuses it. An app that colours its rail or bar
|
|
3604
|
+
// explicitly is untouched; an app that themed NOTHING moves from
|
|
3605
|
+
// `#ffffff` to the `#f8fafc` its page already was.
|
|
3606
|
+
version: "1.93.0",
|
|
3593
3607
|
sharedTranslationKeys: SHARED_TRANSLATION_KEYS,
|
|
3594
3608
|
hooks: HOOKS,
|
|
3595
3609
|
primitives: PRIMITIVES,
|
package/dist/contract.js
CHANGED
|
@@ -3589,7 +3589,21 @@ const CONTRACT = deepFreeze({
|
|
|
3589
3589
|
// the Player and the export cannot disagree about which row an app draws.
|
|
3590
3590
|
// Absent, unknown, or set on any other shape resolves to `links`, so every
|
|
3591
3591
|
// app authored before the choice existed renders and compiles identically.
|
|
3592
|
-
|
|
3592
|
+
// 1.93.0: BEHAVIOUR (sc-6596) -- `resolveSidebarTokens` and
|
|
3593
|
+
// `resolveTopBarTokens` resolve an UNSET `backgroundColor` to the page's
|
|
3594
|
+
// own surface instead of a flat `#ffffff`. No signature or field changed;
|
|
3595
|
+
// what a host RENDERS for an unset chrome surface did. 1.84.0 converged
|
|
3596
|
+
// the two hosts' separately-written defaults onto the Player's white,
|
|
3597
|
+
// which fixed the drift and kept the wrong value: a themed app got a dark
|
|
3598
|
+
// page and bright white chrome on both hosts. The surface now comes from
|
|
3599
|
+
// `chromeSurface`, which shares its chain with the `attached` tab's
|
|
3600
|
+
// `pageSurface` and differs in exactly one rule: a gradient contributes
|
|
3601
|
+
// its start colour to both, but chrome reads a translucent app background
|
|
3602
|
+
// at FULL STRENGTH (trimmed to its opaque base, REQ-THEME-17) where a tab
|
|
3603
|
+
// JOINED to the page refuses it. An app that colours its rail or bar
|
|
3604
|
+
// explicitly is untouched; an app that themed NOTHING moves from
|
|
3605
|
+
// `#ffffff` to the `#f8fafc` its page already was.
|
|
3606
|
+
version: "1.93.0",
|
|
3593
3607
|
sharedTranslationKeys: SHARED_TRANSLATION_KEYS,
|
|
3594
3608
|
hooks: HOOKS,
|
|
3595
3609
|
primitives: PRIMITIVES,
|
package/dist/host.d.ts
CHANGED
|
@@ -219,7 +219,10 @@ export interface SidebarTokens {
|
|
|
219
219
|
/**
|
|
220
220
|
* Resolves the sidebar rail's tokens from a whole `theme_config`. Every default
|
|
221
221
|
* is what the web Player renders, so the export follows the Player rather than
|
|
222
|
-
* the other way round
|
|
222
|
+
* the other way round — except `backgroundColor`, which sc-6596 moved on BOTH
|
|
223
|
+
* hosts: an unset surface takes the colour the PAGE shows (the app's
|
|
224
|
+
* `backgroundColor`, or a fully configured `backgroundGradient`'s start colour,
|
|
225
|
+
* read at full strength) rather than a flat white.
|
|
223
226
|
*/
|
|
224
227
|
export function resolveSidebarTokens(theme: unknown): SidebarTokens;
|
|
225
228
|
|
|
@@ -268,7 +271,8 @@ export interface TopBarTokens {
|
|
|
268
271
|
/**
|
|
269
272
|
* Resolves the top app bar's tokens from a whole `theme_config`. `show` is not
|
|
270
273
|
* among them: it depends on the menu type, not the theme, and is a no-op on
|
|
271
|
-
* native.
|
|
274
|
+
* native. An unset `backgroundColor` follows the PAGE's colour, as the rail's
|
|
275
|
+
* does (sc-6596).
|
|
272
276
|
*/
|
|
273
277
|
export function resolveTopBarTokens(theme: unknown): TopBarTokens;
|
|
274
278
|
|
package/dist/navigation.cjs
CHANGED
|
@@ -143,10 +143,12 @@ function resolveFooterTokens(theme) {
|
|
|
143
143
|
// Every default is what the WEB Player renders today, so the Player does not
|
|
144
144
|
// move and the export converges onto it. That is the direction the footer was
|
|
145
145
|
// converged in too (compiler.service's footerBg defaults to the web's #ffffff).
|
|
146
|
+
//
|
|
147
|
+
// sc-6596 — the ONE exception, and it moves BOTH hosts: an unset rail or bar
|
|
148
|
+
// takes the page's own colour. Converging on the Player's white left a themed
|
|
149
|
+
// app's chrome contradicting its own theme.
|
|
146
150
|
|
|
147
151
|
const DEFAULT_PRIMARY_COLOR = "#3b82f6";
|
|
148
|
-
// The web rail's and app bar's `bg-white`.
|
|
149
|
-
const DEFAULT_CHROME_SURFACE = "#ffffff";
|
|
150
152
|
// The web nav item's `text-slate-600`.
|
|
151
153
|
const DEFAULT_CHROME_TEXT = "#475569";
|
|
152
154
|
// The web mobile header's icon colour, `text-slate-700`.
|
|
@@ -155,22 +157,43 @@ const DEFAULT_TOP_BAR_TINT = "#334155";
|
|
|
155
157
|
// (frontend/src/utils/theme.js) and the compiler's, which are the same slate-50.
|
|
156
158
|
const DEFAULT_APP_SURFACE = "#f8fafc";
|
|
157
159
|
|
|
158
|
-
//
|
|
159
|
-
//
|
|
160
|
-
//
|
|
161
|
-
//
|
|
162
|
-
|
|
163
|
-
// The colour the PAGE actually shows where a tab meets it. A gradient owns the
|
|
164
|
-
// visible background wherever one is configured and the flat `backgroundColor`
|
|
165
|
-
// shows nowhere, so an attached tab matching the flat colour under a gradient is
|
|
166
|
-
// the mismatch this exists to avoid — it takes the gradient's START colour,
|
|
167
|
-
// which is what the page paints at the top edge the tab is joined to.
|
|
168
|
-
function pageSurface(config) {
|
|
160
|
+
// A gradient shows only when BOTH stops are a flat hex — the rule both hosts'
|
|
161
|
+
// page readers apply (`normaliseThemeGradient`, mirrored frontend/backend). A
|
|
162
|
+
// half-configured or alpha-carrying gradient paints NOTHING, so reading its
|
|
163
|
+
// `from` would hand the chrome a colour the page never shows.
|
|
164
|
+
function gradientStart(config) {
|
|
169
165
|
const gradient = isPlainObject(config.backgroundGradient)
|
|
170
166
|
? config.backgroundGradient
|
|
171
167
|
: null;
|
|
172
|
-
|
|
173
|
-
|
|
168
|
+
if (!gradient) return null;
|
|
169
|
+
const from = flatHexOrNull(gradient.from);
|
|
170
|
+
return from && flatHexOrNull(gradient.to) ? from : null;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// The colour the PAGE actually shows. A gradient owns the visible background,
|
|
174
|
+
// so its START colour wins — the flat colour shows nowhere under one.
|
|
175
|
+
//
|
|
176
|
+
// `alphaRule` is the only thing the two callers differ by, and they differ for a
|
|
177
|
+
// reason: a tab JOINED to the page refuses a translucent page rather than
|
|
178
|
+
// approximate it, while chrome BESIDE the page follows what the page renders —
|
|
179
|
+
// the alpha-trimmed value both hosts paint (REQ-THEME-17). Sharing the chain is
|
|
180
|
+
// what keeps them from drifting on everything else.
|
|
181
|
+
function pageColor(config, alphaRule) {
|
|
182
|
+
return hexOr(
|
|
183
|
+
gradientStart(config) || alphaRule(config.backgroundColor),
|
|
184
|
+
DEFAULT_APP_SURFACE,
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// An `attached` tab: opaque, or the bar shows through the page it joins.
|
|
189
|
+
function pageSurface(config) {
|
|
190
|
+
return pageColor(config, opaqueOr);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// sc-6596: what an UNSET rail or bar is painted. Read at full strength — an
|
|
194
|
+
// alpha on the bottom layer would mean nothing to chrome above it.
|
|
195
|
+
function chromeSurface(config) {
|
|
196
|
+
return pageColor(config, flattenedHex);
|
|
174
197
|
}
|
|
175
198
|
|
|
176
199
|
// The rail's raw block — the fallback every other chrome's active colour ends
|
|
@@ -215,6 +238,18 @@ function opaqueOr(value) {
|
|
|
215
238
|
: null;
|
|
216
239
|
}
|
|
217
240
|
|
|
241
|
+
// A gradient stop as the page readers admit one: flat hex, never alpha.
|
|
242
|
+
function flatHexOrNull(value) {
|
|
243
|
+
return isHexColor(value) && value.length !== 9 ? value : null;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// `#RRGGBBAA` trimmed to its opaque base rather than refused — what both hosts'
|
|
247
|
+
// page readers paint (web `opaqueColor`, compiler `opaqueHex`).
|
|
248
|
+
function flattenedHex(value) {
|
|
249
|
+
if (!isHexColor(value)) return null;
|
|
250
|
+
return value.length === 9 ? value.slice(0, 7) : value;
|
|
251
|
+
}
|
|
252
|
+
|
|
218
253
|
// The contract's own guard, which already admits the 8-digit form a look uses
|
|
219
254
|
// to float a translucent rail (#RRGGBBAA).
|
|
220
255
|
function hexOrNull(value) {
|
|
@@ -233,7 +268,9 @@ function brandPrimary(config) {
|
|
|
233
268
|
* The sidebar rail's surface, labels, active item and opt-in divider.
|
|
234
269
|
*
|
|
235
270
|
* @param {unknown} theme — the whole `theme_config`; `primaryColor` is read
|
|
236
|
-
* because an unset active colour resolves to the brand
|
|
271
|
+
* because an unset active colour resolves to the brand, and the app's
|
|
272
|
+
* `backgroundColor`/`backgroundGradient` because an unset surface resolves to
|
|
273
|
+
* the page's (sc-6596).
|
|
237
274
|
* @returns {{ backgroundColor: string, textColor: string, activeColor: string,
|
|
238
275
|
* activeStyle: string, borderColor: string|null, borderWidth: number|null }}
|
|
239
276
|
*/
|
|
@@ -242,7 +279,7 @@ function resolveSidebarTokens(theme) {
|
|
|
242
279
|
const sidebar = isPlainObject(config.sidebar) ? config.sidebar : {};
|
|
243
280
|
const borderColor = hexOrNull(sidebar.borderColor);
|
|
244
281
|
return {
|
|
245
|
-
backgroundColor: hexOr(sidebar.backgroundColor,
|
|
282
|
+
backgroundColor: hexOr(sidebar.backgroundColor, chromeSurface(config)),
|
|
246
283
|
textColor: hexOr(sidebar.textColor, DEFAULT_CHROME_TEXT),
|
|
247
284
|
activeColor: hexOr(sidebar.activeColor, brandPrimary(config)),
|
|
248
285
|
activeStyle: sidebar.activeStyle === "accent" ? "accent" : "filled",
|
|
@@ -264,7 +301,9 @@ function resolveSidebarTokens(theme) {
|
|
|
264
301
|
* `show` is deliberately absent: it depends on the menu TYPE, not the theme,
|
|
265
302
|
* and REQ-THEME-14 makes it a no-op on native — so it is not a shared token.
|
|
266
303
|
*
|
|
267
|
-
* @param {unknown} theme — the whole `theme_config
|
|
304
|
+
* @param {unknown} theme — the whole `theme_config`; the app's
|
|
305
|
+
* `backgroundColor`/`backgroundGradient` are read because an unset surface
|
|
306
|
+
* resolves to the page's, as an `attached` tab's already did (sc-6596).
|
|
268
307
|
* @returns {{ backgroundColor: string, tintColor: string, titleColor: string,
|
|
269
308
|
* borderColor: string|null, borderWidth: number|null }}
|
|
270
309
|
*/
|
|
@@ -275,7 +314,7 @@ function resolveTopBarTokens(theme) {
|
|
|
275
314
|
// An explicit colour drives BOTH slots; only the unset case splits.
|
|
276
315
|
const authored = hexOrNull(topBar.textColor);
|
|
277
316
|
return {
|
|
278
|
-
backgroundColor: hexOr(topBar.backgroundColor,
|
|
317
|
+
backgroundColor: hexOr(topBar.backgroundColor, chromeSurface(config)),
|
|
279
318
|
tintColor: authored || DEFAULT_TOP_BAR_TINT,
|
|
280
319
|
titleColor: authored || brandPrimary(config),
|
|
281
320
|
// REQ-NAV-STRUCTURE: the CURRENT page's mark — the active link's label, and
|
package/dist/navigation.js
CHANGED
|
@@ -134,10 +134,12 @@ export function resolveFooterTokens(theme) {
|
|
|
134
134
|
// Every default is what the WEB Player renders today, so the Player does not
|
|
135
135
|
// move and the export converges onto it. That is the direction the footer was
|
|
136
136
|
// converged in too (compiler.service's footerBg defaults to the web's #ffffff).
|
|
137
|
+
//
|
|
138
|
+
// sc-6596 — the ONE exception, and it moves BOTH hosts: an unset rail or bar
|
|
139
|
+
// takes the page's own colour. Converging on the Player's white left a themed
|
|
140
|
+
// app's chrome contradicting its own theme.
|
|
137
141
|
|
|
138
142
|
const DEFAULT_PRIMARY_COLOR = "#3b82f6";
|
|
139
|
-
// The web rail's and app bar's `bg-white`.
|
|
140
|
-
const DEFAULT_CHROME_SURFACE = "#ffffff";
|
|
141
143
|
// The web nav item's `text-slate-600`.
|
|
142
144
|
const DEFAULT_CHROME_TEXT = "#475569";
|
|
143
145
|
// The web mobile header's icon colour, `text-slate-700`.
|
|
@@ -146,22 +148,43 @@ const DEFAULT_TOP_BAR_TINT = "#334155";
|
|
|
146
148
|
// (frontend/src/utils/theme.js) and the compiler's, which are the same slate-50.
|
|
147
149
|
const DEFAULT_APP_SURFACE = "#f8fafc";
|
|
148
150
|
|
|
149
|
-
//
|
|
150
|
-
//
|
|
151
|
-
//
|
|
152
|
-
//
|
|
153
|
-
|
|
154
|
-
// The colour the PAGE actually shows where a tab meets it. A gradient owns the
|
|
155
|
-
// visible background wherever one is configured and the flat `backgroundColor`
|
|
156
|
-
// shows nowhere, so an attached tab matching the flat colour under a gradient is
|
|
157
|
-
// the mismatch this exists to avoid — it takes the gradient's START colour,
|
|
158
|
-
// which is what the page paints at the top edge the tab is joined to.
|
|
159
|
-
function pageSurface(config) {
|
|
151
|
+
// A gradient shows only when BOTH stops are a flat hex — the rule both hosts'
|
|
152
|
+
// page readers apply (`normaliseThemeGradient`, mirrored frontend/backend). A
|
|
153
|
+
// half-configured or alpha-carrying gradient paints NOTHING, so reading its
|
|
154
|
+
// `from` would hand the chrome a colour the page never shows.
|
|
155
|
+
function gradientStart(config) {
|
|
160
156
|
const gradient = isPlainObject(config.backgroundGradient)
|
|
161
157
|
? config.backgroundGradient
|
|
162
158
|
: null;
|
|
163
|
-
|
|
164
|
-
|
|
159
|
+
if (!gradient) return null;
|
|
160
|
+
const from = flatHexOrNull(gradient.from);
|
|
161
|
+
return from && flatHexOrNull(gradient.to) ? from : null;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// The colour the PAGE actually shows. A gradient owns the visible background,
|
|
165
|
+
// so its START colour wins — the flat colour shows nowhere under one.
|
|
166
|
+
//
|
|
167
|
+
// `alphaRule` is the only thing the two callers differ by, and they differ for a
|
|
168
|
+
// reason: a tab JOINED to the page refuses a translucent page rather than
|
|
169
|
+
// approximate it, while chrome BESIDE the page follows what the page renders —
|
|
170
|
+
// the alpha-trimmed value both hosts paint (REQ-THEME-17). Sharing the chain is
|
|
171
|
+
// what keeps them from drifting on everything else.
|
|
172
|
+
function pageColor(config, alphaRule) {
|
|
173
|
+
return hexOr(
|
|
174
|
+
gradientStart(config) || alphaRule(config.backgroundColor),
|
|
175
|
+
DEFAULT_APP_SURFACE,
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// An `attached` tab: opaque, or the bar shows through the page it joins.
|
|
180
|
+
function pageSurface(config) {
|
|
181
|
+
return pageColor(config, opaqueOr);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// sc-6596: what an UNSET rail or bar is painted. Read at full strength — an
|
|
185
|
+
// alpha on the bottom layer would mean nothing to chrome above it.
|
|
186
|
+
function chromeSurface(config) {
|
|
187
|
+
return pageColor(config, flattenedHex);
|
|
165
188
|
}
|
|
166
189
|
|
|
167
190
|
// The rail's raw block — the fallback every other chrome's active colour ends
|
|
@@ -206,6 +229,18 @@ function opaqueOr(value) {
|
|
|
206
229
|
: null;
|
|
207
230
|
}
|
|
208
231
|
|
|
232
|
+
// A gradient stop as the page readers admit one: flat hex, never alpha.
|
|
233
|
+
function flatHexOrNull(value) {
|
|
234
|
+
return isHexColor(value) && value.length !== 9 ? value : null;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// `#RRGGBBAA` trimmed to its opaque base rather than refused — what both hosts'
|
|
238
|
+
// page readers paint (web `opaqueColor`, compiler `opaqueHex`).
|
|
239
|
+
function flattenedHex(value) {
|
|
240
|
+
if (!isHexColor(value)) return null;
|
|
241
|
+
return value.length === 9 ? value.slice(0, 7) : value;
|
|
242
|
+
}
|
|
243
|
+
|
|
209
244
|
// The contract's own guard, which already admits the 8-digit form a look uses
|
|
210
245
|
// to float a translucent rail (#RRGGBBAA).
|
|
211
246
|
function hexOrNull(value) {
|
|
@@ -224,7 +259,9 @@ function brandPrimary(config) {
|
|
|
224
259
|
* The sidebar rail's surface, labels, active item and opt-in divider.
|
|
225
260
|
*
|
|
226
261
|
* @param {unknown} theme — the whole `theme_config`; `primaryColor` is read
|
|
227
|
-
* because an unset active colour resolves to the brand
|
|
262
|
+
* because an unset active colour resolves to the brand, and the app's
|
|
263
|
+
* `backgroundColor`/`backgroundGradient` because an unset surface resolves to
|
|
264
|
+
* the page's (sc-6596).
|
|
228
265
|
* @returns {{ backgroundColor: string, textColor: string, activeColor: string,
|
|
229
266
|
* activeStyle: string, borderColor: string|null, borderWidth: number|null }}
|
|
230
267
|
*/
|
|
@@ -233,7 +270,7 @@ export function resolveSidebarTokens(theme) {
|
|
|
233
270
|
const sidebar = isPlainObject(config.sidebar) ? config.sidebar : {};
|
|
234
271
|
const borderColor = hexOrNull(sidebar.borderColor);
|
|
235
272
|
return {
|
|
236
|
-
backgroundColor: hexOr(sidebar.backgroundColor,
|
|
273
|
+
backgroundColor: hexOr(sidebar.backgroundColor, chromeSurface(config)),
|
|
237
274
|
textColor: hexOr(sidebar.textColor, DEFAULT_CHROME_TEXT),
|
|
238
275
|
activeColor: hexOr(sidebar.activeColor, brandPrimary(config)),
|
|
239
276
|
activeStyle: sidebar.activeStyle === "accent" ? "accent" : "filled",
|
|
@@ -255,7 +292,9 @@ export function resolveSidebarTokens(theme) {
|
|
|
255
292
|
* `show` is deliberately absent: it depends on the menu TYPE, not the theme,
|
|
256
293
|
* and REQ-THEME-14 makes it a no-op on native — so it is not a shared token.
|
|
257
294
|
*
|
|
258
|
-
* @param {unknown} theme — the whole `theme_config
|
|
295
|
+
* @param {unknown} theme — the whole `theme_config`; the app's
|
|
296
|
+
* `backgroundColor`/`backgroundGradient` are read because an unset surface
|
|
297
|
+
* resolves to the page's, as an `attached` tab's already did (sc-6596).
|
|
259
298
|
* @returns {{ backgroundColor: string, tintColor: string, titleColor: string,
|
|
260
299
|
* borderColor: string|null, borderWidth: number|null }}
|
|
261
300
|
*/
|
|
@@ -266,7 +305,7 @@ export function resolveTopBarTokens(theme) {
|
|
|
266
305
|
// An explicit colour drives BOTH slots; only the unset case splits.
|
|
267
306
|
const authored = hexOrNull(topBar.textColor);
|
|
268
307
|
return {
|
|
269
|
-
backgroundColor: hexOr(topBar.backgroundColor,
|
|
308
|
+
backgroundColor: hexOr(topBar.backgroundColor, chromeSurface(config)),
|
|
270
309
|
tintColor: authored || DEFAULT_TOP_BAR_TINT,
|
|
271
310
|
titleColor: authored || brandPrimary(config),
|
|
272
311
|
// REQ-NAV-STRUCTURE: the CURRENT page's mark — the active link's label, and
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@colixsystems/widget-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.121.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",
|