@box-kite/react 2.0.1 → 2.1.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/.claude/rules/box-kite-rules.md +16 -0
- package/.claude/skills/box-kite/SKILL.md +16 -0
- package/.claude/skills/box-kite/references/components.md +8 -3
- package/.claude/skills/box-kite/references/patterns.md +23 -0
- package/.cursor/rules/box-kite.mdc +16 -0
- package/AGENTS.md +19 -0
- package/BOX_AI_CONTEXT.md +562 -1
- package/BOX_KITE_AI_CONTEXT.md +562 -1
- package/README.md +39 -7
- package/catalog.cjs +1 -0
- package/catalog.d.ts +8 -0
- package/catalog.mjs +2333 -0
- package/client.cjs +1 -1
- package/client.mjs +40 -42
- package/components/agent.cjs +1 -0
- package/components/agent.d.ts +215 -0
- package/components/agent.mjs +405 -0
- package/components/chart.d.ts +1 -0
- package/components/dashboard.cjs +1 -0
- package/components/dashboard.d.ts +121 -0
- package/components/dashboard.mjs +690 -0
- package/components/dataGrid/components/dataGridBody.d.ts +2 -1
- package/components/dataGrid/components/dataGridDetailRow.d.ts +13 -2
- package/components/dataGrid/components/dataGridGroupRow.d.ts +13 -2
- package/components/dataGrid/components/dataGridRow.d.ts +13 -2
- package/components/dataGrid/contracts/dataGridContract.d.ts +66 -2
- package/components/dataGrid/models/cellModel.d.ts +3 -0
- package/components/dataGrid/models/editModel.d.ts +27 -0
- package/components/dataGrid/models/exportModel.d.ts +2 -1
- package/components/dataGrid/models/gridModel.d.ts +3 -0
- package/components/dataGrid/models/rangeModel.d.ts +119 -0
- package/components/dataGrid/models/viewportModel.d.ts +23 -2
- package/components/dataGrid/useGridNavigation.d.ts +10 -2
- package/components/dataGrid.cjs +4 -1
- package/components/dataGrid.d.ts +3 -0
- package/components/dataGrid.mjs +1056 -765
- package/components/markdown.cjs +1 -0
- package/components/markdown.d.ts +55 -0
- package/components/markdown.mjs +179 -0
- package/components/semantics.d.ts +29 -29
- package/components/skeleton.cjs +1 -0
- package/components/skeleton.d.ts +34 -0
- package/components/skeleton.mjs +25 -0
- package/dashboardSchema.cjs +1 -0
- package/dashboardSchema.mjs +78 -0
- package/docs/a11y.md +2 -3
- package/docs/catalog.md +451 -0
- package/docs/components.md +4 -0
- package/docs/index.md +3 -0
- package/docs/interop.md +237 -0
- package/docs/mcp.md +69 -0
- package/docs/props.md +3 -3
- package/interop.cjs +1 -0
- package/interop.d.ts +51 -0
- package/interop.mjs +454 -0
- package/mcp/src/data.d.ts +88 -0
- package/mcp/src/data.test.d.ts +1 -0
- package/mcp/src/engine.d.ts +23 -0
- package/mcp/src/index.d.ts +1 -0
- package/mcp/src/search.d.ts +26 -0
- package/mcp/src/search.test.d.ts +1 -0
- package/mcp/src/server.d.ts +18 -0
- package/mcp/src/server.test.d.ts +1 -0
- package/mcp/src/styles.d.ts +27 -0
- package/mcp/src/styles.test.d.ts +1 -0
- package/mcp/src/tools.d.ts +18 -0
- package/mcp/src/vocabulary.d.ts +41 -0
- package/package.json +124 -17
- package/react/spec/renderSpec.d.ts +51 -0
- package/react/spec/specBoundary.d.ts +25 -0
- package/react/spec/specRegistry.d.ts +42 -0
- package/react/spec/specRenderer.d.ts +10 -0
- package/registry/blocks/dashboard-shell/dashboard-shell.d.ts +22 -0
- package/registry/blocks/dashboard-shell/dashboard-stats.d.ts +13 -0
- package/registry/blocks/data-grid/invoice-rows.d.ts +15 -0
- package/registry/blocks/data-grid/invoices-grid.d.ts +1 -0
- package/registry/blocks/settings-form/settings-form.d.ts +17 -0
- package/spec.cjs +2 -0
- package/spec.d.ts +12 -0
- package/spec.mjs +382 -0
- package/specData.cjs +1 -0
- package/specData.mjs +69 -0
- package/specDefs.cjs +1 -0
- package/specDefs.mjs +33 -0
- package/specSchema.cjs +1 -0
- package/specSchema.mjs +88 -0
- package/utils/agent/agentUtils.d.ts +81 -0
- package/utils/catalog/catalogContracts.d.ts +19 -0
- package/utils/catalog/catalogManifest.d.ts +8 -0
- package/utils/dashboard/dashboardSchema.d.ts +18 -0
- package/utils/dashboard/dashboardUtils.d.ts +97 -0
- package/utils/interop/a2uiInterop.d.ts +82 -0
- package/utils/interop/assistantUiInterop.d.ts +34 -0
- package/utils/interop/toolInterop.d.ts +30 -0
- package/utils/spec/specData.d.ts +19 -0
- package/utils/spec/specDefs.d.ts +11 -0
- package/utils/spec/specProps.d.ts +15 -0
- package/utils/spec/specSchema.d.ts +23 -0
- package/utils/spec/specTypes.d.ts +71 -0
- package/utils/spec/specValidate.d.ts +10 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { CatalogManifest } from '@box-kite/core';
|
|
2
|
+
/**
|
|
3
|
+
* Generated by `npm run docs:catalog` — never edited by hand. What a prop *means*, extracted from the
|
|
4
|
+
* same JSDoc the reference and the AI context come from; what it *accepts* is read off the live engine,
|
|
5
|
+
* so this file says nothing that could go stale against a `Box.extend()`.
|
|
6
|
+
*/
|
|
7
|
+
declare const catalogManifest: CatalogManifest;
|
|
8
|
+
export default catalogManifest;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { CatalogSchema } from '@box-kite/core';
|
|
2
|
+
/**
|
|
3
|
+
* The layout's own shape, as a schema and the two numbers it quotes. Its own module because both the
|
|
4
|
+
* dashboard and `catalog()` want it and only one of them wants the model around it: reaching it through
|
|
5
|
+
* `dashboardUtils` would put the compaction, the drag arithmetic and the parser in the catalog entry.
|
|
6
|
+
* Plain exports rather than a namespace, so neither entry carries a wrapper for four constants.
|
|
7
|
+
*/
|
|
8
|
+
/** The layout format's own version, bumped when its shape changes and never when a dashboard does. */
|
|
9
|
+
export declare const LAYOUT_VERSION = 1;
|
|
10
|
+
/** Both ends of the column space a layout may declare, so a generated `columns: 400` cannot be rendered. */
|
|
11
|
+
export declare const MIN_COLUMNS = 1;
|
|
12
|
+
export declare const MAX_COLUMNS = 24;
|
|
13
|
+
/**
|
|
14
|
+
* The layout as JSON Schema — what a model generates a dashboard under, and the half of the contract a
|
|
15
|
+
* prompt cannot carry. Deliberately inside the subset `catalog()` emits and `<SpecRenderer>` validates,
|
|
16
|
+
* so a host can hand it to the same machinery: the schema says the shape and `parse` says the sense.
|
|
17
|
+
*/
|
|
18
|
+
export declare const LAYOUT_SCHEMA: CatalogSchema;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a widget sits, in cells. The unit is the whole point: a layout written in cells is the same
|
|
3
|
+
* layout at any width, and a drag moves by one of them rather than by a pixel somebody measured.
|
|
4
|
+
*/
|
|
5
|
+
export interface DashboardItem {
|
|
6
|
+
/** What this place belongs to — the `id` of the widget that fills it. */
|
|
7
|
+
id: string;
|
|
8
|
+
/** Column and row, both zero-based. */
|
|
9
|
+
x: number;
|
|
10
|
+
y: number;
|
|
11
|
+
/** How many columns and rows it spans, at least one of each. */
|
|
12
|
+
w: number;
|
|
13
|
+
h: number;
|
|
14
|
+
minW?: number;
|
|
15
|
+
minH?: number;
|
|
16
|
+
maxW?: number;
|
|
17
|
+
maxH?: number;
|
|
18
|
+
/** Never moved and never resized — the rest of the layout flows around it. */
|
|
19
|
+
fixed?: boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The artifact: one column space, one list of places, and a version in front of both. It is what a model
|
|
23
|
+
* emits, what a host stores and what a drag reports back, which is why it is plain JSON with no
|
|
24
|
+
* component, no callback and no measurement anywhere in it.
|
|
25
|
+
*/
|
|
26
|
+
export interface DashboardLayout {
|
|
27
|
+
version: number;
|
|
28
|
+
/** The space the items are written in. A narrower container renders a projection of it. */
|
|
29
|
+
columns: number;
|
|
30
|
+
items: DashboardItem[];
|
|
31
|
+
}
|
|
32
|
+
/** What a layout that arrived as JSON got wrong, in the shape the spec renderer reports issues in. */
|
|
33
|
+
export interface DashboardIssue {
|
|
34
|
+
code: 'not-an-object' | 'version' | 'columns' | 'items' | 'invalid-item' | 'duplicate-id';
|
|
35
|
+
/** Where it happened, printable: `items.2.w`. */
|
|
36
|
+
path: string;
|
|
37
|
+
message: string;
|
|
38
|
+
}
|
|
39
|
+
/** The pixel a cell steps by on each axis — one cell plus the gap after it. Measured once per drag. */
|
|
40
|
+
export interface DashboardStep {
|
|
41
|
+
x: number;
|
|
42
|
+
y: number;
|
|
43
|
+
}
|
|
44
|
+
declare namespace DashboardUtils {
|
|
45
|
+
const VERSION = 1;
|
|
46
|
+
const MIN_COLUMNS = 1;
|
|
47
|
+
const MAX_COLUMNS = 24;
|
|
48
|
+
/** Whether two places want the same cell. Touching edges do not overlap — `x + w` is the first column past it. */
|
|
49
|
+
function overlaps(left: DashboardItem, right: DashboardItem): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Every item clamped, then floated up and pushed down until nothing overlaps — so a layout has no holes
|
|
52
|
+
* and a widget cannot be parked in mid-air. That is what makes two dashboards of the same items compare
|
|
53
|
+
* equal, and it is why a drop below a neighbour rises to meet it.
|
|
54
|
+
*
|
|
55
|
+
* It is reading order and nothing else. A widget a drag is holding gets no priority here: settling it
|
|
56
|
+
* first floats it to the top of a board with nothing on it yet, which is every drag's opening frame
|
|
57
|
+
* (#183). Where a drop lands on an occupied cell it is `displace` that decides, before this runs.
|
|
58
|
+
*/
|
|
59
|
+
function resolve(items: readonly DashboardItem[], columns: number): DashboardItem[];
|
|
60
|
+
/** The same, as a layout. Every function here returns one of these: a change is always the whole artifact. */
|
|
61
|
+
function normalize(layout: DashboardLayout): DashboardLayout;
|
|
62
|
+
function itemOf(layout: DashboardLayout, id: string): DashboardItem | undefined;
|
|
63
|
+
/** Where a widget sits in reading order, which is the order a stacked dashboard renders in. */
|
|
64
|
+
function ranks(layout: DashboardLayout): Map<string, number>;
|
|
65
|
+
/** A widget sent to a cell. The rest of the layout moves around it rather than refusing the move. */
|
|
66
|
+
function moveTo(layout: DashboardLayout, id: string, x: number, y: number): DashboardLayout;
|
|
67
|
+
/** A widget given a size. Its own minimum and maximum are applied by `resolve`, so this only asks. */
|
|
68
|
+
function resizeTo(layout: DashboardLayout, id: string, w: number, h: number): DashboardLayout;
|
|
69
|
+
/** A widget added where there is room for it: under everything, which compaction then floats up. */
|
|
70
|
+
function add(layout: DashboardLayout, item: Omit<DashboardItem, 'x' | 'y'> & Partial<DashboardItem>): DashboardLayout;
|
|
71
|
+
function remove(layout: DashboardLayout, id: string): DashboardLayout;
|
|
72
|
+
/**
|
|
73
|
+
* The same layout in a narrower space — arithmetic, not a measurement, which is what lets every
|
|
74
|
+
* projection be a class the browser chooses between. Widths scale and round up to a cell, so a widget
|
|
75
|
+
* never projects to nothing; the compaction afterwards is what closes the holes that leaves.
|
|
76
|
+
*/
|
|
77
|
+
function project(layout: DashboardLayout, columns: number): DashboardLayout;
|
|
78
|
+
/** Whether a layout says anything new — so a drag that crossed no cell costs no render and no callback. */
|
|
79
|
+
function same(left: DashboardLayout, right: DashboardLayout): boolean;
|
|
80
|
+
/** How many cells a pointer has travelled, rounded to the nearest one. The step is a cell plus its gap. */
|
|
81
|
+
function cellsMoved(dx: number, dy: number, step: DashboardStep): {
|
|
82
|
+
columns: number;
|
|
83
|
+
rows: number;
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* A layout read from somewhere it could be anything: a model's answer, a `localStorage` string, a
|
|
87
|
+
* column of a database written by a version that has since moved on. Everything unusable is dropped and
|
|
88
|
+
* reported rather than thrown — a dashboard missing one widget is a dashboard, and an exception is not.
|
|
89
|
+
*/
|
|
90
|
+
function parse(value: unknown, fallbackColumns?: number): {
|
|
91
|
+
layout: DashboardLayout;
|
|
92
|
+
issues: DashboardIssue[];
|
|
93
|
+
};
|
|
94
|
+
/** The layout as JSON Schema: what a model generates a dashboard under, and what `<SpecRenderer>` validates. */
|
|
95
|
+
const SCHEMA: import("../../core").CatalogSchema;
|
|
96
|
+
}
|
|
97
|
+
export default DashboardUtils;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { BoxCatalog, CatalogSchema } from '@box-kite/core';
|
|
2
|
+
import { SpecNode } from '../spec/specTypes';
|
|
3
|
+
/** One component of a surface, flattened to v0.9's shape whichever version it arrived in. */
|
|
4
|
+
export interface A2uiComponent {
|
|
5
|
+
id: string;
|
|
6
|
+
component: string;
|
|
7
|
+
[prop: string]: unknown;
|
|
8
|
+
}
|
|
9
|
+
/** One surface: its components, its own data model, and what the agent said about rendering it. */
|
|
10
|
+
export interface A2uiSurface {
|
|
11
|
+
id: string;
|
|
12
|
+
catalogId?: string;
|
|
13
|
+
/** v0.8 names the root in its `beginRendering`; v0.9 settles it by convention, which is the id `root`. */
|
|
14
|
+
root?: string;
|
|
15
|
+
theme?: Record<string, unknown>;
|
|
16
|
+
components: Record<string, A2uiComponent>;
|
|
17
|
+
data: Record<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
/** Every surface an agent has opened, in the order it opened them. */
|
|
20
|
+
export interface A2uiState {
|
|
21
|
+
surfaces: Record<string, A2uiSurface>;
|
|
22
|
+
order: string[];
|
|
23
|
+
}
|
|
24
|
+
export interface A2uiSpecOptions {
|
|
25
|
+
/** Which component to start from. Otherwise the surface's own root, and then the id `root`. */
|
|
26
|
+
root?: string;
|
|
27
|
+
/**
|
|
28
|
+
* `catalog()`, where the agent generated against this library's own components: a prop the catalog
|
|
29
|
+
* lists as an event becomes an `on` binding rather than a value. Without one, only A2UI's `action` is.
|
|
30
|
+
*/
|
|
31
|
+
catalog?: {
|
|
32
|
+
components: Record<string, {
|
|
33
|
+
events?: string[];
|
|
34
|
+
}>;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export interface A2uiCatalogOptions {
|
|
38
|
+
/** The document's own id, which is what an agent's `createSurface.catalogId` names. */
|
|
39
|
+
catalogId?: string;
|
|
40
|
+
title?: string;
|
|
41
|
+
description?: string;
|
|
42
|
+
}
|
|
43
|
+
declare namespace A2uiInterop {
|
|
44
|
+
/** The id v0.9 settles the root by, since its `createSurface` does not carry one. */
|
|
45
|
+
const ROOT_ID = "root";
|
|
46
|
+
/** The surface a message means when it names none, which is what the published renderers call it. */
|
|
47
|
+
const DEFAULT_SURFACE = "main";
|
|
48
|
+
const EMPTY: A2uiState;
|
|
49
|
+
/**
|
|
50
|
+
* One message, whichever of v0.8 and v0.9 it is written in. The same state comes back where the
|
|
51
|
+
* message changed nothing or is not an A2UI message at all — a transport carries plenty that is not.
|
|
52
|
+
*/
|
|
53
|
+
function apply(state: A2uiState, message: unknown): A2uiState;
|
|
54
|
+
/** A whole stream, oldest first. A JSONL transport is `applyAll(state, lines.map(JSON.parse))`. */
|
|
55
|
+
function applyAll(state: A2uiState, messages: readonly unknown[]): A2uiState;
|
|
56
|
+
/** A surface by id, or the first one opened — which is the whole of it for an agent that opens one. */
|
|
57
|
+
function surface(state: A2uiState, id?: string): A2uiSurface | null;
|
|
58
|
+
/**
|
|
59
|
+
* A surface as one `<SpecRenderer>` tree. A component nothing reaches from the root is not rendered —
|
|
60
|
+
* an agent streams a leaf before the branch that holds it, so a half-arrived surface is the ordinary
|
|
61
|
+
* case rather than an error, and the node appears when the message naming it does.
|
|
62
|
+
*/
|
|
63
|
+
function toSpec(surface: A2uiSurface | null, options?: A2uiSpecOptions): SpecNode | null;
|
|
64
|
+
/**
|
|
65
|
+
* `catalog()` as an A2UI catalog document. The components and the values their props take are the
|
|
66
|
+
* same ones; what changes is the shape around them — a component carries its own `id`, its type is a
|
|
67
|
+
* property rather than the key above it, and its children are **ids** rather than nested nodes, which
|
|
68
|
+
* is the whole of what an adjacency list is.
|
|
69
|
+
*
|
|
70
|
+
* Every event the catalog names becomes a string, because a JSON message cannot carry a function: what
|
|
71
|
+
* an agent writes is the name of an action, and `onAction` is where the host decides what it does.
|
|
72
|
+
*/
|
|
73
|
+
/**
|
|
74
|
+
* One component of a catalog document, self-contained. A `$ref` resolves against the *document*, so a
|
|
75
|
+
* component lifted out of one on its own points at nothing — which is what every consumer that
|
|
76
|
+
* converts a component at a time does (`z.fromJSONSchema` for CopilotKit's renderer and json-render
|
|
77
|
+
* alike). Measured against zod 4.6: it throws `Reference not found: #/$defs/color`.
|
|
78
|
+
*/
|
|
79
|
+
function componentSchema(document: Record<string, unknown>, name: string): CatalogSchema | null;
|
|
80
|
+
function catalogDocument(catalog: BoxCatalog, options?: A2uiCatalogOptions): Record<string, unknown>;
|
|
81
|
+
}
|
|
82
|
+
export default A2uiInterop;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { SpecNode } from '../spec/specTypes';
|
|
2
|
+
/** assistant-ui's node: a string renders as text, an object is a component. */
|
|
3
|
+
export type GenerativeUiNode = string | {
|
|
4
|
+
component: string;
|
|
5
|
+
props?: Record<string, unknown>;
|
|
6
|
+
children?: readonly GenerativeUiNode[];
|
|
7
|
+
key?: string;
|
|
8
|
+
};
|
|
9
|
+
/** assistant-ui's root, which is one node or several. */
|
|
10
|
+
export interface GenerativeUiSpec {
|
|
11
|
+
root: GenerativeUiNode | readonly GenerativeUiNode[];
|
|
12
|
+
}
|
|
13
|
+
/** What `fromSpec` could not carry across, since their spec has nowhere to put it. */
|
|
14
|
+
export interface GenerativeUiLoss {
|
|
15
|
+
/** `data-binding`, `repeat` or `event` — the three things their shape has no room for. */
|
|
16
|
+
code: 'data-binding' | 'repeat' | 'event';
|
|
17
|
+
path: string;
|
|
18
|
+
}
|
|
19
|
+
declare namespace AssistantUiInterop {
|
|
20
|
+
/**
|
|
21
|
+
* Their spec as ours. Several roots become the children of nothing, so a multi-root spec is rendered
|
|
22
|
+
* by mapping this over `spec.root` rather than being wrapped in a container nobody asked for.
|
|
23
|
+
*/
|
|
24
|
+
function toSpec(spec: GenerativeUiSpec | null | undefined): SpecNode[];
|
|
25
|
+
/**
|
|
26
|
+
* Ours as theirs, with what could not come along reported rather than dropped in silence. A named
|
|
27
|
+
* slot has no counterpart either and is left out with the rest — their nodes have one children list.
|
|
28
|
+
*/
|
|
29
|
+
function fromSpec(spec: SpecNode | readonly SpecNode[]): {
|
|
30
|
+
spec: GenerativeUiSpec;
|
|
31
|
+
losses: GenerativeUiLoss[];
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export default AssistantUiInterop;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ApprovalDecision, ToolCallStatus } from '../agent/agentUtils';
|
|
2
|
+
/** Which of the two cards a part belongs to. A call is shown; a question is answered. */
|
|
3
|
+
export type ToolPartKind = 'call' | 'approval';
|
|
4
|
+
/** A tool call in this library's words, whichever runtime's words arrived. */
|
|
5
|
+
export interface ToolPart {
|
|
6
|
+
kind: ToolPartKind;
|
|
7
|
+
/** Where the call is, for `<ToolCallCard status>`. An approval waiting on a person is `pending`. */
|
|
8
|
+
status: ToolCallStatus;
|
|
9
|
+
/** What was decided, for `<ApprovalCard decision>`. `null` is a question nobody has answered yet. */
|
|
10
|
+
decision: ApprovalDecision | null;
|
|
11
|
+
/** The arguments, where the part carried them under any of its runtimes' names. */
|
|
12
|
+
input?: unknown;
|
|
13
|
+
output?: unknown;
|
|
14
|
+
/** The failure, as text, where the part reported one. */
|
|
15
|
+
error?: string;
|
|
16
|
+
}
|
|
17
|
+
declare namespace ToolInterop {
|
|
18
|
+
/**
|
|
19
|
+
* A part from any of the three runtimes that hand you one, in this library's words. `null` is a value
|
|
20
|
+
* that is not a tool part at all — the caller decides what that means, since a half-streamed message
|
|
21
|
+
* carrying nothing yet is ordinary.
|
|
22
|
+
*/
|
|
23
|
+
function toolPart(value: unknown): ToolPart | null;
|
|
24
|
+
/**
|
|
25
|
+
* AG-UI is the odd one out: it reports *events*, not parts, so a card needs a fold rather than a
|
|
26
|
+
* mapping. One call per event, oldest first, keyed by `toolCallId`.
|
|
27
|
+
*/
|
|
28
|
+
function applyEvent(parts: Readonly<Record<string, ToolPart>>, event: unknown): Record<string, ToolPart>;
|
|
29
|
+
}
|
|
30
|
+
export default ToolInterop;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { SpecRef, SpecScope } from './specTypes';
|
|
2
|
+
declare namespace SpecData {
|
|
3
|
+
/** A reference is a plain object carrying exactly one of the three keys, and nothing beside it. */
|
|
4
|
+
function isRef(value: unknown): value is SpecRef;
|
|
5
|
+
/** What a reference points at, and whether it pointed at anything — `undefined` is an answer either way. */
|
|
6
|
+
function resolve(ref: SpecRef, scope: SpecScope): {
|
|
7
|
+
value: unknown;
|
|
8
|
+
found: boolean;
|
|
9
|
+
};
|
|
10
|
+
/** The text of a reference, for the message that says it resolved to nothing. */
|
|
11
|
+
function pathOf(ref: SpecRef): string;
|
|
12
|
+
/**
|
|
13
|
+
* A value with every reference inside it resolved — a prop is `{ $data: … }`, an array of them, or an
|
|
14
|
+
* object with one in a corner (a gradient's stops, a chart's series). Reported rather than dropped:
|
|
15
|
+
* the caller decides, because a reference that resolves to nothing mid-stream is ordinary.
|
|
16
|
+
*/
|
|
17
|
+
function deep(value: unknown, scope: SpecScope, onMissing?: (path: string) => void, depth?: number): unknown;
|
|
18
|
+
}
|
|
19
|
+
export default SpecData;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { CatalogSchema } from '@box-kite/core';
|
|
2
|
+
declare namespace SpecDefs {
|
|
3
|
+
/**
|
|
4
|
+
* A component's props, with its local `$defs` lifted into `defs` (which is mutated). The colour grammar
|
|
5
|
+
* is the same object for every component, so the twenty-six colour props across a whole catalog share
|
|
6
|
+
* one definition — and a host's custom schema that happens to name `color` something else is renamed
|
|
7
|
+
* rather than silently taking the palette's meaning.
|
|
8
|
+
*/
|
|
9
|
+
function hoist(props: CatalogSchema, defs: Record<string, CatalogSchema>): CatalogSchema;
|
|
10
|
+
}
|
|
11
|
+
export default SpecDefs;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { SpecAction, SpecIssue, SpecRules, SpecScope } from './specTypes';
|
|
2
|
+
declare namespace SpecProps {
|
|
3
|
+
interface Resolved {
|
|
4
|
+
/** Everything the schema allowed, resolved. */
|
|
5
|
+
props: Record<string, unknown>;
|
|
6
|
+
/** The events the node bound, for the renderer to turn into functions. */
|
|
7
|
+
actions: Record<string, SpecAction>;
|
|
8
|
+
issues: SpecIssue[];
|
|
9
|
+
/** Required props that did not arrive, or were refused. A node with any of these cannot render. */
|
|
10
|
+
missing: string[];
|
|
11
|
+
}
|
|
12
|
+
/** The props pass for one node: resolved, validated, and an issue for everything left out. */
|
|
13
|
+
function resolve(node: Record<string, unknown>, rules: SpecRules, scope: SpecScope, path: string): Resolved;
|
|
14
|
+
}
|
|
15
|
+
export default SpecProps;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { CatalogSchema } from '@box-kite/core';
|
|
2
|
+
/** A component, as much of it as a tree schema needs. A `catalog()` entry is one of these already. */
|
|
3
|
+
export interface SpecSchemaComponent {
|
|
4
|
+
description?: string;
|
|
5
|
+
props?: CatalogSchema;
|
|
6
|
+
slots?: string[];
|
|
7
|
+
events?: string[];
|
|
8
|
+
}
|
|
9
|
+
export interface SpecSchemaSource {
|
|
10
|
+
components: Record<string, SpecSchemaComponent>;
|
|
11
|
+
}
|
|
12
|
+
export interface SpecSchemaOptions {
|
|
13
|
+
/** Which components may be the root of the tree. Every one of them by default. */
|
|
14
|
+
root?: string[];
|
|
15
|
+
/**
|
|
16
|
+
* Whether a prop may be a `{ $data: … }` reference and a node may `repeat`. Off by default: it widens
|
|
17
|
+
* every prop in the document with an `anyOf`, which is a cost a static view should not pay.
|
|
18
|
+
*/
|
|
19
|
+
bindings?: boolean;
|
|
20
|
+
}
|
|
21
|
+
/** The JSON Schema a generated view has to conform to: a tree of the components this source allows. */
|
|
22
|
+
export declare function specSchema(source: SpecSchemaSource, options?: SpecSchemaOptions): CatalogSchema;
|
|
23
|
+
export default specSchema;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { CatalogSchema } from '@box-kite/core';
|
|
2
|
+
/** A value read out of the data the spec is rendered against: `{ $data: 'user.name' }`. */
|
|
3
|
+
export interface SpecDataRef {
|
|
4
|
+
/** A dot path (`stats.revenue.0`) or a JSON Pointer (`/stats/revenue/0`). Empty is the whole of it. */
|
|
5
|
+
$data: string;
|
|
6
|
+
}
|
|
7
|
+
/** The current item of the enclosing `repeat`. `{ $item: '' }` is the item itself. */
|
|
8
|
+
export interface SpecItemRef {
|
|
9
|
+
$item: string;
|
|
10
|
+
}
|
|
11
|
+
/** The current index of the enclosing `repeat`, from zero. */
|
|
12
|
+
export interface SpecIndexRef {
|
|
13
|
+
$index: true;
|
|
14
|
+
}
|
|
15
|
+
/** Anywhere a value can stand, a reference to one can stand instead. */
|
|
16
|
+
export type SpecRef = SpecDataRef | SpecItemRef | SpecIndexRef;
|
|
17
|
+
/** What an event does: it tells the host, which is the only thing that may decide what happens next. */
|
|
18
|
+
export interface SpecAction {
|
|
19
|
+
action: string;
|
|
20
|
+
/** Sent back with the action, resolved the way a prop is. */
|
|
21
|
+
payload?: unknown;
|
|
22
|
+
}
|
|
23
|
+
/** One node of a generated tree, or a leaf that is text. */
|
|
24
|
+
export type SpecChild = SpecNode | SpecRef | string | number | boolean | null;
|
|
25
|
+
export interface SpecNode {
|
|
26
|
+
/** The component to render. A name the registry does not hold renders nothing. */
|
|
27
|
+
type: string;
|
|
28
|
+
/** React's key, where the host wants a node's identity to survive a re-order. */
|
|
29
|
+
key?: string;
|
|
30
|
+
/** Everything the component's own schema allows, and nothing else. */
|
|
31
|
+
props?: Record<string, unknown>;
|
|
32
|
+
/** The default slot. */
|
|
33
|
+
children?: SpecChild | SpecChild[];
|
|
34
|
+
/** The component's named slots — `Tooltip`'s `content`, a form control's `label`. */
|
|
35
|
+
slots?: Record<string, SpecChild | SpecChild[]>;
|
|
36
|
+
/** An event prop bound to an action the host handles: `{ onClick: 'refresh' }`. */
|
|
37
|
+
on?: Record<string, SpecAction | string>;
|
|
38
|
+
/** Render this node once per item of an array. `$item` and `$index` address the item inside it. */
|
|
39
|
+
repeat?: SpecRef;
|
|
40
|
+
}
|
|
41
|
+
/** Why a node, a prop or a child did not render. Advisory: the tree renders around every one of them. */
|
|
42
|
+
export type SpecIssueCode = 'unknown-component' | 'unknown-prop' | 'invalid-prop' | 'missing-prop' | 'unknown-slot' | 'unknown-event' | 'unresolved-data' | 'invalid-child' | 'invalid-repeat' | 'too-deep' | 'too-many-nodes' | 'render-error';
|
|
43
|
+
export interface SpecIssue {
|
|
44
|
+
code: SpecIssueCode;
|
|
45
|
+
/** Where in the spec it happened, as a path that can be printed: `children.1.props.bgColor`. */
|
|
46
|
+
path: string;
|
|
47
|
+
message: string;
|
|
48
|
+
/** The component the node named, where it named one. */
|
|
49
|
+
component?: string;
|
|
50
|
+
prop?: string;
|
|
51
|
+
}
|
|
52
|
+
/** What the renderer needs to know about one component. The implementation is the registry's half. */
|
|
53
|
+
export interface SpecRules {
|
|
54
|
+
/** What its props may be. No schema at all means no props: a component is opened up on purpose. */
|
|
55
|
+
props?: CatalogSchema;
|
|
56
|
+
/** Where children may go. `default` is the ordinary children slot. */
|
|
57
|
+
slots: string[];
|
|
58
|
+
/** The props a spec may bind an action to. Nothing else can ever become a function. */
|
|
59
|
+
events: string[];
|
|
60
|
+
description?: string;
|
|
61
|
+
}
|
|
62
|
+
/** The data a reference is resolved against, plus whatever `repeat` put in scope. */
|
|
63
|
+
export interface SpecScope {
|
|
64
|
+
data?: unknown;
|
|
65
|
+
item?: unknown;
|
|
66
|
+
index?: number;
|
|
67
|
+
/** Whether an `$item`/`$index` reference means anything here at all. */
|
|
68
|
+
repeating?: boolean;
|
|
69
|
+
}
|
|
70
|
+
/** The ordinary children slot, under the name the catalog gives it. */
|
|
71
|
+
export declare const DEFAULT_SLOT = "default";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { CatalogSchema } from '@box-kite/core';
|
|
2
|
+
declare namespace SpecValidate {
|
|
3
|
+
/** A name a spec may set at all. */
|
|
4
|
+
function isSafeKey(key: string): boolean;
|
|
5
|
+
/** An object a spec could have written: `JSON.parse` produces these and nothing else. */
|
|
6
|
+
function isPlainObject(value: unknown): value is Record<string, unknown>;
|
|
7
|
+
/** Whether a value is one this schema allows. The whole of it: an invalid part makes the value invalid. */
|
|
8
|
+
function matches(schema: CatalogSchema, value: unknown, root?: CatalogSchema): boolean;
|
|
9
|
+
}
|
|
10
|
+
export default SpecValidate;
|