@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 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
- version: "1.92.0",
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
- version: "1.92.0",
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
 
@@ -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
- // An `attached` tab is joined to the page, so its surface must be OPAQUE: the
159
- // 8-digit form a look uses to float a translucent rail would show the bar
160
- // through the page the tab claims to be part of. Both hosts already drop alpha
161
- // for the page itself (web `opaqueColor`, compiler `opaqueHex`); this is the
162
- // same rule, in the one place the tab reads it from.
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
- const from = gradient ? opaqueOr(gradient.from) : null;
173
- return hexOr(from || opaqueOr(config.backgroundColor), DEFAULT_APP_SURFACE);
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, DEFAULT_CHROME_SURFACE),
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, DEFAULT_CHROME_SURFACE),
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
@@ -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
- // An `attached` tab is joined to the page, so its surface must be OPAQUE: the
150
- // 8-digit form a look uses to float a translucent rail would show the bar
151
- // through the page the tab claims to be part of. Both hosts already drop alpha
152
- // for the page itself (web `opaqueColor`, compiler `opaqueHex`); this is the
153
- // same rule, in the one place the tab reads it from.
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
- const from = gradient ? opaqueOr(gradient.from) : null;
164
- return hexOr(from || opaqueOr(config.backgroundColor), DEFAULT_APP_SURFACE);
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, DEFAULT_CHROME_SURFACE),
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, DEFAULT_CHROME_SURFACE),
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.120.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",