@colixsystems/widget-sdk 0.183.0 → 0.185.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/button-view.js +3 -2
- package/dist/card-style.js +7 -9
- package/dist/card-view.js +7 -4
- package/dist/contract.cjs +13 -3
- package/dist/contract.js +13 -3
- package/dist/detail-parts-view.js +2 -1
- package/dist/flatten-style.js +23 -0
- package/dist/host.d.ts +5 -0
- package/dist/index.d.ts +2 -1
- package/dist/list-view.js +4 -3
- package/dist/list.native.js +2 -2
- package/dist/navigation.cjs +15 -0
- package/dist/navigation.js +15 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -74,7 +74,19 @@ See the design reference for the full architecture: [`docs/architecture/widget-m
|
|
|
74
74
|
|
|
75
75
|
## Status
|
|
76
76
|
|
|
77
|
-
`v0.
|
|
77
|
+
`v0.185.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**.
|
|
78
|
+
|
|
79
|
+
### What's new in 0.185.0 (contract 1.146.0)
|
|
80
|
+
|
|
81
|
+
**`<Card>` reads a style array, so a card given `flex: 1` in one actually shares its row.** `style` was read only as a plain object. A widget writing ordinary React Native, `style={[{ flex: 1, minWidth: 0 }, align && { alignItems: align }]}`, lost every key in the array: each card sized to its content and a row of figures ran out of its grid cell into the widget beside it once the numbers arrived. `<Card>` now flattens `style` the way both hosts do (nested arrays are walked in order, falsy entries are skipped, a later entry wins) before it reads the layout keys and the `card*` fields, so an array and the equivalent object draw the same card on the web Player and in the native app. `<Button>` and `<ListRow>` read their `style` through the same flatten; they already handled arrays, so nothing changes for them.
|
|
82
|
+
|
|
83
|
+
**`<Stat>` stays inside a narrow tile.** Its icon, figure and delta sat on one line that could not shrink, so in a tile a third of a desktop column wide the delta ("Busiest day: Sat") ran past the card into the next one. The line now wraps: whatever does not fit moves underneath. A tile with room is unchanged.
|
|
84
|
+
|
|
85
|
+
An installed widget is not rebuilt or republished for this. The web Player hands every widget bundle the host's own SDK at runtime, so the fix reaches it with the Studio release. A native app installs the published SDK release when it is next built.
|
|
86
|
+
|
|
87
|
+
### What's new in 0.184.0 (contract 1.145.0)
|
|
88
|
+
|
|
89
|
+
**A page's top navigation bar can put its tabs on the left, in the centre or on the right.** The tab row always started at the left edge, which looks wrong under a centred or right-aligned brand. `resolveTopBarTokens` now returns **`tabAlignment`** (`"left"` | `"center"` | `"right"`), read from `theme_config.topBar.tabAlignment`; anything else, including unset, resolves to `"left"`, so an app that never chose is unchanged. It also returns **`tabRowWidth`** (`"full"` | `"content"`, default `"full"`): the column the tabs sit in. `content` gives the tabs the page content's width and inset, so they line up with it, while the bar's own surface still spans the full width. Both hosts place the tabs with flexible spacers either side rather than by centring the row, so a row with more tabs than fit still scrolls sideways from its first tab instead of cutting it off. Host-integration surface only — no author-facing hook, prop, primitive, or manifest field changed.
|
|
78
90
|
|
|
79
91
|
### What's new in 0.183.0 (contract 1.144.0)
|
|
80
92
|
|
package/dist/button-view.js
CHANGED
|
@@ -8,6 +8,7 @@ import { DEFAULT_THEME_TOKENS } from "./_theme-tokens.js";
|
|
|
8
8
|
import { lucideGlyph } from "./icon.js";
|
|
9
9
|
import { applyThemeComponentStyle } from "./theme-components.js";
|
|
10
10
|
import { cornerRadiusOverlay, shadowStyle, gradientProps } from "./card-style.js";
|
|
11
|
+
import { flattenStyle } from "./flatten-style.js";
|
|
11
12
|
import {
|
|
12
13
|
buttonSurfaceOverlay,
|
|
13
14
|
buttonSurfaceTextOverlay,
|
|
@@ -123,8 +124,8 @@ export function makeButton(rn) {
|
|
|
123
124
|
const owned = ownedButtonPaint(
|
|
124
125
|
resolvedVariant,
|
|
125
126
|
f,
|
|
126
|
-
|
|
127
|
-
|
|
127
|
+
flattenStyle(style),
|
|
128
|
+
flattenStyle(labelStyle),
|
|
128
129
|
);
|
|
129
130
|
const { layers, ink } = containerLayers(resolvedVariant, f, colors, owned);
|
|
130
131
|
|
package/dist/card-style.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { CONTRACT, isHexColor, mixHex, normaliseComponentGradient } from "./contract.js";
|
|
9
9
|
import { normaliseCornerRadius, cornerRadiusStyle } from "./corner-radius.js";
|
|
10
10
|
import { normaliseSpacing, spacingStyle, isZeroSpacing } from "./spacing.js";
|
|
11
|
+
import { flattenStyle } from "./flatten-style.js";
|
|
11
12
|
|
|
12
13
|
export const SHADOW_PRESETS = CONTRACT.themeTokens.elevation;
|
|
13
14
|
|
|
@@ -90,17 +91,19 @@ export const CARD_LAYOUT_STYLE_FIELDS = Object.freeze([
|
|
|
90
91
|
* `<Card style={{ width: "100%" }}>` from being silently dropped; a card
|
|
91
92
|
* declaring none yields null, so it emits no extra style object.
|
|
92
93
|
*
|
|
94
|
+
* `style` may be an RN style array, read as the hosts flatten it.
|
|
95
|
+
*
|
|
93
96
|
* An `undefined` value is skipped rather than copied: react-native-web's
|
|
94
97
|
* styleq ignores it while React Native's flattenStyle assigns it, so copying
|
|
95
98
|
* one would clear the theme's value on native alone.
|
|
96
99
|
*/
|
|
97
100
|
export function cardLayoutStyle(style) {
|
|
98
|
-
|
|
101
|
+
const flat = flattenStyle(style);
|
|
99
102
|
const out = {};
|
|
100
103
|
let any = false;
|
|
101
104
|
for (const key of CARD_LAYOUT_STYLE_FIELDS) {
|
|
102
|
-
if (
|
|
103
|
-
out[key] =
|
|
105
|
+
if (flat[key] === undefined) continue;
|
|
106
|
+
out[key] = flat[key];
|
|
104
107
|
any = true;
|
|
105
108
|
}
|
|
106
109
|
return any ? out : null;
|
|
@@ -131,12 +134,7 @@ export function cardBackdrop(styles, gradient) {
|
|
|
131
134
|
const [from, to] = gradient.colors;
|
|
132
135
|
return isOpaqueHex(from) && isOpaqueHex(to) ? mixHex(from, to, 0.5) : null;
|
|
133
136
|
}
|
|
134
|
-
|
|
135
|
-
for (const style of [styles].flat(Infinity)) {
|
|
136
|
-
if (style && typeof style === "object" && style.backgroundColor !== undefined) {
|
|
137
|
-
fill = style.backgroundColor;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
137
|
+
const fill = flattenStyle(styles).backgroundColor;
|
|
140
138
|
return isOpaqueHex(fill) ? fill : null;
|
|
141
139
|
}
|
|
142
140
|
|
package/dist/card-view.js
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
cardBackdrop,
|
|
18
18
|
} from "./card-style.js";
|
|
19
19
|
import { normaliseThemeComponents } from "./theme-components.js";
|
|
20
|
+
import { flattenStyle } from "./flatten-style.js";
|
|
20
21
|
|
|
21
22
|
// A wrapped scroller stays transparent and fits inside the gradient.
|
|
22
23
|
const SCROLLER_IN_GRADIENT = { backgroundColor: "transparent", flexShrink: 1 };
|
|
@@ -80,8 +81,9 @@ export function makeCard(rn) {
|
|
|
80
81
|
const { View, Gradient } = rn;
|
|
81
82
|
|
|
82
83
|
/**
|
|
83
|
-
* @param {object} [props.style] — `card*` fields, `shadow`, `margin`
|
|
84
|
-
* (a widget's per-instance style, theme tokens already folded in)
|
|
84
|
+
* @param {object|Array} [props.style] — `card*` fields, `shadow`, `margin`
|
|
85
|
+
* (a widget's per-instance style, theme tokens already folded in), as an
|
|
86
|
+
* object or an RN style array, flattened as the hosts flatten it. On a
|
|
85
87
|
* card with no `baseStyle` it also carries the box's LAYOUT
|
|
86
88
|
* (`CARD_LAYOUT_STYLE_FIELDS`), so `style={{ width: "100%" }}` sizes the
|
|
87
89
|
* card rather than vanishing. Under `as` + a gradient the layout rides the
|
|
@@ -124,14 +126,15 @@ export function makeCard(rn) {
|
|
|
124
126
|
// A built-in brings its own base and receives the theme through `style`;
|
|
125
127
|
// anything else starts from the theme, so it matches without plumbing.
|
|
126
128
|
const standalone = baseStyle === undefined;
|
|
129
|
+
const own = flattenStyle(style);
|
|
127
130
|
const fields = {
|
|
128
131
|
...(standalone ? themedFields(theme) : null),
|
|
129
|
-
...
|
|
132
|
+
...own,
|
|
130
133
|
...explicit,
|
|
131
134
|
};
|
|
132
135
|
const base = standalone ? themedBase(theme) : baseStyle;
|
|
133
136
|
// Last, so an author's own declaration beats the theme's surface.
|
|
134
|
-
const layout = standalone ? cardLayoutStyle(
|
|
137
|
+
const layout = standalone ? cardLayoutStyle(own) : null;
|
|
135
138
|
|
|
136
139
|
const overlay = withoutMargin ? cardSurfaceStyle(fields) : cardOverlay(fields);
|
|
137
140
|
const gradient = cardGradientProps(fields);
|
package/dist/contract.cjs
CHANGED
|
@@ -2478,7 +2478,7 @@ const PRIMITIVES = [
|
|
|
2478
2478
|
{
|
|
2479
2479
|
name: "Stat",
|
|
2480
2480
|
description:
|
|
2481
|
-
'Themed headline figure. `<Stat value={openCount} label="Open orders" delta="+3 this week" deltaTone="positive" icon="package" />`. THE way to show one headline number in a summary tile; put peer tiles side by side in a row. It only DISPLAYS a figure: compute a count, sum or average over a table with `useDatastoreFigure` and pass its `text`. An empty value (null, undefined, blank text, NaN) prints `emptyValue` (default "—") in the muted tier, never a fake 0. Props: `value` (string or number), `label`, `icon` (lucide name), `delta`, `deltaTone` ("neutral" | "positive" | "negative"), `emptyValue`, `color` and `fontSize` (12-96) for the figure, `style`, `testID`.',
|
|
2481
|
+
'Themed headline figure. `<Stat value={openCount} label="Open orders" delta="+3 this week" deltaTone="positive" icon="package" />`. THE way to show one headline number in a summary tile; put peer tiles side by side in a row. It only DISPLAYS a figure: compute a count, sum or average over a table with `useDatastoreFigure` and pass its `text`. An empty value (null, undefined, blank text, NaN) prints `emptyValue` (default "—") in the muted tier, never a fake 0. Props: `value` (string or number), `label`, `icon` (lucide name), `delta`, `deltaTone` ("neutral" | "positive" | "negative"), `emptyValue`, `color` and `fontSize` (12-96) for the figure, `style`, `testID`. In a tile too narrow for the icon, figure and delta on one line, they wrap onto the next line rather than run past the tile.',
|
|
2482
2482
|
rnComponent: null,
|
|
2483
2483
|
docsUrl: null,
|
|
2484
2484
|
},
|
|
@@ -2499,7 +2499,7 @@ const PRIMITIVES = [
|
|
|
2499
2499
|
{
|
|
2500
2500
|
name: "Card",
|
|
2501
2501
|
description:
|
|
2502
|
-
'Themed card surface. `<Card>…</Card>` — THE way to draw a card, panel or tile: with no props it takes the app\'s card look (Theme Settings > Cards: background, border, corner radius, padding, shadow, gradient) so it matches every built-in card. Override one card with `background`, `borderColor`, `radius`, `padding` (a number or `{ top, right, bottom, left }`), `shadow` ("none" | "sm" | "md" | "lg") or `gradient` (`{ from, to, angle }`), or pass `style={props.style}` when your widget declares the `cardBackground` / `cardBorderColor` / `cardRadius` / `cardPadding` / `cardGradient` / `shadow` / `margin` style fields, so an author can restyle it. A card that brings no `baseStyle` also takes the box\'s LAYOUT from `style` — width, height, the flex properties, `alignSelf`, `gap`, position — so `style={{ width: \'100%\', maxWidth: 480, alignSelf: \'center\' }}` sizes the card and still keeps the app\'s card look; put anything else about the container on `containerStyle`. A gradient paints on both hosts. `as` renders the card as another container (e.g. `Pressable`, `ScrollView`) and every other prop lands on it. Never hand-roll a card from `View` + border + radius.',
|
|
2502
|
+
'Themed card surface. `<Card>…</Card>` — THE way to draw a card, panel or tile: with no props it takes the app\'s card look (Theme Settings > Cards: background, border, corner radius, padding, shadow, gradient) so it matches every built-in card. Override one card with `background`, `borderColor`, `radius`, `padding` (a number or `{ top, right, bottom, left }`), `shadow` ("none" | "sm" | "md" | "lg") or `gradient` (`{ from, to, angle }`), or pass `style={props.style}` when your widget declares the `cardBackground` / `cardBorderColor` / `cardRadius` / `cardPadding` / `cardGradient` / `shadow` / `margin` style fields, so an author can restyle it. A card that brings no `baseStyle` also takes the box\'s LAYOUT from `style` — width, height, the flex properties, `alignSelf`, `gap`, position — so `style={{ width: \'100%\', maxWidth: 480, alignSelf: \'center\' }}` sizes the card and still keeps the app\'s card look; put anything else about the container on `containerStyle`. `style` may be an object or a React Native style array (`style={[{ flex: 1, minWidth: 0 }, align && { alignItems: align }]}`), read as the host flattens it: nested arrays and falsy entries are fine and a later entry wins. A gradient paints on both hosts. `as` renders the card as another container (e.g. `Pressable`, `ScrollView`) and every other prop lands on it. Never hand-roll a card from `View` + border + radius.',
|
|
2503
2503
|
rnComponent: null,
|
|
2504
2504
|
docsUrl: null,
|
|
2505
2505
|
},
|
|
@@ -4803,7 +4803,17 @@ const CONTRACT = deepFreeze({
|
|
|
4803
4803
|
// `send_invitation`; `false` stores the invite unsent. Invite rows gain
|
|
4804
4804
|
// `sent_at` and the `not_sent` status, and `useInvites().resend` is its
|
|
4805
4805
|
// first send. Omitting the flag emails at once, as before.
|
|
4806
|
-
|
|
4806
|
+
// 1.145.0: additive (sc-10123) — `resolveTopBarTokens` returns
|
|
4807
|
+
// `tabAlignment` ("left" | "center" | "right"), where a local top bar's
|
|
4808
|
+
// tabs sit across the row, and `tabRowWidth` ("full" | "content"), the
|
|
4809
|
+
// column they sit in. Unset resolves to "left" / "full", as before.
|
|
4810
|
+
// 1.146.0: fix (sc-10179) — `<Card style>` reads an RN style ARRAY as the
|
|
4811
|
+
// host flattens it. It read only a plain object, so
|
|
4812
|
+
// `style={[{ flex: 1, minWidth: 0 }, …]}` lost every key and the cards
|
|
4813
|
+
// sized to their content. `<Button>` / `<ListRow>` read their `style`
|
|
4814
|
+
// through the same flatten; their behaviour is unchanged. `<Stat>`'s
|
|
4815
|
+
// icon, figure and delta wrap in a tile too narrow to hold them.
|
|
4816
|
+
version: "1.146.0",
|
|
4807
4817
|
sharedTranslationKeys: SHARED_TRANSLATION_KEYS,
|
|
4808
4818
|
hooks: HOOKS,
|
|
4809
4819
|
primitives: PRIMITIVES,
|
package/dist/contract.js
CHANGED
|
@@ -2478,7 +2478,7 @@ const PRIMITIVES = [
|
|
|
2478
2478
|
{
|
|
2479
2479
|
name: "Stat",
|
|
2480
2480
|
description:
|
|
2481
|
-
'Themed headline figure. `<Stat value={openCount} label="Open orders" delta="+3 this week" deltaTone="positive" icon="package" />`. THE way to show one headline number in a summary tile; put peer tiles side by side in a row. It only DISPLAYS a figure: compute a count, sum or average over a table with `useDatastoreFigure` and pass its `text`. An empty value (null, undefined, blank text, NaN) prints `emptyValue` (default "—") in the muted tier, never a fake 0. Props: `value` (string or number), `label`, `icon` (lucide name), `delta`, `deltaTone` ("neutral" | "positive" | "negative"), `emptyValue`, `color` and `fontSize` (12-96) for the figure, `style`, `testID`.',
|
|
2481
|
+
'Themed headline figure. `<Stat value={openCount} label="Open orders" delta="+3 this week" deltaTone="positive" icon="package" />`. THE way to show one headline number in a summary tile; put peer tiles side by side in a row. It only DISPLAYS a figure: compute a count, sum or average over a table with `useDatastoreFigure` and pass its `text`. An empty value (null, undefined, blank text, NaN) prints `emptyValue` (default "—") in the muted tier, never a fake 0. Props: `value` (string or number), `label`, `icon` (lucide name), `delta`, `deltaTone` ("neutral" | "positive" | "negative"), `emptyValue`, `color` and `fontSize` (12-96) for the figure, `style`, `testID`. In a tile too narrow for the icon, figure and delta on one line, they wrap onto the next line rather than run past the tile.',
|
|
2482
2482
|
rnComponent: null,
|
|
2483
2483
|
docsUrl: null,
|
|
2484
2484
|
},
|
|
@@ -2499,7 +2499,7 @@ const PRIMITIVES = [
|
|
|
2499
2499
|
{
|
|
2500
2500
|
name: "Card",
|
|
2501
2501
|
description:
|
|
2502
|
-
'Themed card surface. `<Card>…</Card>` — THE way to draw a card, panel or tile: with no props it takes the app\'s card look (Theme Settings > Cards: background, border, corner radius, padding, shadow, gradient) so it matches every built-in card. Override one card with `background`, `borderColor`, `radius`, `padding` (a number or `{ top, right, bottom, left }`), `shadow` ("none" | "sm" | "md" | "lg") or `gradient` (`{ from, to, angle }`), or pass `style={props.style}` when your widget declares the `cardBackground` / `cardBorderColor` / `cardRadius` / `cardPadding` / `cardGradient` / `shadow` / `margin` style fields, so an author can restyle it. A card that brings no `baseStyle` also takes the box\'s LAYOUT from `style` — width, height, the flex properties, `alignSelf`, `gap`, position — so `style={{ width: \'100%\', maxWidth: 480, alignSelf: \'center\' }}` sizes the card and still keeps the app\'s card look; put anything else about the container on `containerStyle`. A gradient paints on both hosts. `as` renders the card as another container (e.g. `Pressable`, `ScrollView`) and every other prop lands on it. Never hand-roll a card from `View` + border + radius.',
|
|
2502
|
+
'Themed card surface. `<Card>…</Card>` — THE way to draw a card, panel or tile: with no props it takes the app\'s card look (Theme Settings > Cards: background, border, corner radius, padding, shadow, gradient) so it matches every built-in card. Override one card with `background`, `borderColor`, `radius`, `padding` (a number or `{ top, right, bottom, left }`), `shadow` ("none" | "sm" | "md" | "lg") or `gradient` (`{ from, to, angle }`), or pass `style={props.style}` when your widget declares the `cardBackground` / `cardBorderColor` / `cardRadius` / `cardPadding` / `cardGradient` / `shadow` / `margin` style fields, so an author can restyle it. A card that brings no `baseStyle` also takes the box\'s LAYOUT from `style` — width, height, the flex properties, `alignSelf`, `gap`, position — so `style={{ width: \'100%\', maxWidth: 480, alignSelf: \'center\' }}` sizes the card and still keeps the app\'s card look; put anything else about the container on `containerStyle`. `style` may be an object or a React Native style array (`style={[{ flex: 1, minWidth: 0 }, align && { alignItems: align }]}`), read as the host flattens it: nested arrays and falsy entries are fine and a later entry wins. A gradient paints on both hosts. `as` renders the card as another container (e.g. `Pressable`, `ScrollView`) and every other prop lands on it. Never hand-roll a card from `View` + border + radius.',
|
|
2503
2503
|
rnComponent: null,
|
|
2504
2504
|
docsUrl: null,
|
|
2505
2505
|
},
|
|
@@ -4799,7 +4799,17 @@ const CONTRACT = deepFreeze({
|
|
|
4799
4799
|
// `send_invitation`; `false` stores the invite unsent. Invite rows gain
|
|
4800
4800
|
// `sent_at` and the `not_sent` status, and `useInvites().resend` is its
|
|
4801
4801
|
// first send. Omitting the flag emails at once, as before.
|
|
4802
|
-
|
|
4802
|
+
// 1.145.0: additive (sc-10123) — `resolveTopBarTokens` returns
|
|
4803
|
+
// `tabAlignment` ("left" | "center" | "right"), where a local top bar's
|
|
4804
|
+
// tabs sit across the row, and `tabRowWidth` ("full" | "content"), the
|
|
4805
|
+
// column they sit in. Unset resolves to "left" / "full", as before.
|
|
4806
|
+
// 1.146.0: fix (sc-10179) — `<Card style>` reads an RN style ARRAY as the
|
|
4807
|
+
// host flattens it. It read only a plain object, so
|
|
4808
|
+
// `style={[{ flex: 1, minWidth: 0 }, …]}` lost every key and the cards
|
|
4809
|
+
// sized to their content. `<Button>` / `<ListRow>` read their `style`
|
|
4810
|
+
// through the same flatten; their behaviour is unchanged. `<Stat>`'s
|
|
4811
|
+
// icon, figure and delta wrap in a tile too narrow to hold them.
|
|
4812
|
+
version: "1.146.0",
|
|
4803
4813
|
sharedTranslationKeys: SHARED_TRANSLATION_KEYS,
|
|
4804
4814
|
hooks: HOOKS,
|
|
4805
4815
|
primitives: PRIMITIVES,
|
|
@@ -309,7 +309,8 @@ export function makeDetailParts(rn) {
|
|
|
309
309
|
{ style: [{ alignItems: "flex-start" }, style], testID },
|
|
310
310
|
h(
|
|
311
311
|
View,
|
|
312
|
-
|
|
312
|
+
// Wraps in a narrow tile rather than running past its edge.
|
|
313
|
+
{ style: { flexDirection: "row", flexWrap: "wrap", alignItems: "center", gap: spacing.xs } },
|
|
313
314
|
glyph(icon, Math.max(12, Math.round(size * 0.75)), valueColor),
|
|
314
315
|
h(
|
|
315
316
|
Text,
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// The ONE way the SDK reads keys out of a caller's `style`. Platform-free, so
|
|
2
|
+
// the component views and the card resolvers share it on both hosts.
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A React Native style as one plain object, resolved exactly as both hosts'
|
|
6
|
+
* `StyleSheet.flatten` resolve it: nested arrays are walked in order, falsy
|
|
7
|
+
* and non-object entries are skipped, and a later entry's key wins — an
|
|
8
|
+
* explicit `undefined` included, as React Native assigns it.
|
|
9
|
+
*
|
|
10
|
+
* A component that applies only SOME of `style`'s keys must read them through
|
|
11
|
+
* this: `style={[{ flex: 1 }, cond && { alignItems }]}` is ordinary RN, and
|
|
12
|
+
* reading the array as if it were the object loses every key in it.
|
|
13
|
+
*
|
|
14
|
+
* @param {object|Array|null|undefined|false} style
|
|
15
|
+
* @returns {object} a new object; empty when the style declares nothing.
|
|
16
|
+
*/
|
|
17
|
+
export function flattenStyle(style) {
|
|
18
|
+
const out = {};
|
|
19
|
+
for (const entry of [style].flat(Infinity)) {
|
|
20
|
+
if (entry && typeof entry === "object") Object.assign(out, entry);
|
|
21
|
+
}
|
|
22
|
+
return out;
|
|
23
|
+
}
|
package/dist/host.d.ts
CHANGED
|
@@ -291,6 +291,11 @@ export interface TopBarTokens {
|
|
|
291
291
|
* bar's surface behind an indicator; `attached` cuts the bar away under the
|
|
292
292
|
* current tab so the page shows through it. */
|
|
293
293
|
tabStyle: "underline" | "attached";
|
|
294
|
+
/** Where the row's tabs sit across its width; `left` unless authored. */
|
|
295
|
+
tabAlignment: "left" | "center" | "right";
|
|
296
|
+
/** The column the tabs sit in: the whole bar, or the page content's. The
|
|
297
|
+
* bar's surface spans the full width either way. */
|
|
298
|
+
tabRowWidth: "full" | "content";
|
|
294
299
|
/** Under `attached`, the colour the PANEL behind the row paints — the
|
|
295
300
|
* authored `tabActiveBackgroundColor`, alpha kept — or null for the page's
|
|
296
301
|
* own wash. The current tab paints nothing itself. */
|
package/dist/index.d.ts
CHANGED
|
@@ -2861,8 +2861,9 @@ export const Card: (props: {
|
|
|
2861
2861
|
* sizes the card; anything else about the container goes on
|
|
2862
2862
|
* `containerStyle`. Read for the `card*` fields alone when `baseStyle` is
|
|
2863
2863
|
* given — the contract the built-in widgets pass their whole style bag on.
|
|
2864
|
+
* An RN style array is read as the host flattens it.
|
|
2864
2865
|
*/
|
|
2865
|
-
style?: Record<string, any>;
|
|
2866
|
+
style?: Record<string, any> | ReadonlyArray<any>;
|
|
2866
2867
|
/** The caller's own base style; a card given none starts from the theme. */
|
|
2867
2868
|
baseStyle?: any;
|
|
2868
2869
|
as?: any;
|
package/dist/list-view.js
CHANGED
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
LIST_SELECTED_BAR_WIDTH,
|
|
19
19
|
} from "./list-tokens.js";
|
|
20
20
|
import { textRoleStyle } from "./text-roles.js";
|
|
21
|
+
import { flattenStyle } from "./flatten-style.js";
|
|
21
22
|
|
|
22
23
|
// Outside a widget host (a test, a preview) the defaults still paint a row.
|
|
23
24
|
function useListTheme() {
|
|
@@ -49,10 +50,10 @@ const HORIZONTAL_PADDING = [
|
|
|
49
50
|
/**
|
|
50
51
|
* Bind the shared list components to one platform's primitives.
|
|
51
52
|
*
|
|
52
|
-
* @param {{View: any, Text: any, Pressable: any
|
|
53
|
+
* @param {{View: any, Text: any, Pressable: any}} rn
|
|
53
54
|
*/
|
|
54
55
|
export function makeList(rn) {
|
|
55
|
-
const { View, Text, Pressable
|
|
56
|
+
const { View, Text, Pressable } = rn;
|
|
56
57
|
const ListContext = React.createContext(null);
|
|
57
58
|
|
|
58
59
|
function useRowTokens(props) {
|
|
@@ -71,7 +72,7 @@ export function makeList(rn) {
|
|
|
71
72
|
}
|
|
72
73
|
|
|
73
74
|
function setsOwnInset(style) {
|
|
74
|
-
const flat =
|
|
75
|
+
const flat = flattenStyle(style);
|
|
75
76
|
return HORIZONTAL_PADDING.some((key) => flat[key] !== undefined);
|
|
76
77
|
}
|
|
77
78
|
|
package/dist/list.native.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// `<List>`, `<ListRow>`, `<ListHeader>`, `<EmptyState>` (native). Binds
|
|
2
2
|
// ./list-view.js to React Native's own primitives; only the import differs from ./list.js.
|
|
3
3
|
|
|
4
|
-
import { View, Text, Pressable
|
|
4
|
+
import { View, Text, Pressable } from "react-native";
|
|
5
5
|
import { makeList } from "./list-view.js";
|
|
6
6
|
|
|
7
|
-
export const { List, ListRow, ListHeader, EmptyState } = makeList({ View, Text, Pressable
|
|
7
|
+
export const { List, ListRow, ListHeader, EmptyState } = makeList({ View, Text, Pressable });
|
package/dist/navigation.cjs
CHANGED
|
@@ -535,6 +535,9 @@ function resolveTopStripeLayout(theme) {
|
|
|
535
535
|
};
|
|
536
536
|
}
|
|
537
537
|
|
|
538
|
+
const TAB_ALIGNMENTS = ["left", "center", "right"];
|
|
539
|
+
const TAB_ROW_WIDTHS = ["full", "content"];
|
|
540
|
+
|
|
538
541
|
function resolveTopBarTokens(theme) {
|
|
539
542
|
const config = isPlainObject(theme) ? theme : {};
|
|
540
543
|
const topBar = isPlainObject(config.topBar) ? config.topBar : {};
|
|
@@ -566,6 +569,18 @@ function resolveTopBarTokens(theme) {
|
|
|
566
569
|
// surface and meets the page beneath it, so the two read as one plane. Meaningless on a shape that draws no tab row — a host
|
|
567
570
|
// reads it only where it has tabs to draw.
|
|
568
571
|
tabStyle: topBar.tabStyle === "attached" ? "attached" : "underline",
|
|
572
|
+
// sc-10123: where the row's tabs sit across its width. Both hosts place
|
|
573
|
+
// them with flexible spacers rather than centring the row, so a row that
|
|
574
|
+
// overflows still scrolls from its first tab instead of clipping it.
|
|
575
|
+
tabAlignment: TAB_ALIGNMENTS.includes(topBar.tabAlignment)
|
|
576
|
+
? topBar.tabAlignment
|
|
577
|
+
: "left",
|
|
578
|
+
// sc-10123: the column the tabs sit in. `full` spans the bar; `content`
|
|
579
|
+
// shares the page content's width and inset, so the tabs line up with it.
|
|
580
|
+
// The bar's surface always spans.
|
|
581
|
+
tabRowWidth: TAB_ROW_WIDTHS.includes(topBar.tabRowWidth)
|
|
582
|
+
? topBar.tabRowWidth
|
|
583
|
+
: "full",
|
|
569
584
|
// The surface the PANEL behind an `attached` row paints — the authored
|
|
570
585
|
// active colour, alpha and all, or nothing. Under `attached` the current
|
|
571
586
|
// tab itself paints NOTHING: it is a hole in the bar, and what shows
|
package/dist/navigation.js
CHANGED
|
@@ -526,6 +526,9 @@ export function resolveTopStripeLayout(theme) {
|
|
|
526
526
|
};
|
|
527
527
|
}
|
|
528
528
|
|
|
529
|
+
const TAB_ALIGNMENTS = ["left", "center", "right"];
|
|
530
|
+
const TAB_ROW_WIDTHS = ["full", "content"];
|
|
531
|
+
|
|
529
532
|
export function resolveTopBarTokens(theme) {
|
|
530
533
|
const config = isPlainObject(theme) ? theme : {};
|
|
531
534
|
const topBar = isPlainObject(config.topBar) ? config.topBar : {};
|
|
@@ -557,6 +560,18 @@ export function resolveTopBarTokens(theme) {
|
|
|
557
560
|
// surface and meets the page beneath it, so the two read as one plane. Meaningless on a shape that draws no tab row — a host
|
|
558
561
|
// reads it only where it has tabs to draw.
|
|
559
562
|
tabStyle: topBar.tabStyle === "attached" ? "attached" : "underline",
|
|
563
|
+
// sc-10123: where the row's tabs sit across its width. Both hosts place
|
|
564
|
+
// them with flexible spacers rather than centring the row, so a row that
|
|
565
|
+
// overflows still scrolls from its first tab instead of clipping it.
|
|
566
|
+
tabAlignment: TAB_ALIGNMENTS.includes(topBar.tabAlignment)
|
|
567
|
+
? topBar.tabAlignment
|
|
568
|
+
: "left",
|
|
569
|
+
// sc-10123: the column the tabs sit in. `full` spans the bar; `content`
|
|
570
|
+
// shares the page content's width and inset, so the tabs line up with it.
|
|
571
|
+
// The bar's surface always spans.
|
|
572
|
+
tabRowWidth: TAB_ROW_WIDTHS.includes(topBar.tabRowWidth)
|
|
573
|
+
? topBar.tabRowWidth
|
|
574
|
+
: "full",
|
|
560
575
|
// The surface the PANEL behind an `attached` row paints — the authored
|
|
561
576
|
// active colour, alpha and all, or nothing. Under `attached` the current
|
|
562
577
|
// tab itself paints NOTHING: it is a hole in the bar, and what shows
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@colixsystems/widget-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.185.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",
|