@texuli/spec 0.4.0 → 0.6.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 +39 -10
- package/dist/generated/typescript/blueprint.d.ts +44 -3
- package/dist/generated/typescript/blueprint.js +1 -1
- package/dist/generated/typescript/catalog-schema.js +1 -1
- package/dist/generated/typescript/diagnostics.js +1 -1
- package/dist/generated/typescript/manifest.js +1 -1
- package/dist/generated/typescript/vocabulary.d.ts +44 -2
- package/dist/generated/typescript/vocabulary.js +6 -2
- package/dist/generated/typescript/workflow.js +1 -1
- package/dist/migrations/0.4.0-0.5.0.d.ts +8 -0
- package/dist/migrations/0.4.0-0.5.0.js +11 -0
- package/dist/migrations/0.5.0-0.6.0.d.ts +9 -0
- package/dist/migrations/0.5.0-0.6.0.js +12 -0
- package/dist/migrations/index.js +4 -0
- package/dist/motion.d.ts +40 -0
- package/dist/motion.js +133 -0
- package/dist/stream/assembler.d.ts +101 -0
- package/dist/stream/assembler.js +284 -0
- package/dist/stream/index.d.ts +11 -0
- package/dist/stream/index.js +11 -0
- package/dist/stream/source.d.ts +22 -0
- package/dist/stream/source.js +72 -0
- package/dist/stream/tokenizer.d.ts +67 -0
- package/dist/stream/tokenizer.js +383 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +9 -1
package/README.md
CHANGED
|
@@ -14,9 +14,14 @@ by Texuli's Kotlin Multiplatform twin. The package is framework-free: no
|
|
|
14
14
|
DOM, no Svelte, no Node APIs and no runtime dependencies.
|
|
15
15
|
|
|
16
16
|
> **Status: 0.x release.** Texuli is in development. The packages are
|
|
17
|
-
> published to npm as `0.
|
|
18
|
-
> stable release). Under 0.x, a new minor (`0.
|
|
19
|
-
> changes, so pin the exact version or use `^0.
|
|
17
|
+
> published to npm as `0.6.0`, a pre-1.0 release (1.0.0 will be the first
|
|
18
|
+
> stable release). Under 0.x, a new minor (`0.7.0`) may contain breaking
|
|
19
|
+
> changes, so pin the exact version or use `^0.6.0`, which accepts only 0.6.x.
|
|
20
|
+
|
|
21
|
+
> **New in `0.6.0`.** `@texuli/spec@0.6.0` carries **spec 0.6.0**: the
|
|
22
|
+
> closed motion vocabulary (`@texuli/spec/motion`, below), and the new
|
|
23
|
+
> `@texuli/spec/stream` subpath reads streamed blueprints. Every `0.5.0`
|
|
24
|
+
> envelope migrates by stamping `spec`.
|
|
20
25
|
|
|
21
26
|
> **New in `0.4.0`.** `@texuli/spec@0.4.0` carries **spec 0.4.0**: spec
|
|
22
27
|
> 0.3.0 (state, bindings, closed actions, `reorder`, workflow graphs), spec
|
|
@@ -56,7 +61,7 @@ import {
|
|
|
56
61
|
validateInstance,
|
|
57
62
|
} from '@texuli/spec';
|
|
58
63
|
|
|
59
|
-
SPEC_VERSION; // the spec version: '0.
|
|
64
|
+
SPEC_VERSION; // the spec version: '0.6.0' in @texuli/spec@0.6.0
|
|
60
65
|
SPEC_COMPONENT_IDS.includes('alert'); // true: the closed component vocabulary
|
|
61
66
|
|
|
62
67
|
// The dialect validator: a closed subset of JSON Schema 2020-12.
|
|
@@ -88,7 +93,7 @@ import { type Schema, type SpecCatalog, validateBlueprint } from '@texuli/spec';
|
|
|
88
93
|
import { migrateBlueprint } from '@texuli/spec/migrate';
|
|
89
94
|
import { validateWorkflowGraph } from '@texuli/spec/workflow';
|
|
90
95
|
|
|
91
|
-
const migrated = migrateBlueprint(blueprint); // 0.2.0 → 0.
|
|
96
|
+
const migrated = migrateBlueprint(blueprint); // 0.2.0 → … → 0.5.0 → 0.6.0; never throws
|
|
92
97
|
const result = validateBlueprint(migrated.blueprint, {
|
|
93
98
|
blueprintSchema: blueprintSchemaJson as Schema,
|
|
94
99
|
catalog: componentsJson as SpecCatalog,
|
|
@@ -120,6 +125,8 @@ warning without failing.
|
|
|
120
125
|
| `@texuli/spec/workflow` | Runtime, opt-in: workflow graph validation | `validateWorkflowGraph` (pass it in `SpecDocuments.validateWorkflowGraph`) |
|
|
121
126
|
| `@texuli/spec/migrate` | Runtime, opt-in: envelope migrations | `migrateBlueprint`, `SPEC_MIGRATIONS`, `UNDECLARED_SPEC_VERSION` |
|
|
122
127
|
| `@texuli/spec/surface` | Runtime: the state surface rules every validator shares (no imports) | `checkStateSurface`, `surfaceInputs`, `SPEC_CONTROL_STATE_TYPES`, `SURFACE_PLAYER_CODES`, `LIST_TEXT_PATTERN` |
|
|
128
|
+
| `@texuli/spec/motion` | Runtime (new in `0.6.0`, spec `0.6.0`): the closed motion vocabulary and its check, shared by the catalog and the player ([motion.md](https://github.com/DailybotHQ/texuli/blob/main/packages/spec/docs/motion.md)) | `SPEC_MOTION_PRESETS`, `SPEC_MOTION_DURATIONS`, `SPEC_MOTION_STAGGERS`, `SPEC_MOTION_LEVELS`, `checkNodeMotion`, `checkEnvelopeMotion` |
|
|
129
|
+
| `@texuli/spec/stream` | Runtime, opt-in (new in `0.6.0`): streamed blueprints ([stream.md](https://github.com/DailybotHQ/texuli/blob/main/packages/spec/docs/stream.md)) | `createJsonTokenizer`, `createBlueprintAssembler`, `createBlueprintStream`, `STREAM_NODE_ORDER` |
|
|
123
130
|
| `@texuli/spec/codegen` | Build time: generation and conformance | `buildSpec`, `projectCatalog`, `checkConformance`, `checkCatalogContract`, `formatJson`, `nextSpecVersion`, `checkVersionHistory` |
|
|
124
131
|
|
|
125
132
|
## Key guarantees
|
|
@@ -148,6 +155,19 @@ warning without failing.
|
|
|
148
155
|
component slides. The change is additive: every 0.3.0 envelope is a valid
|
|
149
156
|
0.4.0 envelope, and the `0.3.0 → 0.4.0` migration only stamps `spec`. The
|
|
150
157
|
deck model itself is validated by `@texuli/deck`, not by this package.
|
|
158
|
+
- **Motion as data (spec 0.6.0, new in `0.6.0`).** A node may declare `motion`
|
|
159
|
+
(`enter` and `exit` presets `fade`, `rise`, `scale`, `slide-start` and
|
|
160
|
+
`slide-end`; `layout`; `stagger` and `duration` in token steps) and the
|
|
161
|
+
envelope a `motion.level` (`full`, `subtle`, `none`). Names map to the
|
|
162
|
+
motion tokens: a blueprint never carries CSS, keyframes, milliseconds or
|
|
163
|
+
code, and anything else is refused. The `0.5.0 → 0.6.0` migration only
|
|
164
|
+
stamps `spec`.
|
|
165
|
+
- **Streams parse, never guess.** `@texuli/spec/stream` (new in `0.6.0`)
|
|
166
|
+
reads a blueprint split anywhere in linear time under a byte budget and a
|
|
167
|
+
depth cap, reports a node only once its shell (everything but
|
|
168
|
+
`children`) has closed, and refuses duplicate and prototype keys. It
|
|
169
|
+
judges no rule: the catalog checks each node, and the complete draft
|
|
170
|
+
goes through `validateDraft`.
|
|
151
171
|
- **Structure only.** This validator checks structure. URL policy, tree
|
|
152
172
|
limits and rendering live in the runtime validator of
|
|
153
173
|
[`@texuli/catalog`](https://www.npmjs.com/package/@texuli/catalog). The
|
|
@@ -190,11 +210,16 @@ catalog hash, and from 0.3.0 may declare the exact spec version it was
|
|
|
190
210
|
written for (`spec`; omitted means 0.2.0). `migrateBlueprint`
|
|
191
211
|
(`@texuli/spec/migrate`) brings an
|
|
192
212
|
envelope up to the current spec with pure, per-version steps
|
|
193
|
-
(`src/migrations/`: `0.2.0 → 0.3.0
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
`
|
|
197
|
-
`
|
|
213
|
+
(`src/migrations/`: `0.2.0 → 0.3.0`, `0.3.0 → 0.4.0`, `0.4.0 → 0.5.0` and
|
|
214
|
+
`0.5.0 → 0.6.0`, each of which only stamps `spec`); a compatible version range is planned,
|
|
215
|
+
not built. `@texuli/spec@0.6.0` carries spec `0.6.0` (digest
|
|
216
|
+
`37141b85b9ab9f02af849a62a9c97ba729d6c5c2705130290bcdf45b308ea4cc`), which
|
|
217
|
+
adds the closed motion vocabulary (ADR-012); `@texuli/spec@0.5.0` carried
|
|
218
|
+
spec `0.5.0`, which added the `data-cohort-table`,
|
|
219
|
+
`data-notification-inbox`, `data-filter-builder` and `time-field` catalog
|
|
220
|
+
ids, and `@texuli/spec@0.4.0` spec `0.4.0` (digest
|
|
221
|
+
`fac29f542b16ddb78ab401c508e5b8346f655991c56e25aa811f4931661a8cb3`). Every
|
|
222
|
+
pin is in `versions.json`.
|
|
198
223
|
|
|
199
224
|
The full rules (the digest, `versions.json` pins, regeneration and the
|
|
200
225
|
conformance harness) are in
|
|
@@ -209,6 +234,10 @@ conformance harness) are in
|
|
|
209
234
|
[packages/spec](https://github.com/DailybotHQ/texuli/tree/main/packages/spec)
|
|
210
235
|
- The contract in depth (the JSON Schema dialect, projections, conformance
|
|
211
236
|
and versioning): [contract.md](https://github.com/DailybotHQ/texuli/blob/main/packages/spec/docs/contract.md)
|
|
237
|
+
- The motion vocabulary (spec 0.6.0):
|
|
238
|
+
[motion.md](https://github.com/DailybotHQ/texuli/blob/main/packages/spec/docs/motion.md)
|
|
239
|
+
- Streamed blueprints (the incremental tokenizer, the canonical order and
|
|
240
|
+
node shells; new in `0.6.0`): [stream.md](https://github.com/DailybotHQ/texuli/blob/main/packages/spec/docs/stream.md)
|
|
212
241
|
- The Kotlin Multiplatform twin that consumes the generated models:
|
|
213
242
|
[native/README.md](https://github.com/DailybotHQ/texuli/blob/main/native/README.md)
|
|
214
243
|
- Architecture: [ARCHITECTURE.md](https://github.com/DailybotHQ/texuli/blob/main/docs/ARCHITECTURE.md)
|
|
@@ -47,7 +47,10 @@ export interface BlueprintEditOp {
|
|
|
47
47
|
tree?: BlueprintNode;
|
|
48
48
|
}
|
|
49
49
|
export type BlueprintNodePath = readonly number[];
|
|
50
|
-
/**
|
|
50
|
+
/**
|
|
51
|
+
* One catalog node: id, props, children (each with an optional named slot), when, bind, on and
|
|
52
|
+
* motion.
|
|
53
|
+
*/
|
|
51
54
|
export interface BlueprintNode {
|
|
52
55
|
/** A catalog component id. */
|
|
53
56
|
id: string;
|
|
@@ -63,6 +66,7 @@ export interface BlueprintNode {
|
|
|
63
66
|
/** Two-way bindings: a prop the component lists as bindable → a $state binding it writes back. */
|
|
64
67
|
bind?: Readonly<Record<string, BlueprintBinding>>;
|
|
65
68
|
on?: BlueprintEventMap;
|
|
69
|
+
motion?: BlueprintNodeMotion;
|
|
66
70
|
}
|
|
67
71
|
/**
|
|
68
72
|
* Shows the node when true (audit G07): the closed Condition AST of the blocks formula grammar.
|
|
@@ -185,11 +189,47 @@ export interface BlueprintReorder {
|
|
|
185
189
|
pull?: 'move' | 'clone' | 'none';
|
|
186
190
|
disabled?: boolean;
|
|
187
191
|
}
|
|
192
|
+
/**
|
|
193
|
+
* A closed motion preset (ADR-013): fade, rise (fade in from the block end), scale (fade and grow
|
|
194
|
+
* from 96%), slide-start or slide-end (fade in from the inline start or end, mirrored right to
|
|
195
|
+
* left). The runtime maps each to token keyframes; a blueprint never carries keyframes.
|
|
196
|
+
*/
|
|
197
|
+
export type BlueprintMotionPreset = 'fade' | 'rise' | 'scale' | 'slide-start' | 'slide-end';
|
|
198
|
+
/** A duration token step (@texuli/tokens motion durations), never milliseconds. */
|
|
199
|
+
export type BlueprintMotionDuration = 'fast' | 'base' | 'slow';
|
|
200
|
+
/**
|
|
201
|
+
* The offset between the entering children of this node, in token steps: none, fast or base. The
|
|
202
|
+
* runtime caps the whole spread.
|
|
203
|
+
*/
|
|
204
|
+
export type BlueprintMotionStagger = 'none' | 'fast' | 'base';
|
|
205
|
+
/**
|
|
206
|
+
* A motion ceiling (ADR-013): full, subtle (shorter, no travel or scale) or none (instant). The
|
|
207
|
+
* host and the reader's reduced-motion preference can only lower it.
|
|
208
|
+
*/
|
|
209
|
+
export type BlueprintMotionLevel = 'full' | 'subtle' | 'none';
|
|
210
|
+
/**
|
|
211
|
+
* How a node moves (spec 0.6.0, ADR-012): named presets and token steps only. Nothing here is CSS,
|
|
212
|
+
* a duration in milliseconds or code. The server paints the end state, and nothing plays on
|
|
213
|
+
* hydration or under reduced motion.
|
|
214
|
+
*/
|
|
215
|
+
export interface BlueprintNodeMotion {
|
|
216
|
+
enter?: BlueprintMotionPreset;
|
|
217
|
+
exit?: BlueprintMotionPreset;
|
|
218
|
+
/** Animate a change of this node's position or size among its siblings (FLIP). */
|
|
219
|
+
layout?: boolean;
|
|
220
|
+
stagger?: BlueprintMotionStagger;
|
|
221
|
+
duration?: BlueprintMotionDuration;
|
|
222
|
+
}
|
|
223
|
+
/** The blueprint's motion settings (spec 0.6.0): the level every node motion plays at. */
|
|
224
|
+
export interface BlueprintEnvelopeMotion {
|
|
225
|
+
level: BlueprintMotionLevel;
|
|
226
|
+
}
|
|
188
227
|
/**
|
|
189
228
|
* Envelope version 1 around one catalog tree (ADR-004, audit G13). Mirrors what
|
|
190
229
|
* @texuli/catalog/envelope reads; a declared status, activation or tier is display data, never
|
|
191
230
|
* authority. Spec 0.4.0 (ADR-008 + PLAN_008 deck encoding) adds an optional spec version, local
|
|
192
|
-
* state and a flow.
|
|
231
|
+
* state and a flow; spec 0.6.0 (ADR-012, ADR-013) adds the closed motion vocabulary: a node motion
|
|
232
|
+
* and the envelope motion level. Planned minor additions: the native profile and several roots.
|
|
193
233
|
*/
|
|
194
234
|
export interface BlueprintEnvelope {
|
|
195
235
|
format: 'texuli-blueprint';
|
|
@@ -213,11 +253,12 @@ export interface BlueprintEnvelope {
|
|
|
213
253
|
/**
|
|
214
254
|
* The spec version the envelope was written for. Omitted means 0.2.0; migrateBlueprint stamps it.
|
|
215
255
|
*/
|
|
216
|
-
spec?: '0.3.0' | '0.4.0';
|
|
256
|
+
spec?: '0.3.0' | '0.4.0' | '0.5.0' | '0.6.0';
|
|
217
257
|
/**
|
|
218
258
|
* Local state declarations (ADR-008), at most 64. Names, counts and per-type rules are checked by
|
|
219
259
|
* the validator.
|
|
220
260
|
*/
|
|
221
261
|
state?: Readonly<Record<string, BlueprintStateDeclaration>>;
|
|
222
262
|
flow?: BlueprintFlow;
|
|
263
|
+
motion?: BlueprintEnvelopeMotion;
|
|
223
264
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// Generated by @texuli/spec from schemas/blueprint.schema.json. Do not edit: run the spec generator.
|
|
2
|
-
// Spec 0.
|
|
2
|
+
// Spec 0.6.0, digest 37141b85b9ab9f02af849a62a9c97ba729d6c5c2705130290bcdf45b308ea4cc
|
|
3
3
|
export {};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// Generated by @texuli/spec from schemas/catalog.schema.json. Do not edit: run the spec generator.
|
|
2
|
-
// Spec 0.
|
|
2
|
+
// Spec 0.6.0, digest 37141b85b9ab9f02af849a62a9c97ba729d6c5c2705130290bcdf45b308ea4cc
|
|
3
3
|
export {};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// Generated by @texuli/spec from schemas/diagnostics.schema.json. Do not edit: run the spec generator.
|
|
2
|
-
// Spec 0.
|
|
2
|
+
// Spec 0.6.0, digest 37141b85b9ab9f02af849a62a9c97ba729d6c5c2705130290bcdf45b308ea4cc
|
|
3
3
|
export {};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// Generated by @texuli/spec from schemas/manifest.schema.json. Do not edit: run the spec generator.
|
|
2
|
-
// Spec 0.
|
|
2
|
+
// Spec 0.6.0, digest 37141b85b9ab9f02af849a62a9c97ba729d6c5c2705130290bcdf45b308ea4cc
|
|
3
3
|
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** The built catalog this vocabulary was projected from. */
|
|
2
|
-
export declare const SPEC_CATALOG_HASH = "
|
|
2
|
+
export declare const SPEC_CATALOG_HASH = "4ac7ecedd1c59d1999a9f7eea2f523c7653fececb97258a478f09253f6b6057f";
|
|
3
3
|
/** Every closed component id, sorted. */
|
|
4
|
-
export declare const SPEC_COMPONENT_IDS: readonly ["action-form", "alert", "alert-dialog", "analytics-grid", "app-nav", "badge", "banner", "blocks-code", "blocks-data", "blocks-diagram", "blocks-embed", "blocks-interactive", "blocks-map", "blocks-media", "blocks-structure", "blocks-text", "breadcrumb", "button", "button-group", "callout", "card", "charts-area", "charts-bar", "charts-bubble", "charts-bullet", "charts-canvas-renderer", "charts-cartesian", "charts-combo", "charts-donut", "charts-funnel", "charts-gauge", "charts-geo-map", "charts-geo-point-map", "charts-heatmap", "charts-line", "charts-network", "charts-pie", "charts-progress-ring", "charts-sankey", "charts-scatter", "charts-sparkline", "charts-stacked-bar", "charts-sunburst", "charts-treemap", "chat-message", "chat-thread", "checkbox", "chip", "code", "combobox", "command-palette", "content-layout", "context-menu", "context-menu-trigger", "control-choice", "control-filter", "control-slider", "control-toggle", "data-board", "data-calendar", "data-files", "data-grid", "data-map", "data-timeline", "data-tree-view", "deck-slide", "description", "detail-panel", "dialog", "drawer", "dropdown-menu", "dropdown-menu-content", "dropdown-menu-item", "dropdown-menu-trigger", "empty-state", "error-state", "field", "field-error", "flow-action", "flow-view", "form", "form-field", "form-submit", "host-region", "hover-card", "hover-card-content", "icon-button", "inline-text", "input", "input-group", "kbd", "kpi", "label", "layout-auth-split", "layout-blog", "layout-card", "layout-chrome", "layout-dashboard-grid", "layout-deck", "layout-doc", "layout-docs", "layout-drawer", "layout-dual-sidebar", "layout-editorial", "layout-grid", "layout-host", "layout-landing", "layout-marketing", "layout-page", "layout-pricing", "layout-row", "layout-settings", "layout-sidebar", "layout-split", "layout-stack", "layout-tile", "layout-top-nav", "layout-wizard", "media-composition-canvas", "media-composition-svg", "media-image", "menubar", "menubar-trigger", "multi-select", "nav-icon", "navigation-menu", "pagination", "popover", "popover-content", "radio", "radio-group", "responsive-modal", "screen-outlet", "select", "select-content", "select-group", "select-item", "select-label", "select-portal", "select-separator", "select-trigger", "select-value", "select-viewport", "sheet", "sidebar", "sortable-list", "split-view", "stat", "stepper", "switch", "table", "tag", "text-counter", "textarea", "timeline", "toaster", "tooltip", "workflow-graph"];
|
|
4
|
+
export declare const SPEC_COMPONENT_IDS: readonly ["action-form", "alert", "alert-dialog", "analytics-grid", "app-nav", "badge", "banner", "blocks-code", "blocks-data", "blocks-diagram", "blocks-embed", "blocks-interactive", "blocks-map", "blocks-media", "blocks-structure", "blocks-text", "breadcrumb", "button", "button-group", "callout", "card", "charts-area", "charts-bar", "charts-bubble", "charts-bullet", "charts-canvas-renderer", "charts-cartesian", "charts-combo", "charts-donut", "charts-funnel", "charts-gauge", "charts-geo-map", "charts-geo-point-map", "charts-heatmap", "charts-line", "charts-network", "charts-pie", "charts-progress-ring", "charts-sankey", "charts-scatter", "charts-sparkline", "charts-stacked-bar", "charts-sunburst", "charts-treemap", "chat-message", "chat-thread", "checkbox", "chip", "code", "combobox", "command-palette", "content-layout", "context-menu", "context-menu-trigger", "control-choice", "control-filter", "control-slider", "control-toggle", "data-board", "data-calendar", "data-cohort-table", "data-files", "data-filter-builder", "data-grid", "data-map", "data-notification-inbox", "data-timeline", "data-tree-view", "deck-slide", "description", "detail-panel", "dialog", "drawer", "dropdown-menu", "dropdown-menu-content", "dropdown-menu-item", "dropdown-menu-trigger", "empty-state", "error-state", "field", "field-error", "flow-action", "flow-view", "form", "form-field", "form-submit", "host-region", "hover-card", "hover-card-content", "icon-button", "inline-text", "input", "input-group", "kbd", "kpi", "label", "layout-auth-split", "layout-blog", "layout-card", "layout-chrome", "layout-dashboard-grid", "layout-deck", "layout-doc", "layout-docs", "layout-drawer", "layout-dual-sidebar", "layout-editorial", "layout-grid", "layout-host", "layout-landing", "layout-marketing", "layout-page", "layout-pricing", "layout-row", "layout-settings", "layout-sidebar", "layout-split", "layout-stack", "layout-tile", "layout-top-nav", "layout-wizard", "media-composition-canvas", "media-composition-svg", "media-image", "menubar", "menubar-trigger", "multi-select", "nav-icon", "navigation-menu", "pagination", "popover", "popover-content", "radio", "radio-group", "responsive-modal", "screen-outlet", "select", "select-content", "select-group", "select-item", "select-label", "select-portal", "select-separator", "select-trigger", "select-value", "select-viewport", "sheet", "sidebar", "sortable-list", "split-view", "stat", "stepper", "switch", "table", "tag", "text-counter", "textarea", "time-field", "timeline", "toaster", "tooltip", "workflow-graph"];
|
|
5
5
|
export type SpecComponentId = (typeof SPEC_COMPONENT_IDS)[number];
|
|
6
6
|
/** The props a blueprint may set on each component (platform extensions left out). */
|
|
7
7
|
export interface SpecComponentProps {
|
|
@@ -481,12 +481,31 @@ export interface SpecComponentProps {
|
|
|
481
481
|
timeZone?: string;
|
|
482
482
|
view?: 'month' | 'week' | 'day' | 'agenda';
|
|
483
483
|
};
|
|
484
|
+
'data-cohort-table': {
|
|
485
|
+
average?: boolean;
|
|
486
|
+
caption: string;
|
|
487
|
+
captionHidden?: boolean;
|
|
488
|
+
density?: 'compact' | 'default' | 'comfortable';
|
|
489
|
+
heat?: boolean;
|
|
490
|
+
locale?: string;
|
|
491
|
+
max?: number;
|
|
492
|
+
periods?: readonly unknown[];
|
|
493
|
+
rows: readonly unknown[];
|
|
494
|
+
valueKind?: 'rate' | 'count';
|
|
495
|
+
};
|
|
484
496
|
'data-files': {
|
|
485
497
|
density?: 'comfortable' | 'compact';
|
|
486
498
|
entries: readonly unknown[];
|
|
487
499
|
label: string;
|
|
488
500
|
layout?: 'grid' | 'list';
|
|
489
501
|
};
|
|
502
|
+
'data-filter-builder': {
|
|
503
|
+
disabled?: boolean;
|
|
504
|
+
fields: readonly unknown[];
|
|
505
|
+
label: string;
|
|
506
|
+
maxDepth?: number;
|
|
507
|
+
value?: Readonly<Record<string, unknown>>;
|
|
508
|
+
};
|
|
490
509
|
'data-grid': {
|
|
491
510
|
caption: string;
|
|
492
511
|
columns: readonly unknown[];
|
|
@@ -500,6 +519,15 @@ export interface SpecComponentProps {
|
|
|
500
519
|
listPlacement?: 'side' | 'below';
|
|
501
520
|
markers: readonly unknown[];
|
|
502
521
|
};
|
|
522
|
+
'data-notification-inbox': {
|
|
523
|
+
filter?: 'all' | 'unread';
|
|
524
|
+
headingLevel?: number;
|
|
525
|
+
items: readonly unknown[];
|
|
526
|
+
locale?: string;
|
|
527
|
+
markReadOnOpen?: boolean;
|
|
528
|
+
now?: string;
|
|
529
|
+
timeZone?: string;
|
|
530
|
+
};
|
|
503
531
|
'data-timeline': {
|
|
504
532
|
dependencies?: readonly unknown[];
|
|
505
533
|
label: string;
|
|
@@ -1088,6 +1116,20 @@ export interface SpecComponentProps {
|
|
|
1088
1116
|
rows?: number;
|
|
1089
1117
|
value?: string;
|
|
1090
1118
|
};
|
|
1119
|
+
'time-field': {
|
|
1120
|
+
description?: string;
|
|
1121
|
+
disabled?: boolean;
|
|
1122
|
+
error?: string;
|
|
1123
|
+
hourCycle?: number;
|
|
1124
|
+
label: string;
|
|
1125
|
+
labels?: Readonly<Record<string, unknown>>;
|
|
1126
|
+
locale?: string;
|
|
1127
|
+
minuteStep?: number;
|
|
1128
|
+
name?: string;
|
|
1129
|
+
required?: boolean;
|
|
1130
|
+
size?: 'sm' | 'md';
|
|
1131
|
+
value?: string;
|
|
1132
|
+
};
|
|
1091
1133
|
timeline: {
|
|
1092
1134
|
hrefTrust?: 'developer' | 'untrusted';
|
|
1093
1135
|
items?: readonly unknown[];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Generated by @texuli/spec from catalog/components.json. Do not edit: run the spec generator.
|
|
2
|
-
// Spec 0.
|
|
2
|
+
// Spec 0.6.0, digest 37141b85b9ab9f02af849a62a9c97ba729d6c5c2705130290bcdf45b308ea4cc
|
|
3
3
|
/** The built catalog this vocabulary was projected from. */
|
|
4
|
-
export const SPEC_CATALOG_HASH = '
|
|
4
|
+
export const SPEC_CATALOG_HASH = '4ac7ecedd1c59d1999a9f7eea2f523c7653fececb97258a478f09253f6b6057f';
|
|
5
5
|
/** Every closed component id, sorted. */
|
|
6
6
|
export const SPEC_COMPONENT_IDS = [
|
|
7
7
|
'action-form',
|
|
@@ -64,9 +64,12 @@ export const SPEC_COMPONENT_IDS = [
|
|
|
64
64
|
'control-toggle',
|
|
65
65
|
'data-board',
|
|
66
66
|
'data-calendar',
|
|
67
|
+
'data-cohort-table',
|
|
67
68
|
'data-files',
|
|
69
|
+
'data-filter-builder',
|
|
68
70
|
'data-grid',
|
|
69
71
|
'data-map',
|
|
72
|
+
'data-notification-inbox',
|
|
70
73
|
'data-timeline',
|
|
71
74
|
'data-tree-view',
|
|
72
75
|
'deck-slide',
|
|
@@ -158,6 +161,7 @@ export const SPEC_COMPONENT_IDS = [
|
|
|
158
161
|
'tag',
|
|
159
162
|
'text-counter',
|
|
160
163
|
'textarea',
|
|
164
|
+
'time-field',
|
|
161
165
|
'timeline',
|
|
162
166
|
'toaster',
|
|
163
167
|
'tooltip',
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// Generated by @texuli/spec from schemas/workflow.schema.json. Do not edit: run the spec generator.
|
|
2
|
-
// Spec 0.
|
|
2
|
+
// Spec 0.6.0, digest 37141b85b9ab9f02af849a62a9c97ba729d6c5c2705130290bcdf45b308ea4cc
|
|
3
3
|
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { SpecMigration } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* 0.4.0 → 0.5.0 is additive (PLAN_009 catalog coverage): the catalog gains
|
|
4
|
+
* the data-cohort-table, data-notification-inbox and data-filter-builder
|
|
5
|
+
* ids and the app-tier time-field id. Every 0.4.0 envelope is a valid 0.5.0
|
|
6
|
+
* envelope, so the step only stamps `spec`.
|
|
7
|
+
*/
|
|
8
|
+
export declare const migration040to050: SpecMigration;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 0.4.0 → 0.5.0 is additive (PLAN_009 catalog coverage): the catalog gains
|
|
3
|
+
* the data-cohort-table, data-notification-inbox and data-filter-builder
|
|
4
|
+
* ids and the app-tier time-field id. Every 0.4.0 envelope is a valid 0.5.0
|
|
5
|
+
* envelope, so the step only stamps `spec`.
|
|
6
|
+
*/
|
|
7
|
+
export const migration040to050 = Object.freeze({
|
|
8
|
+
from: '0.4.0',
|
|
9
|
+
to: '0.5.0',
|
|
10
|
+
migrate: (envelope) => ({ ...envelope, spec: '0.5.0' }),
|
|
11
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { SpecMigration } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* 0.5.0 → 0.6.0 is additive (PLAN_010 T-motion-spec, ADR-012 and ADR-013):
|
|
4
|
+
* nodes gain an optional closed `motion` (enter and exit presets, `layout`,
|
|
5
|
+
* `stagger` and `duration` in token steps) and the envelope an optional
|
|
6
|
+
* `motion.level`. Every 0.5.0 envelope is a valid 0.6.0 envelope, so the
|
|
7
|
+
* step only stamps `spec`.
|
|
8
|
+
*/
|
|
9
|
+
export declare const migration050to060: SpecMigration;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 0.5.0 → 0.6.0 is additive (PLAN_010 T-motion-spec, ADR-012 and ADR-013):
|
|
3
|
+
* nodes gain an optional closed `motion` (enter and exit presets, `layout`,
|
|
4
|
+
* `stagger` and `duration` in token steps) and the envelope an optional
|
|
5
|
+
* `motion.level`. Every 0.5.0 envelope is a valid 0.6.0 envelope, so the
|
|
6
|
+
* step only stamps `spec`.
|
|
7
|
+
*/
|
|
8
|
+
export const migration050to060 = Object.freeze({
|
|
9
|
+
from: '0.5.0',
|
|
10
|
+
to: '0.6.0',
|
|
11
|
+
migrate: (envelope) => ({ ...envelope, spec: '0.6.0' }),
|
|
12
|
+
});
|
package/dist/migrations/index.js
CHANGED
|
@@ -2,12 +2,16 @@ import { isRecord } from "../dialect.js";
|
|
|
2
2
|
import { SPEC_VERSION } from "../version.js";
|
|
3
3
|
import { migration020to030 } from "./0.2.0-0.3.0.js";
|
|
4
4
|
import { migration030to040 } from "./0.3.0-0.4.0.js";
|
|
5
|
+
import { migration040to050 } from "./0.4.0-0.5.0.js";
|
|
6
|
+
import { migration050to060 } from "./0.5.0-0.6.0.js";
|
|
5
7
|
/** The version an envelope without `spec` was written for. */
|
|
6
8
|
export const UNDECLARED_SPEC_VERSION = '0.2.0';
|
|
7
9
|
/** Every step, in order; each `to` is the next step's `from`. */
|
|
8
10
|
export const SPEC_MIGRATIONS = Object.freeze([
|
|
9
11
|
migration020to030,
|
|
10
12
|
migration030to040,
|
|
13
|
+
migration040to050,
|
|
14
|
+
migration050to060,
|
|
11
15
|
]);
|
|
12
16
|
/**
|
|
13
17
|
* Bring a blueprint envelope up to `target` (the current spec by default)
|
package/dist/motion.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@texuli/spec/motion` — the closed motion vocabulary of spec 0.6.0
|
|
3
|
+
* (ADR-012, ADR-013) in code, mirrored from `schemas/blueprint.schema.json`
|
|
4
|
+
* (`tests/spec.test.ts` asserts they stay equal), and the one structural
|
|
5
|
+
* check every runtime shares: `@texuli/catalog` refuses with it, and
|
|
6
|
+
* `@texuli/player` paints only what it accepted.
|
|
7
|
+
*
|
|
8
|
+
* Agents name presets and token steps. Nothing here is CSS, keyframes, a
|
|
9
|
+
* duration in milliseconds or code. No imports at runtime.
|
|
10
|
+
*/
|
|
11
|
+
import type { BlueprintEnvelopeMotion, BlueprintMotionDuration, BlueprintMotionLevel, BlueprintMotionPreset, BlueprintMotionStagger, BlueprintNodeMotion } from './generated/typescript/blueprint.js';
|
|
12
|
+
export type { BlueprintEnvelopeMotion, BlueprintMotionDuration, BlueprintMotionLevel, BlueprintMotionPreset, BlueprintMotionStagger, BlueprintNodeMotion, };
|
|
13
|
+
/** Enter and exit presets (`$defs.motionPreset`). */
|
|
14
|
+
export declare const SPEC_MOTION_PRESETS: readonly BlueprintMotionPreset[];
|
|
15
|
+
/** Duration token steps (`$defs.motionDuration`); `base` when omitted. */
|
|
16
|
+
export declare const SPEC_MOTION_DURATIONS: readonly BlueprintMotionDuration[];
|
|
17
|
+
/** Stagger token steps between entering children (`$defs.motionStagger`). */
|
|
18
|
+
export declare const SPEC_MOTION_STAGGERS: readonly BlueprintMotionStagger[];
|
|
19
|
+
/** Motion ceilings (`$defs.motionLevel`), highest first. */
|
|
20
|
+
export declare const SPEC_MOTION_LEVELS: readonly BlueprintMotionLevel[];
|
|
21
|
+
/** The fields a node `motion` takes (`$defs.nodeMotion`). */
|
|
22
|
+
export declare const SPEC_NODE_MOTION_FIELDS: readonly string[];
|
|
23
|
+
export type SpecMotionCheck<T> = {
|
|
24
|
+
ok: true;
|
|
25
|
+
motion: Readonly<T>;
|
|
26
|
+
}
|
|
27
|
+
/** `path` is relative to the motion value (`""`, `.enter` …). */
|
|
28
|
+
| {
|
|
29
|
+
ok: false;
|
|
30
|
+
path: string;
|
|
31
|
+
message: string;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Check a node `motion` against the closed vocabulary. Returns a frozen
|
|
35
|
+
* copy with only the known fields, or the first refusal. Linear in the
|
|
36
|
+
* number of keys, and it stops at the first unknown one.
|
|
37
|
+
*/
|
|
38
|
+
export declare function checkNodeMotion(value: unknown): SpecMotionCheck<BlueprintNodeMotion>;
|
|
39
|
+
/** Check an envelope `motion` (`{ level }`). Returns a frozen copy, or the first refusal. */
|
|
40
|
+
export declare function checkEnvelopeMotion(value: unknown): SpecMotionCheck<BlueprintEnvelopeMotion>;
|
package/dist/motion.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@texuli/spec/motion` — the closed motion vocabulary of spec 0.6.0
|
|
3
|
+
* (ADR-012, ADR-013) in code, mirrored from `schemas/blueprint.schema.json`
|
|
4
|
+
* (`tests/spec.test.ts` asserts they stay equal), and the one structural
|
|
5
|
+
* check every runtime shares: `@texuli/catalog` refuses with it, and
|
|
6
|
+
* `@texuli/player` paints only what it accepted.
|
|
7
|
+
*
|
|
8
|
+
* Agents name presets and token steps. Nothing here is CSS, keyframes, a
|
|
9
|
+
* duration in milliseconds or code. No imports at runtime.
|
|
10
|
+
*/
|
|
11
|
+
/** Enter and exit presets (`$defs.motionPreset`). */
|
|
12
|
+
export const SPEC_MOTION_PRESETS = Object.freeze([
|
|
13
|
+
'fade',
|
|
14
|
+
'rise',
|
|
15
|
+
'scale',
|
|
16
|
+
'slide-start',
|
|
17
|
+
'slide-end',
|
|
18
|
+
]);
|
|
19
|
+
/** Duration token steps (`$defs.motionDuration`); `base` when omitted. */
|
|
20
|
+
export const SPEC_MOTION_DURATIONS = Object.freeze([
|
|
21
|
+
'fast',
|
|
22
|
+
'base',
|
|
23
|
+
'slow',
|
|
24
|
+
]);
|
|
25
|
+
/** Stagger token steps between entering children (`$defs.motionStagger`). */
|
|
26
|
+
export const SPEC_MOTION_STAGGERS = Object.freeze([
|
|
27
|
+
'none',
|
|
28
|
+
'fast',
|
|
29
|
+
'base',
|
|
30
|
+
]);
|
|
31
|
+
/** Motion ceilings (`$defs.motionLevel`), highest first. */
|
|
32
|
+
export const SPEC_MOTION_LEVELS = Object.freeze([
|
|
33
|
+
'full',
|
|
34
|
+
'subtle',
|
|
35
|
+
'none',
|
|
36
|
+
]);
|
|
37
|
+
/** The fields a node `motion` takes (`$defs.nodeMotion`). */
|
|
38
|
+
export const SPEC_NODE_MOTION_FIELDS = Object.freeze([
|
|
39
|
+
'enter',
|
|
40
|
+
'exit',
|
|
41
|
+
'layout',
|
|
42
|
+
'stagger',
|
|
43
|
+
'duration',
|
|
44
|
+
]);
|
|
45
|
+
const isRecord = (value) => value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
46
|
+
/** A short, single-line label for a refused value: never the value itself in full. */
|
|
47
|
+
function describe(value) {
|
|
48
|
+
if (typeof value === 'string')
|
|
49
|
+
return JSON.stringify(value.slice(0, 24));
|
|
50
|
+
if (Array.isArray(value))
|
|
51
|
+
return 'an array';
|
|
52
|
+
return value === null ? 'null' : typeof value;
|
|
53
|
+
}
|
|
54
|
+
function oneOf(value, allowed, field) {
|
|
55
|
+
if (typeof value === 'string' && allowed.includes(value)) {
|
|
56
|
+
return { ok: true, value: value };
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
ok: false,
|
|
60
|
+
path: `.${field}`,
|
|
61
|
+
message: `"${field}" must be one of ${allowed.join(', ')} (got ${describe(value)}).`,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Check a node `motion` against the closed vocabulary. Returns a frozen
|
|
66
|
+
* copy with only the known fields, or the first refusal. Linear in the
|
|
67
|
+
* number of keys, and it stops at the first unknown one.
|
|
68
|
+
*/
|
|
69
|
+
export function checkNodeMotion(value) {
|
|
70
|
+
if (!isRecord(value)) {
|
|
71
|
+
return { ok: false, path: '', message: `"motion" must be an object (got ${describe(value)}).` };
|
|
72
|
+
}
|
|
73
|
+
const out = {};
|
|
74
|
+
for (const key of Object.keys(value)) {
|
|
75
|
+
if (!SPEC_NODE_MOTION_FIELDS.includes(key)) {
|
|
76
|
+
return {
|
|
77
|
+
ok: false,
|
|
78
|
+
path: `.${key.slice(0, 32)}`,
|
|
79
|
+
message: `"motion" takes only ${SPEC_NODE_MOTION_FIELDS.join(', ')}; no CSS, keyframes or code.`,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const entry = value[key];
|
|
83
|
+
if (key === 'layout') {
|
|
84
|
+
if (typeof entry !== 'boolean') {
|
|
85
|
+
return {
|
|
86
|
+
ok: false,
|
|
87
|
+
path: '.layout',
|
|
88
|
+
message: `"layout" must be a boolean (got ${describe(entry)}).`,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
out.layout = entry;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (key === 'enter' || key === 'exit') {
|
|
95
|
+
const checked = oneOf(entry, SPEC_MOTION_PRESETS, key);
|
|
96
|
+
if (!checked.ok)
|
|
97
|
+
return checked;
|
|
98
|
+
out[key] = checked.value;
|
|
99
|
+
}
|
|
100
|
+
else if (key === 'stagger') {
|
|
101
|
+
const checked = oneOf(entry, SPEC_MOTION_STAGGERS, key);
|
|
102
|
+
if (!checked.ok)
|
|
103
|
+
return checked;
|
|
104
|
+
out.stagger = checked.value;
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
const checked = oneOf(entry, SPEC_MOTION_DURATIONS, key);
|
|
108
|
+
if (!checked.ok)
|
|
109
|
+
return checked;
|
|
110
|
+
out.duration = checked.value;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return { ok: true, motion: Object.freeze(out) };
|
|
114
|
+
}
|
|
115
|
+
/** Check an envelope `motion` (`{ level }`). Returns a frozen copy, or the first refusal. */
|
|
116
|
+
export function checkEnvelopeMotion(value) {
|
|
117
|
+
if (!isRecord(value)) {
|
|
118
|
+
return { ok: false, path: '', message: `"motion" must be an object (got ${describe(value)}).` };
|
|
119
|
+
}
|
|
120
|
+
for (const key of Object.keys(value)) {
|
|
121
|
+
if (key !== 'level') {
|
|
122
|
+
return {
|
|
123
|
+
ok: false,
|
|
124
|
+
path: `.${key.slice(0, 32)}`,
|
|
125
|
+
message: 'The envelope "motion" takes only "level".',
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const level = oneOf(value.level, SPEC_MOTION_LEVELS, 'level');
|
|
130
|
+
if (!level.ok)
|
|
131
|
+
return level;
|
|
132
|
+
return { ok: true, motion: Object.freeze({ level: level.value }) };
|
|
133
|
+
}
|