@keemakr/ui-sdk 1.3.0 → 1.4.0-dev-20261012081643
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/nodes.d.ts +1 -1
- package/dist/nodes.js +2 -0
- package/dist/schema.d.ts +69 -3
- package/dist/schema.js +105 -2
- package/package.json +1 -1
package/dist/nodes.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ScreenRootNode } from './schema.js';
|
|
2
2
|
/** Every node type the root union admits (KEE-574 item 3). */
|
|
3
|
-
export declare const KNOWN_NODE_TYPES: readonly ["heading", "text", "markdown", "stat", "button", "form", "table", "timeline", "pending_request", "pending_requests", "choice_cards", "progress", "chart", "pagination", "select", "alert", "details", "timestamp", "section", "tabs"];
|
|
3
|
+
export declare const KNOWN_NODE_TYPES: readonly ["heading", "text", "markdown", "stat", "button", "form", "table", "timeline", "pending_request", "pending_requests", "choice_cards", "progress", "chart", "pagination", "select", "alert", "details", "timestamp", "divider", "board", "section", "tabs"];
|
|
4
4
|
export type KnownNodeType = (typeof KNOWN_NODE_TYPES)[number];
|
|
5
5
|
/**
|
|
6
6
|
* The node types that hold child nodes. `section` mounts its children
|
package/dist/nodes.js
CHANGED
package/dist/schema.d.ts
CHANGED
|
@@ -42,6 +42,8 @@ export declare const buttonSchema: z.ZodObject<{
|
|
|
42
42
|
secondary: "secondary";
|
|
43
43
|
}>>;
|
|
44
44
|
disabled: z.ZodDefault<z.ZodBoolean>;
|
|
45
|
+
hint: z.ZodOptional<z.ZodString>;
|
|
46
|
+
disabledReason: z.ZodOptional<z.ZodString>;
|
|
45
47
|
}, z.core.$strip>;
|
|
46
48
|
/** A table cell. Dates are ISO 8601; core formats them tenant-locale-aware. */
|
|
47
49
|
export declare const cellSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
@@ -94,6 +96,8 @@ declare const leafNodeSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
94
96
|
secondary: "secondary";
|
|
95
97
|
}>>;
|
|
96
98
|
disabled: z.ZodDefault<z.ZodBoolean>;
|
|
99
|
+
hint: z.ZodOptional<z.ZodString>;
|
|
100
|
+
disabledReason: z.ZodOptional<z.ZodString>;
|
|
97
101
|
}, z.core.$strip>, z.ZodObject<{
|
|
98
102
|
type: z.ZodLiteral<"form">;
|
|
99
103
|
key: z.ZodString;
|
|
@@ -185,6 +189,8 @@ declare const leafNodeSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
185
189
|
secondary: "secondary";
|
|
186
190
|
}>>;
|
|
187
191
|
disabled: z.ZodDefault<z.ZodBoolean>;
|
|
192
|
+
hint: z.ZodOptional<z.ZodString>;
|
|
193
|
+
disabledReason: z.ZodOptional<z.ZodString>;
|
|
188
194
|
}, z.core.$strip>], "type">>;
|
|
189
195
|
}, z.core.$strip>>;
|
|
190
196
|
}, z.core.$strip>>;
|
|
@@ -287,6 +293,12 @@ declare const leafNodeSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
287
293
|
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
288
294
|
}, z.core.$strip>], "kind">;
|
|
289
295
|
disabled: z.ZodDefault<z.ZodBoolean>;
|
|
296
|
+
labelPlacement: z.ZodDefault<z.ZodEnum<{
|
|
297
|
+
above: "above";
|
|
298
|
+
inline: "inline";
|
|
299
|
+
}>>;
|
|
300
|
+
hint: z.ZodOptional<z.ZodString>;
|
|
301
|
+
disabledReason: z.ZodOptional<z.ZodString>;
|
|
290
302
|
}, z.core.$strip>, z.ZodObject<{
|
|
291
303
|
type: z.ZodLiteral<"alert">;
|
|
292
304
|
tone: z.ZodDefault<z.ZodEnum<{
|
|
@@ -316,6 +328,8 @@ declare const leafNodeSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
316
328
|
secondary: "secondary";
|
|
317
329
|
}>>;
|
|
318
330
|
disabled: z.ZodDefault<z.ZodBoolean>;
|
|
331
|
+
hint: z.ZodOptional<z.ZodString>;
|
|
332
|
+
disabledReason: z.ZodOptional<z.ZodString>;
|
|
319
333
|
}, z.core.$strip>>;
|
|
320
334
|
}, z.core.$strip>, z.ZodObject<{
|
|
321
335
|
type: z.ZodLiteral<"details">;
|
|
@@ -349,6 +363,52 @@ declare const leafNodeSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
349
363
|
relative: "relative";
|
|
350
364
|
}>>;
|
|
351
365
|
label: z.ZodOptional<z.ZodString>;
|
|
366
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
367
|
+
type: z.ZodLiteral<"divider">;
|
|
368
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
369
|
+
type: z.ZodLiteral<"board">;
|
|
370
|
+
columns: z.ZodArray<z.ZodObject<{
|
|
371
|
+
key: z.ZodString;
|
|
372
|
+
label: z.ZodString;
|
|
373
|
+
tone: z.ZodDefault<z.ZodEnum<{
|
|
374
|
+
success: "success";
|
|
375
|
+
default: "default";
|
|
376
|
+
warning: "warning";
|
|
377
|
+
destructive: "destructive";
|
|
378
|
+
}>>;
|
|
379
|
+
cards: z.ZodArray<z.ZodObject<{
|
|
380
|
+
key: z.ZodString;
|
|
381
|
+
title: z.ZodString;
|
|
382
|
+
subtitle: z.ZodOptional<z.ZodString>;
|
|
383
|
+
values: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
384
|
+
kind: z.ZodLiteral<"text">;
|
|
385
|
+
value: z.ZodString;
|
|
386
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
387
|
+
kind: z.ZodLiteral<"badge">;
|
|
388
|
+
value: z.ZodString;
|
|
389
|
+
tone: z.ZodDefault<z.ZodEnum<{
|
|
390
|
+
success: "success";
|
|
391
|
+
default: "default";
|
|
392
|
+
warning: "warning";
|
|
393
|
+
destructive: "destructive";
|
|
394
|
+
}>>;
|
|
395
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
396
|
+
kind: z.ZodLiteral<"date">;
|
|
397
|
+
value: z.ZodISODateTime;
|
|
398
|
+
}, z.core.$strip>], "kind">>>;
|
|
399
|
+
onPress: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
400
|
+
kind: z.ZodLiteral<"action">;
|
|
401
|
+
action: z.ZodString;
|
|
402
|
+
input: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
403
|
+
confirm: z.ZodOptional<z.ZodString>;
|
|
404
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
405
|
+
kind: z.ZodLiteral<"navigate">;
|
|
406
|
+
screen: z.ZodString;
|
|
407
|
+
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
408
|
+
}, z.core.$strip>], "kind">>;
|
|
409
|
+
}, z.core.$strip>>;
|
|
410
|
+
}, z.core.$strip>>;
|
|
411
|
+
empty: z.ZodDefault<z.ZodString>;
|
|
352
412
|
}, z.core.$strip>], "type">;
|
|
353
413
|
type LeafScreenNode = z.infer<typeof leafNodeSchema>;
|
|
354
414
|
type LeafScreenNodeInput = z.input<typeof leafNodeSchema>;
|
|
@@ -356,16 +416,18 @@ export type ScreenNode = LeafScreenNode | {
|
|
|
356
416
|
type: 'section';
|
|
357
417
|
title?: string;
|
|
358
418
|
description?: string;
|
|
359
|
-
layout: 'stack' | 'grid';
|
|
419
|
+
layout: 'stack' | 'grid' | 'row';
|
|
360
420
|
columns: number;
|
|
421
|
+
scroll: boolean;
|
|
361
422
|
children: ScreenNode[];
|
|
362
423
|
};
|
|
363
424
|
type ScreenNodeInput = LeafScreenNodeInput | {
|
|
364
425
|
type: 'section';
|
|
365
426
|
title?: string;
|
|
366
427
|
description?: string;
|
|
367
|
-
layout: 'stack' | 'grid';
|
|
368
|
-
columns
|
|
428
|
+
layout: 'stack' | 'grid' | 'row';
|
|
429
|
+
columns?: number;
|
|
430
|
+
scroll?: boolean;
|
|
369
431
|
children: ScreenNodeInput[];
|
|
370
432
|
};
|
|
371
433
|
/**
|
|
@@ -437,6 +499,8 @@ export declare const screenTreeSchema: z.ZodObject<{
|
|
|
437
499
|
secondary: "secondary";
|
|
438
500
|
}>>;
|
|
439
501
|
disabled: z.ZodDefault<z.ZodBoolean>;
|
|
502
|
+
hint: z.ZodOptional<z.ZodString>;
|
|
503
|
+
disabledReason: z.ZodOptional<z.ZodString>;
|
|
440
504
|
}, z.core.$strip>>>;
|
|
441
505
|
children: z.ZodArray<z.ZodType<ScreenRootNode, ScreenRootNodeInput, z.core.$ZodTypeInternals<ScreenRootNode, ScreenRootNodeInput>>>;
|
|
442
506
|
refreshSeconds: z.ZodOptional<z.ZodNumber>;
|
|
@@ -485,6 +549,8 @@ export declare const screenLoadResponseSchema: z.ZodObject<{
|
|
|
485
549
|
secondary: "secondary";
|
|
486
550
|
}>>;
|
|
487
551
|
disabled: z.ZodDefault<z.ZodBoolean>;
|
|
552
|
+
hint: z.ZodOptional<z.ZodString>;
|
|
553
|
+
disabledReason: z.ZodOptional<z.ZodString>;
|
|
488
554
|
}, z.core.$strip>>>;
|
|
489
555
|
children: z.ZodArray<z.ZodType<ScreenRootNode, ScreenRootNodeInput, z.core.$ZodTypeInternals<ScreenRootNode, ScreenRootNodeInput>>>;
|
|
490
556
|
refreshSeconds: z.ZodOptional<z.ZodNumber>;
|
package/dist/schema.js
CHANGED
|
@@ -41,6 +41,15 @@ export const buttonSchema = z.object({
|
|
|
41
41
|
variant: z.enum(['primary', 'secondary', 'destructive']).default('secondary'),
|
|
42
42
|
/** Shown but not pressable — a Next button on the last page, an action not yet available. */
|
|
43
43
|
disabled: z.boolean().default(false),
|
|
44
|
+
/** A short explanation shown next to the button on hover or keyboard focus. */
|
|
45
|
+
hint: z.string().min(1).max(200).optional(),
|
|
46
|
+
/**
|
|
47
|
+
* Why the button is disabled, shown under it while `disabled` is true:
|
|
48
|
+
* "Kee stopped because the patient asked for a person". Ignored when the
|
|
49
|
+
* button is enabled. A greyed control that does not say why leaves the
|
|
50
|
+
* reader guessing.
|
|
51
|
+
*/
|
|
52
|
+
disabledReason: z.string().min(1).max(200).optional(),
|
|
44
53
|
});
|
|
45
54
|
/** A table cell. Dates are ISO 8601; core formats them tenant-locale-aware. */
|
|
46
55
|
export const cellSchema = z.discriminatedUnion('kind', [
|
|
@@ -164,6 +173,16 @@ const selectSchema = z
|
|
|
164
173
|
.max(100),
|
|
165
174
|
onChange: pressSchema,
|
|
166
175
|
disabled: z.boolean().default(false),
|
|
176
|
+
/**
|
|
177
|
+
* Where the label sits. `above` (the default) is a form field. `inline` puts
|
|
178
|
+
* the label inside the control on the same line, so a row of filters is one
|
|
179
|
+
* line tall: "Status: Open".
|
|
180
|
+
*/
|
|
181
|
+
labelPlacement: z.enum(['above', 'inline']).default('above'),
|
|
182
|
+
/** A short explanation shown next to the select on hover or keyboard focus. */
|
|
183
|
+
hint: z.string().min(1).max(200).optional(),
|
|
184
|
+
/** Why the select is disabled, shown under it while `disabled` is true. */
|
|
185
|
+
disabledReason: z.string().min(1).max(200).optional(),
|
|
167
186
|
})
|
|
168
187
|
.superRefine((node, ctx) => {
|
|
169
188
|
if (node.value !== undefined && !node.options.some((option) => option.value === node.value)) {
|
|
@@ -214,6 +233,76 @@ const timestampSchema = z.object({
|
|
|
214
233
|
/** Shown before the time, muted: "Last contacted". */
|
|
215
234
|
label: z.string().max(80).optional(),
|
|
216
235
|
});
|
|
236
|
+
/**
|
|
237
|
+
* Cards in columns by stage: a sales pipeline, installs by status, accounts by
|
|
238
|
+
* health. A card carries a title, an optional subtitle, and up to 3 values that
|
|
239
|
+
* reuse the table cell kinds (a `date` shows in the viewer's zone, a `badge`
|
|
240
|
+
* keeps its tone). A card with `onPress` opens a record or calls an action.
|
|
241
|
+
* Each column shows its card count. Moving a card between columns is not part
|
|
242
|
+
* of this block yet: call an action from the record instead.
|
|
243
|
+
*/
|
|
244
|
+
const boardSchema = z
|
|
245
|
+
.object({
|
|
246
|
+
type: z.literal('board'),
|
|
247
|
+
columns: z
|
|
248
|
+
.array(z.object({
|
|
249
|
+
key: slug,
|
|
250
|
+
label: z.string().min(1).max(40),
|
|
251
|
+
/** Colours the column's count: an at-risk stage, a done stage. */
|
|
252
|
+
tone: tone.default('default'),
|
|
253
|
+
cards: z
|
|
254
|
+
.array(z.object({
|
|
255
|
+
key: z.string().min(1).max(128),
|
|
256
|
+
title: z.string().min(1).max(120),
|
|
257
|
+
subtitle: z.string().max(200).optional(),
|
|
258
|
+
values: z.array(cellSchema).max(3).optional(),
|
|
259
|
+
onPress: pressSchema.optional(),
|
|
260
|
+
}))
|
|
261
|
+
.max(100),
|
|
262
|
+
}))
|
|
263
|
+
.min(1)
|
|
264
|
+
.max(8),
|
|
265
|
+
/** Shown in a column that has no cards. */
|
|
266
|
+
empty: z.string().min(1).max(80).default('Nothing here'),
|
|
267
|
+
})
|
|
268
|
+
.superRefine((node, ctx) => {
|
|
269
|
+
const columnKeys = new Set();
|
|
270
|
+
const cardKeys = new Set();
|
|
271
|
+
let cards = 0;
|
|
272
|
+
for (const [c, column] of node.columns.entries()) {
|
|
273
|
+
if (columnKeys.has(column.key)) {
|
|
274
|
+
ctx.addIssue({
|
|
275
|
+
code: 'custom',
|
|
276
|
+
path: ['columns', c, 'key'],
|
|
277
|
+
message: `duplicate column key "${column.key}"`,
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
columnKeys.add(column.key);
|
|
281
|
+
for (const [i, card] of column.cards.entries()) {
|
|
282
|
+
if (cardKeys.has(card.key)) {
|
|
283
|
+
ctx.addIssue({
|
|
284
|
+
code: 'custom',
|
|
285
|
+
path: ['columns', c, 'cards', i, 'key'],
|
|
286
|
+
message: `duplicate card key "${card.key}"`,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
cardKeys.add(card.key);
|
|
290
|
+
}
|
|
291
|
+
cards += column.cards.length;
|
|
292
|
+
}
|
|
293
|
+
if (cards > 500) {
|
|
294
|
+
ctx.addIssue({
|
|
295
|
+
code: 'custom',
|
|
296
|
+
path: ['columns'],
|
|
297
|
+
message: `a board holds at most 500 cards, got ${cards}`,
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
/**
|
|
302
|
+
* A horizontal line that says where one part of a screen ends and the next
|
|
303
|
+
* begins. It carries no content. Use a `section` when the parts need a title.
|
|
304
|
+
*/
|
|
305
|
+
const dividerSchema = z.object({ type: z.literal('divider') });
|
|
217
306
|
const headingSchema = z.object({ type: z.literal('heading'), text: z.string().max(120) });
|
|
218
307
|
const textSchema = z.object({
|
|
219
308
|
type: z.literal('text'),
|
|
@@ -337,6 +426,8 @@ const leafNodeSchema = z.discriminatedUnion('type', [
|
|
|
337
426
|
alertSchema,
|
|
338
427
|
detailsSchema,
|
|
339
428
|
timestampSchema,
|
|
429
|
+
dividerSchema,
|
|
430
|
+
boardSchema,
|
|
340
431
|
]);
|
|
341
432
|
const MAX_SECTION_DEPTH = 8;
|
|
342
433
|
const nodeSchemas = new Map();
|
|
@@ -345,8 +436,20 @@ const sectionBranch = (children) => z.object({
|
|
|
345
436
|
type: z.literal('section'),
|
|
346
437
|
title: z.string().max(120).optional(),
|
|
347
438
|
description: z.string().max(300).optional(),
|
|
348
|
-
|
|
349
|
-
|
|
439
|
+
/**
|
|
440
|
+
* `stack`: one child per line. `grid`: `columns` equal columns. `row`:
|
|
441
|
+
* children side by side at their own width, wrapping on a narrow screen,
|
|
442
|
+
* for a filter bar or a pair of buttons that belong together.
|
|
443
|
+
*/
|
|
444
|
+
layout: z.enum(['stack', 'grid', 'row']),
|
|
445
|
+
/** Used by `grid` only. */
|
|
446
|
+
columns: z.number().int().min(1).max(4).default(1),
|
|
447
|
+
/**
|
|
448
|
+
* The section scrolls inside itself at a height the renderer chooses, so
|
|
449
|
+
* that what sits under it stays on screen: a conversation of any length
|
|
450
|
+
* above its reply box.
|
|
451
|
+
*/
|
|
452
|
+
scroll: z.boolean().default(false),
|
|
350
453
|
children: z.array(children).max(100),
|
|
351
454
|
});
|
|
352
455
|
const tabsBranch = (children) => z
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keemakr/ui-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0-dev-20261012081643",
|
|
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",
|