@keemakr/ui-sdk 1.6.0-dev-20261029104555 → 1.6.0-dev-20261029112042
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/dist/negotiate.d.ts +6 -2
- package/dist/negotiate.js +15 -3
- package/dist/schema.d.ts +26 -2
- package/dist/schema.js +21 -14
- package/dist/stat.d.ts +7 -3
- package/dist/stat.js +7 -3
- package/package.json +1 -1
package/dist/negotiate.d.ts
CHANGED
|
@@ -73,6 +73,10 @@ import type { ChatPress, ScreenRootNode, ScreenTree } from './schema.js';
|
|
|
73
73
|
* published release; core's own renderer draws it). An older parse strips it without a sign,
|
|
74
74
|
* so without it the bar's legend ("Red 8 · Amber 13 · Green 29") is written into the tile's
|
|
75
75
|
* `hint`, after any hint it had, and the bar is dropped.
|
|
76
|
+
* - `stat.sparkline`: a stat tile's `sparkline`, a small trend line in the tile (newer than any
|
|
77
|
+
* published release; core's own renderer draws it). An older parse strips it without a sign,
|
|
78
|
+
* so without it the line is dropped on purpose and the fallback list says so. The tile keeps
|
|
79
|
+
* its number; the line carried no exact value.
|
|
76
80
|
* - `section.action`: a section's `action`, a press drawn at the right end of its title line
|
|
77
81
|
* (newer than any published release; core's own renderer draws it). An older parse strips it,
|
|
78
82
|
* so without it the action becomes a `button` with the same label and press, last in the
|
|
@@ -94,7 +98,7 @@ import type { ChatPress, ScreenRootNode, ScreenTree } from './schema.js';
|
|
|
94
98
|
* button included (never left as muted text, which would read as a label), and a row, card,
|
|
95
99
|
* entry or image stays but is no longer pressable.
|
|
96
100
|
*/
|
|
97
|
-
export type UiFeature = 'breadcrumbs' | 'button.disabled' | 'section.row' | 'form.field_kinds' | 'form.confirm' | 'press.chat' | 'form.radio' | 'table.cells' | 'header.meta' | 'tabs.many' | 'choice.action' | 'markdown.links' | 'form.disabled' | 'press.seek' | 'edit.inline' | 'timeline.time_tag' | 'stat.bar' | 'section.action' | 'facts.meter' | 'form.show_when' | 'press.focus';
|
|
101
|
+
export type UiFeature = 'breadcrumbs' | 'button.disabled' | 'section.row' | 'form.field_kinds' | 'form.confirm' | 'press.chat' | 'form.radio' | 'table.cells' | 'header.meta' | 'tabs.many' | 'choice.action' | 'markdown.links' | 'form.disabled' | 'press.seek' | 'edit.inline' | 'timeline.time_tag' | 'stat.bar' | 'stat.sparkline' | 'section.action' | 'facts.meter' | 'form.show_when' | 'press.focus';
|
|
98
102
|
/** The node types and features one ui-sdk release, or one client, draws. */
|
|
99
103
|
export interface NodeSet {
|
|
100
104
|
/** For messages: "ui-sdk 1.4.0", "mobile 0.2.5". */
|
|
@@ -131,7 +135,7 @@ export declare const UI_SDK_SNAPSHOTS: {
|
|
|
131
135
|
readonly current: {
|
|
132
136
|
readonly name: "ui-sdk (this package)";
|
|
133
137
|
readonly nodes: readonly ["heading", "text", "markdown", "stat", "button", "form", "table", "timeline", "pending_request", "pending_requests", "choice_cards", "progress", "chart", "section", "tabs", "pagination", "select", "alert", "details", "timestamp", "divider", "board", "link", "tags", "toggle", "segmented", "progress_bar", "conversation", "composer", "calendar", "image", "video", "stacked_bar", "heatmap", "audio", "document"];
|
|
134
|
-
readonly features: readonly ["breadcrumbs", "button.disabled", "section.row", "form.field_kinds", "form.confirm", "press.chat", "form.radio", "table.cells", "header.meta", "tabs.many", "choice.action", "markdown.links", "form.disabled", "press.seek", "edit.inline", "timeline.time_tag", "stat.bar", "section.action", "facts.meter", "form.show_when", "press.focus"];
|
|
138
|
+
readonly features: readonly ["breadcrumbs", "button.disabled", "section.row", "form.field_kinds", "form.confirm", "press.chat", "form.radio", "table.cells", "header.meta", "tabs.many", "choice.action", "markdown.links", "form.disabled", "press.seek", "edit.inline", "timeline.time_tag", "stat.bar", "stat.sparkline", "section.action", "facts.meter", "form.show_when", "press.focus"];
|
|
135
139
|
};
|
|
136
140
|
};
|
|
137
141
|
export type UiSdkSnapshot = keyof typeof UI_SDK_SNAPSHOTS;
|
package/dist/negotiate.js
CHANGED
|
@@ -52,6 +52,7 @@ const ALL_FEATURES = [
|
|
|
52
52
|
'edit.inline',
|
|
53
53
|
'timeline.time_tag',
|
|
54
54
|
'stat.bar',
|
|
55
|
+
'stat.sparkline',
|
|
55
56
|
'section.action',
|
|
56
57
|
'facts.meter',
|
|
57
58
|
'form.show_when',
|
|
@@ -407,10 +408,21 @@ export function negotiateTree(tree, set) {
|
|
|
407
408
|
return changed ? { ...form, fields } : form;
|
|
408
409
|
}
|
|
409
410
|
case 'stat': {
|
|
410
|
-
|
|
411
|
-
|
|
411
|
+
let stat = node;
|
|
412
|
+
if (stat.sparkline && !features.has('stat.sparkline')) {
|
|
413
|
+
fallbacks.push({
|
|
414
|
+
path: `${path}.sparkline`,
|
|
415
|
+
type: 'stat',
|
|
416
|
+
reason: 'stat.sparkline',
|
|
417
|
+
as: 'dropped',
|
|
418
|
+
});
|
|
419
|
+
const { sparkline: _sparkline, ...rest } = stat;
|
|
420
|
+
stat = rest;
|
|
421
|
+
}
|
|
422
|
+
if (!stat.bar || features.has('stat.bar'))
|
|
423
|
+
return stat;
|
|
412
424
|
fallbacks.push({ path, type: 'stat', reason: 'stat.bar', as: 'folded' });
|
|
413
|
-
const { bar, ...tile } =
|
|
425
|
+
const { bar, ...tile } = stat;
|
|
414
426
|
const { legend } = stackedBarParts({ label: node.label, ...bar });
|
|
415
427
|
return {
|
|
416
428
|
...tile,
|
package/dist/schema.d.ts
CHANGED
|
@@ -318,7 +318,6 @@ export declare const tableCellSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
318
318
|
locale: z.ZodOptional<z.ZodString>;
|
|
319
319
|
}, z.core.$strip>>;
|
|
320
320
|
}, z.core.$strip>, z.ZodObject<{
|
|
321
|
-
kind: z.ZodLiteral<"sparkline">;
|
|
322
321
|
values: z.ZodArray<z.ZodNumber>;
|
|
323
322
|
tone: z.ZodDefault<z.ZodEnum<{
|
|
324
323
|
default: "default";
|
|
@@ -329,6 +328,7 @@ export declare const tableCellSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
329
328
|
accent: "accent";
|
|
330
329
|
}>>;
|
|
331
330
|
label: z.ZodString;
|
|
331
|
+
kind: z.ZodLiteral<"sparkline">;
|
|
332
332
|
}, z.core.$strip>, z.ZodObject<{
|
|
333
333
|
kind: z.ZodLiteral<"meter">;
|
|
334
334
|
value: z.ZodNumber;
|
|
@@ -525,6 +525,18 @@ declare const leafNodeSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
525
525
|
}, z.core.$strip>>;
|
|
526
526
|
max: z.ZodOptional<z.ZodNumber>;
|
|
527
527
|
}, z.core.$strip>>;
|
|
528
|
+
sparkline: z.ZodOptional<z.ZodObject<{
|
|
529
|
+
values: z.ZodArray<z.ZodNumber>;
|
|
530
|
+
tone: z.ZodDefault<z.ZodEnum<{
|
|
531
|
+
default: "default";
|
|
532
|
+
success: "success";
|
|
533
|
+
warning: "warning";
|
|
534
|
+
destructive: "destructive";
|
|
535
|
+
info: "info";
|
|
536
|
+
accent: "accent";
|
|
537
|
+
}>>;
|
|
538
|
+
label: z.ZodString;
|
|
539
|
+
}, z.core.$strip>>;
|
|
528
540
|
}, z.core.$strip>, z.ZodObject<{
|
|
529
541
|
type: z.ZodLiteral<"button">;
|
|
530
542
|
label: z.ZodString;
|
|
@@ -757,7 +769,6 @@ declare const leafNodeSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
757
769
|
locale: z.ZodOptional<z.ZodString>;
|
|
758
770
|
}, z.core.$strip>>;
|
|
759
771
|
}, z.core.$strip>, z.ZodObject<{
|
|
760
|
-
kind: z.ZodLiteral<"sparkline">;
|
|
761
772
|
values: z.ZodArray<z.ZodNumber>;
|
|
762
773
|
tone: z.ZodDefault<z.ZodEnum<{
|
|
763
774
|
default: "default";
|
|
@@ -768,6 +779,7 @@ declare const leafNodeSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
768
779
|
accent: "accent";
|
|
769
780
|
}>>;
|
|
770
781
|
label: z.ZodString;
|
|
782
|
+
kind: z.ZodLiteral<"sparkline">;
|
|
771
783
|
}, z.core.$strip>, z.ZodObject<{
|
|
772
784
|
kind: z.ZodLiteral<"meter">;
|
|
773
785
|
value: z.ZodNumber;
|
|
@@ -931,6 +943,18 @@ declare const leafNodeSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
931
943
|
}, z.core.$strip>>;
|
|
932
944
|
max: z.ZodOptional<z.ZodNumber>;
|
|
933
945
|
}, z.core.$strip>>;
|
|
946
|
+
sparkline: z.ZodOptional<z.ZodObject<{
|
|
947
|
+
values: z.ZodArray<z.ZodNumber>;
|
|
948
|
+
tone: z.ZodDefault<z.ZodEnum<{
|
|
949
|
+
default: "default";
|
|
950
|
+
success: "success";
|
|
951
|
+
warning: "warning";
|
|
952
|
+
destructive: "destructive";
|
|
953
|
+
info: "info";
|
|
954
|
+
accent: "accent";
|
|
955
|
+
}>>;
|
|
956
|
+
label: z.ZodString;
|
|
957
|
+
}, z.core.$strip>>;
|
|
934
958
|
}, z.core.$strip>, z.ZodObject<{
|
|
935
959
|
type: z.ZodLiteral<"button">;
|
|
936
960
|
label: z.ZodString;
|
package/dist/schema.js
CHANGED
|
@@ -337,6 +337,15 @@ const meterCellSchema = z.object({
|
|
|
337
337
|
* reason under a health badge.
|
|
338
338
|
*/
|
|
339
339
|
const cellSecondary = z.string().min(1).max(200).optional();
|
|
340
|
+
/** A trend line with no axis: a table's `sparkline` cell, or a stat tile's `sparkline`. */
|
|
341
|
+
const sparklineFields = {
|
|
342
|
+
/** The points, oldest first: 30 days of usage. */
|
|
343
|
+
values: z.array(z.number()).min(2).max(60),
|
|
344
|
+
/** The line's colour. */
|
|
345
|
+
tone: tone.default('default'),
|
|
346
|
+
/** What the line says, in words: "Usage down 18% in 30 days". Required. */
|
|
347
|
+
label: z.string().min(1).max(120),
|
|
348
|
+
};
|
|
340
349
|
/**
|
|
341
350
|
* A table cell: every value cell kind, plus `sparkline` and `meter`, and a
|
|
342
351
|
* `secondary` line on `text` and `badge`. Table cells only: a `details` row and a board card
|
|
@@ -355,15 +364,7 @@ export const tableCellSchema = z.discriminatedUnion('kind', [
|
|
|
355
364
|
textCellSchema.extend({ secondary: cellSecondary }),
|
|
356
365
|
badgeCellSchema.extend({ secondary: cellSecondary }),
|
|
357
366
|
dateCellSchema,
|
|
358
|
-
z.object({
|
|
359
|
-
kind: z.literal('sparkline'),
|
|
360
|
-
/** The points, oldest first: 30 days of usage. */
|
|
361
|
-
values: z.array(z.number()).min(2).max(60),
|
|
362
|
-
/** The line's colour. */
|
|
363
|
-
tone: tone.default('default'),
|
|
364
|
-
/** What the line says, in words: "Usage down 18% in 30 days". Required. */
|
|
365
|
-
label: z.string().min(1).max(120),
|
|
366
|
-
}),
|
|
367
|
+
z.object({ kind: z.literal('sparkline'), ...sparklineFields }),
|
|
367
368
|
meterCellSchema,
|
|
368
369
|
]);
|
|
369
370
|
/**
|
|
@@ -1585,22 +1586,27 @@ const markdownSchema = z.object({
|
|
|
1585
1586
|
});
|
|
1586
1587
|
/**
|
|
1587
1588
|
* A number with its label: a KPI tile. All of `tone`, `trend`, `onPress`,
|
|
1588
|
-
* `selected` and `
|
|
1589
|
+
* `selected`, `bar` and `sparkline` are optional; a renderer that does not know them draws `label`,
|
|
1589
1590
|
* `value` and `hint` as before.
|
|
1590
1591
|
*
|
|
1591
|
-
* - `tone` colours the tile for a red, amber or green count
|
|
1592
|
-
*
|
|
1592
|
+
* - `tone` colours the tile for a red, amber or green count: a coloured edge, and
|
|
1593
|
+
* the label drawn as a tinted pill with a dot. The label must still say what
|
|
1594
|
+
* the number is: colour is never the only signal.
|
|
1593
1595
|
* - `trend` is the change since the last period, drawn as an arrow and its
|
|
1594
1596
|
* text ("↑ +12% vs last week"). `good` says which way is good, so a falling
|
|
1595
|
-
* complaint count reads green; without it the trend is neutral.
|
|
1597
|
+
* complaint count reads green; without it the trend is neutral. A value that
|
|
1598
|
+
* starts with its own arrow ("▲ 2 pts") is drawn as written, with no second one.
|
|
1596
1599
|
* - `onPress` makes the tile a button: open the list behind the number, or
|
|
1597
1600
|
* filter the list below it.
|
|
1598
1601
|
* - `selected` is for a tile that filters: set it on every tile of the group,
|
|
1599
|
-
* true on the active one. It is drawn as pressed
|
|
1602
|
+
* true on the active one. It is drawn as pressed, ringed in the tile's tone,
|
|
1603
|
+
* and said as pressed.
|
|
1600
1604
|
* - `bar` is a small bar split into coloured parts under the value, the shape
|
|
1601
1605
|
* of a `stacked_bar`'s segments: Book health 50, Red 8 · Amber 13 · Green 29.
|
|
1602
1606
|
* The stat's `label` names it. A segment takes no press: the tile is one
|
|
1603
1607
|
* control, and `onPress` is its press.
|
|
1608
|
+
* - `sparkline` is a small trend line in the tile, the shape of a table's
|
|
1609
|
+
* sparkline cell: 30 days of usage. Its `label` says what the line says.
|
|
1604
1610
|
*/
|
|
1605
1611
|
const statSchema = z
|
|
1606
1612
|
.object({
|
|
@@ -1629,6 +1635,7 @@ const statSchema = z
|
|
|
1629
1635
|
max: z.number().finite().positive().optional(),
|
|
1630
1636
|
})
|
|
1631
1637
|
.optional(),
|
|
1638
|
+
sparkline: z.object(sparklineFields).optional(),
|
|
1632
1639
|
})
|
|
1633
1640
|
.superRefine((node, ctx) => {
|
|
1634
1641
|
if (node.bar)
|
package/dist/stat.d.ts
CHANGED
|
@@ -7,8 +7,11 @@ export interface StatTrendLike {
|
|
|
7
7
|
/** Whether a trend is good news, bad news, or neither. */
|
|
8
8
|
export type StatTrendFeel = 'good' | 'bad' | 'neutral';
|
|
9
9
|
export interface StatTrend {
|
|
10
|
-
/**
|
|
11
|
-
|
|
10
|
+
/**
|
|
11
|
+
* The arrow drawn before the text: ↑, ↓ or →. Never the only signal. Empty when the value
|
|
12
|
+
* starts with an arrow of its own ("▲ 2 pts"): the value is drawn as written.
|
|
13
|
+
*/
|
|
14
|
+
arrow: '↑' | '↓' | '→' | '';
|
|
12
15
|
/** good: drawn in the success colour; bad: in the destructive colour; neutral: muted. */
|
|
13
16
|
feel: StatTrendFeel;
|
|
14
17
|
/** What is drawn after the arrow: "+12% vs last week". */
|
|
@@ -19,6 +22,7 @@ export interface StatTrend {
|
|
|
19
22
|
/**
|
|
20
23
|
* How to draw a tile's trend. A flat trend, or one without `good`, is neutral.
|
|
21
24
|
* The spoken text drops a leading sign from the value ("+12%" is said "up 12%"),
|
|
22
|
-
* because the direction already says it.
|
|
25
|
+
* because the direction already says it. A value that starts with its own arrow
|
|
26
|
+
* ("▲ 2 pts") gets no second one, and its arrow is not said either.
|
|
23
27
|
*/
|
|
24
28
|
export declare function statTrend(trend: StatTrendLike): StatTrend;
|
package/dist/stat.js
CHANGED
|
@@ -4,10 +4,13 @@
|
|
|
4
4
|
// reads green on web and red on the phone.
|
|
5
5
|
const ARROW = { up: '↑', down: '↓', flat: '→' };
|
|
6
6
|
const WORD = { up: 'up', down: 'down', flat: 'no change' };
|
|
7
|
+
/** An arrow the author wrote at the start of the value ("▲ 2 pts"), and the space after it. */
|
|
8
|
+
const OWN_ARROW = /^[↑↓→←↗↘▲▼△▽▴▾⬆⬇]\s*/u;
|
|
7
9
|
/**
|
|
8
10
|
* How to draw a tile's trend. A flat trend, or one without `good`, is neutral.
|
|
9
11
|
* The spoken text drops a leading sign from the value ("+12%" is said "up 12%"),
|
|
10
|
-
* because the direction already says it.
|
|
12
|
+
* because the direction already says it. A value that starts with its own arrow
|
|
13
|
+
* ("▲ 2 pts") gets no second one, and its arrow is not said either.
|
|
11
14
|
*/
|
|
12
15
|
export function statTrend(trend) {
|
|
13
16
|
const feel = !trend.good || trend.direction === 'flat'
|
|
@@ -16,10 +19,11 @@ export function statTrend(trend) {
|
|
|
16
19
|
? 'good'
|
|
17
20
|
: 'bad';
|
|
18
21
|
const text = trend.label ? `${trend.value} ${trend.label}` : trend.value;
|
|
19
|
-
const
|
|
22
|
+
const ownArrow = OWN_ARROW.test(trend.value);
|
|
23
|
+
const amount = trend.value.replace(OWN_ARROW, '').replace(/^[+\-−]\s*/, '');
|
|
20
24
|
const said = [WORD[trend.direction], amount, trend.label].filter(Boolean).join(' ');
|
|
21
25
|
return {
|
|
22
|
-
arrow: ARROW[trend.direction],
|
|
26
|
+
arrow: ownArrow ? '' : ARROW[trend.direction],
|
|
23
27
|
feel,
|
|
24
28
|
text,
|
|
25
29
|
spoken: feel === 'neutral' ? said : `${said}, ${feel}`,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keemakr/ui-sdk",
|
|
3
|
-
"version": "1.6.0-dev-
|
|
3
|
+
"version": "1.6.0-dev-20261029112042",
|
|
4
4
|
"description": "Product screens for keemakr marketplace modules: a versioned, server-driven UI tree schema plus defineScreen() handlers. Module code never ships to the browser — keemakr-core validates the tree and renders it with platform components.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|