@tilewise/workbench-client 0.0.0-stage → 0.1.1
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/CHANGELOG.md +25 -0
- package/LICENSE +21 -0
- package/README.md +210 -2
- package/dist/blocks/ScreenScope.d.ts +11 -0
- package/dist/blocks/ScreenScope.js +11 -0
- package/dist/blocks/drawnBlocks.d.ts +11 -0
- package/dist/blocks/drawnBlocks.js +47 -0
- package/dist/blocks/screenContext.d.ts +2 -0
- package/dist/blocks/screenContext.js +3 -0
- package/dist/bridge/Bridge.d.ts +10 -0
- package/dist/bridge/Bridge.js +129 -0
- package/dist/bridge/device.d.ts +6 -0
- package/dist/bridge/device.js +28 -0
- package/dist/bridge/post.d.ts +5 -0
- package/dist/bridge/post.js +8 -0
- package/dist/bridge/readViewerMessage.d.ts +3 -0
- package/dist/bridge/readViewerMessage.js +46 -0
- package/dist/bridge/revealControl.d.ts +10 -0
- package/dist/bridge/revealControl.js +62 -0
- package/dist/bridge/snapshot.d.ts +7 -0
- package/dist/bridge/snapshot.js +47 -0
- package/dist/bridge/toneAtTop.d.ts +3 -0
- package/dist/bridge/toneAtTop.js +23 -0
- package/dist/bridge/watchScreen.d.ts +10 -0
- package/dist/bridge/watchScreen.js +50 -0
- package/dist/bridge/wholeHeight.d.ts +8 -0
- package/dist/bridge/wholeHeight.js +16 -0
- package/dist/controls/paint.d.ts +8 -0
- package/dist/controls/paint.js +16 -0
- package/dist/controls/parseValue.d.ts +7 -0
- package/dist/controls/parseValue.js +34 -0
- package/dist/controls/resetControl.d.ts +3 -0
- package/dist/controls/resetControl.js +6 -0
- package/dist/controls/setControl.d.ts +3 -0
- package/dist/controls/setControl.js +6 -0
- package/dist/controls/store.d.ts +12 -0
- package/dist/controls/store.js +125 -0
- package/dist/controls/types.d.ts +111 -0
- package/dist/controls/types.js +6 -0
- package/dist/controls/useControl.d.ts +7 -0
- package/dist/controls/useControl.js +16 -0
- package/dist/define/buildManifest.d.ts +8 -0
- package/dist/define/buildManifest.js +51 -0
- package/dist/define/checkDefaults.d.ts +3 -0
- package/dist/define/checkDefaults.js +29 -0
- package/dist/define/defineApp.d.ts +24 -0
- package/dist/define/defineApp.js +92 -0
- package/dist/define/defineBlock.d.ts +12 -0
- package/dist/define/defineBlock.js +10 -0
- package/dist/define/defineScreen.d.ts +11 -0
- package/dist/define/defineScreen.js +10 -0
- package/dist/define/part.d.ts +23 -0
- package/dist/define/part.js +22 -0
- package/dist/define/registeredApp.d.ts +12 -0
- package/dist/define/registeredApp.js +5 -0
- package/dist/draw/boolean.d.ts +6 -0
- package/dist/draw/boolean.js +5 -0
- package/dist/draw/choose.d.ts +4 -0
- package/dist/draw/choose.js +4 -0
- package/dist/draw/color.d.ts +2 -0
- package/dist/draw/color.js +4 -0
- package/dist/draw/number.d.ts +5 -0
- package/dist/draw/number.js +5 -0
- package/dist/draw/text.d.ts +5 -0
- package/dist/draw/text.js +5 -0
- package/dist/draw/variant.d.ts +17 -0
- package/dist/draw/variant.js +4 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +14 -0
- package/dist/protocol/protocol.d.ts +8 -0
- package/dist/protocol/protocol.js +8 -0
- package/dist/protocol/types.d.ts +144 -0
- package/dist/protocol/types.js +1 -0
- package/dist/vite/apiFetch.d.ts +7 -0
- package/dist/vite/apiFetch.js +15 -0
- package/dist/vite/apiWorkers.d.ts +11 -0
- package/dist/vite/apiWorkers.js +111 -0
- package/dist/vite/appFolder.d.ts +6 -0
- package/dist/vite/appFolder.js +11 -0
- package/dist/vite/builds.d.ts +47 -0
- package/dist/vite/builds.js +250 -0
- package/dist/vite/bundleApi.d.ts +9 -0
- package/dist/vite/bundleApi.js +32 -0
- package/dist/vite/checkout.d.ts +11 -0
- package/dist/vite/checkout.js +43 -0
- package/dist/vite/environment.d.ts +9 -0
- package/dist/vite/environment.js +10 -0
- package/dist/vite/fetchBridge.d.ts +8 -0
- package/dist/vite/fetchBridge.js +42 -0
- package/dist/vite/git.d.ts +7 -0
- package/dist/vite/git.js +18 -0
- package/dist/vite/index.d.ts +1 -0
- package/dist/vite/index.js +1 -0
- package/dist/vite/isWorkspace.d.ts +5 -0
- package/dist/vite/isWorkspace.js +10 -0
- package/dist/vite/serveBuild.d.ts +7 -0
- package/dist/vite/serveBuild.js +45 -0
- package/dist/vite/versions.d.ts +44 -0
- package/dist/vite/versions.js +122 -0
- package/dist/vite/workbenchLocal.d.ts +32 -0
- package/dist/vite/workbenchLocal.js +251 -0
- package/docs/protocol.md +66 -0
- package/package.json +63 -3
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { PART } from './part.js';
|
|
2
|
+
/**
|
|
3
|
+
* Everything the app has, for the viewer: its screens and states, every
|
|
4
|
+
* control with where it sits, and every block. A state goes without its jump,
|
|
5
|
+
* so only the fields the protocol names are copied.
|
|
6
|
+
*/
|
|
7
|
+
export function buildManifest(app, screens, parts) {
|
|
8
|
+
const controls = parts.flatMap((part) => {
|
|
9
|
+
const { place, controls: declared } = part[PART];
|
|
10
|
+
return declared.map((control) => ({ ...control, ...place }));
|
|
11
|
+
});
|
|
12
|
+
const blocks = parts.flatMap((part) => {
|
|
13
|
+
const { place, label, controls: declared } = part[PART];
|
|
14
|
+
return place.level === 'block'
|
|
15
|
+
? [
|
|
16
|
+
{
|
|
17
|
+
id: place.block,
|
|
18
|
+
label: label ?? place.block,
|
|
19
|
+
controls: declared.map((control) => control.id),
|
|
20
|
+
},
|
|
21
|
+
]
|
|
22
|
+
: [];
|
|
23
|
+
});
|
|
24
|
+
return { app, screens: screens.map(screenOf), controls, blocks };
|
|
25
|
+
}
|
|
26
|
+
function screenOf(screen) {
|
|
27
|
+
const { id, label, short, parent, tab, group, page, where, statesBy, files } = screen;
|
|
28
|
+
return {
|
|
29
|
+
id,
|
|
30
|
+
label,
|
|
31
|
+
short,
|
|
32
|
+
...(parent !== undefined && { parent }),
|
|
33
|
+
...(tab !== undefined && { tab }),
|
|
34
|
+
...(group !== undefined && { group }),
|
|
35
|
+
...(page !== undefined && { page }),
|
|
36
|
+
...(where !== undefined && { where }),
|
|
37
|
+
...(statesBy !== undefined && { statesBy }),
|
|
38
|
+
...(files !== undefined && { files: [...files] }),
|
|
39
|
+
states: screen.states.map(stateOf),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function stateOf(state) {
|
|
43
|
+
const { id, label, kind, note, when } = state;
|
|
44
|
+
return {
|
|
45
|
+
id,
|
|
46
|
+
label,
|
|
47
|
+
...(kind !== undefined && { kind }),
|
|
48
|
+
...(note !== undefined && { note }),
|
|
49
|
+
...(when !== undefined && { when: [...when] }),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** Throws on a `default` that isn't one of the options, or a number's outside `min` and `max`. */
|
|
2
|
+
export function checkDefaults(controls, where) {
|
|
3
|
+
for (const control of controls) {
|
|
4
|
+
const fault = faultOf(control);
|
|
5
|
+
if (fault) {
|
|
6
|
+
throw new Error(`workbench-client: in ${where}, the default of "${control.id}" ${fault}.`);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function faultOf(control) {
|
|
11
|
+
switch (control.type) {
|
|
12
|
+
case 'variant':
|
|
13
|
+
return control.options.some((option) => option.value === control.default)
|
|
14
|
+
? null
|
|
15
|
+
: `("${control.default}") isn't one of its options`;
|
|
16
|
+
case 'color':
|
|
17
|
+
return control.options.some((option) => option.token === control.default)
|
|
18
|
+
? null
|
|
19
|
+
: `("${control.default}") isn't one of its tokens`;
|
|
20
|
+
case 'number':
|
|
21
|
+
return control.default >= control.min && control.default <= control.max
|
|
22
|
+
? null
|
|
23
|
+
: `(${control.default}) is outside ${control.min} to ${control.max}`;
|
|
24
|
+
case 'boolean':
|
|
25
|
+
return typeof control.default === 'boolean' ? null : "isn't true or false";
|
|
26
|
+
case 'text':
|
|
27
|
+
return typeof control.default === 'string' ? null : "isn't text";
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Control, Declared } from '../controls/types.js';
|
|
2
|
+
import type { Navigation, Screen, State } from '../protocol/types.js';
|
|
3
|
+
import { type Part } from './part.js';
|
|
4
|
+
/**
|
|
5
|
+
* Declares the app: its name, its screens and how to move between them,
|
|
6
|
+
* every other part, and the global controls, which show on every page. An
|
|
7
|
+
* app has exactly one, beside its root component.
|
|
8
|
+
*
|
|
9
|
+
* `parts` is every module that holds a part, as `import.meta.glob` gives
|
|
10
|
+
* them, so each loads as the app starts and the manifest and the first
|
|
11
|
+
* `values` hold every control. As it starts, the app throws on two controls
|
|
12
|
+
* with one id, two blocks with one name, a screen id that isn't in `screens`,
|
|
13
|
+
* a bad default, or a second `defineApp`.
|
|
14
|
+
*/
|
|
15
|
+
export declare function defineApp<S extends State, const C extends readonly Control[]>(declaration: {
|
|
16
|
+
/** The app's name in the manifest, such as `aitems`. */
|
|
17
|
+
app: string;
|
|
18
|
+
/** Every screen and its states, each state with the jump that gets there. */
|
|
19
|
+
screens: readonly Screen<S>[];
|
|
20
|
+
/** A hook: how to go to a state, and where the app is now. */
|
|
21
|
+
useNavigation: () => Navigation<S>;
|
|
22
|
+
parts: Readonly<Record<string, unknown>>;
|
|
23
|
+
controls: C & NoInfer<Declared<C>>;
|
|
24
|
+
}): Part<C>;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { declare } from '../controls/store.js';
|
|
2
|
+
import { buildManifest } from './buildManifest.js';
|
|
3
|
+
import { checkDefaults } from './checkDefaults.js';
|
|
4
|
+
import { isPart, makePart, nameOf, PART } from './part.js';
|
|
5
|
+
import { registerApp, registeredApp } from './registeredApp.js';
|
|
6
|
+
/**
|
|
7
|
+
* Declares the app: its name, its screens and how to move between them,
|
|
8
|
+
* every other part, and the global controls, which show on every page. An
|
|
9
|
+
* app has exactly one, beside its root component.
|
|
10
|
+
*
|
|
11
|
+
* `parts` is every module that holds a part, as `import.meta.glob` gives
|
|
12
|
+
* them, so each loads as the app starts and the manifest and the first
|
|
13
|
+
* `values` hold every control. As it starts, the app throws on two controls
|
|
14
|
+
* with one id, two blocks with one name, a screen id that isn't in `screens`,
|
|
15
|
+
* a bad default, or a second `defineApp`.
|
|
16
|
+
*/
|
|
17
|
+
export function defineApp(declaration) {
|
|
18
|
+
if (registeredApp()) {
|
|
19
|
+
throw new Error('workbench-client: defineApp was called a second time; an app has exactly one.');
|
|
20
|
+
}
|
|
21
|
+
checkDefaults(declaration.controls, 'the app');
|
|
22
|
+
const global = makePart({ level: 'global' }, declaration.controls);
|
|
23
|
+
const parts = [global, ...partsIn(declaration.parts)];
|
|
24
|
+
checkParts(parts, new Set(declaration.screens.map((screen) => screen.id)));
|
|
25
|
+
for (const part of parts) {
|
|
26
|
+
for (const handle of part[PART].handles) {
|
|
27
|
+
declare(handle);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const states = new Map();
|
|
31
|
+
for (const screen of declaration.screens) {
|
|
32
|
+
for (const state of screen.states) {
|
|
33
|
+
states.set(state.id, state);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
registerApp({
|
|
37
|
+
manifest: buildManifest(declaration.app, declaration.screens, parts),
|
|
38
|
+
useNavigation: () => {
|
|
39
|
+
const navigation = declaration.useNavigation();
|
|
40
|
+
return {
|
|
41
|
+
at: navigation.at,
|
|
42
|
+
go: (id) => {
|
|
43
|
+
const state = states.get(id);
|
|
44
|
+
if (state) {
|
|
45
|
+
navigation.go(state);
|
|
46
|
+
}
|
|
47
|
+
return state !== undefined;
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
return global;
|
|
53
|
+
}
|
|
54
|
+
/** Every part among the modules' exports, each once. */
|
|
55
|
+
function partsIn(modules) {
|
|
56
|
+
const found = new Set();
|
|
57
|
+
for (const module of Object.values(modules)) {
|
|
58
|
+
if (typeof module !== 'object' || module === null) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
for (const value of Object.values(module)) {
|
|
62
|
+
if (isPart(value)) {
|
|
63
|
+
found.add(value);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return [...found];
|
|
68
|
+
}
|
|
69
|
+
function checkParts(parts, screens) {
|
|
70
|
+
const ids = new Map();
|
|
71
|
+
const blocks = new Set();
|
|
72
|
+
for (const part of parts) {
|
|
73
|
+
const info = part[PART];
|
|
74
|
+
const where = nameOf(info);
|
|
75
|
+
if (info.place.level === 'screen' && !screens.has(info.place.screen)) {
|
|
76
|
+
throw new Error(`workbench-client: ${where} isn't one of the app's screens.`);
|
|
77
|
+
}
|
|
78
|
+
if (info.place.level === 'block') {
|
|
79
|
+
if (blocks.has(info.place.block)) {
|
|
80
|
+
throw new Error(`workbench-client: two blocks are named "${info.place.block}".`);
|
|
81
|
+
}
|
|
82
|
+
blocks.add(info.place.block);
|
|
83
|
+
}
|
|
84
|
+
for (const control of info.controls) {
|
|
85
|
+
const first = ids.get(control.id);
|
|
86
|
+
if (first !== undefined) {
|
|
87
|
+
throw new Error(`workbench-client: two controls have the id "${control.id}", in ${first} and in ${where}.`);
|
|
88
|
+
}
|
|
89
|
+
ids.set(control.id, where);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Control, Declared } from '../controls/types.js';
|
|
2
|
+
import { type Part } from './part.js';
|
|
3
|
+
/**
|
|
4
|
+
* Declares a block's controls, beside its component. They show in a section
|
|
5
|
+
* of their own, headed by `label`, on any screen while the block is drawn there.
|
|
6
|
+
*/
|
|
7
|
+
export declare function defineBlock<const C extends readonly Control[]>(declaration: {
|
|
8
|
+
/** The block's component name. */
|
|
9
|
+
block: string;
|
|
10
|
+
label: string;
|
|
11
|
+
controls: C & NoInfer<Declared<C>>;
|
|
12
|
+
}): Part<C>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { checkDefaults } from './checkDefaults.js';
|
|
2
|
+
import { makePart } from './part.js';
|
|
3
|
+
/**
|
|
4
|
+
* Declares a block's controls, beside its component. They show in a section
|
|
5
|
+
* of their own, headed by `label`, on any screen while the block is drawn there.
|
|
6
|
+
*/
|
|
7
|
+
export function defineBlock(declaration) {
|
|
8
|
+
checkDefaults(declaration.controls, `block "${declaration.block}"`);
|
|
9
|
+
return makePart({ level: 'block', block: declaration.block }, declaration.controls, declaration.label);
|
|
10
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Control, Declared } from '../controls/types.js';
|
|
2
|
+
import { type Part } from './part.js';
|
|
3
|
+
/**
|
|
4
|
+
* Declares a screen's controls, beside its component. They show in the form
|
|
5
|
+
* on that screen, in the order given.
|
|
6
|
+
*/
|
|
7
|
+
export declare function defineScreen<const C extends readonly Control[]>(declaration: {
|
|
8
|
+
/** A screen id from the app's screens. */
|
|
9
|
+
screen: string;
|
|
10
|
+
controls: C & NoInfer<Declared<C>>;
|
|
11
|
+
}): Part<C>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { checkDefaults } from './checkDefaults.js';
|
|
2
|
+
import { makePart } from './part.js';
|
|
3
|
+
/**
|
|
4
|
+
* Declares a screen's controls, beside its component. They show in the form
|
|
5
|
+
* on that screen, in the order given.
|
|
6
|
+
*/
|
|
7
|
+
export function defineScreen(declaration) {
|
|
8
|
+
checkDefaults(declaration.controls, `screen "${declaration.screen}"`);
|
|
9
|
+
return makePart({ level: 'screen', screen: declaration.screen }, declaration.controls);
|
|
10
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Control, Handle, Place } from '../controls/types.js';
|
|
2
|
+
/** Marks a part, so `defineApp` finds it among a module's exports. */
|
|
3
|
+
export declare const PART: unique symbol;
|
|
4
|
+
export interface PartInfo {
|
|
5
|
+
place: Place;
|
|
6
|
+
/** A block's heading in the form. */
|
|
7
|
+
label?: string;
|
|
8
|
+
controls: readonly Control[];
|
|
9
|
+
handles: readonly Handle[];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* One `.workbench.ts` file's controls: the app's, a screen's or a block's.
|
|
13
|
+
* It holds one handle per control, under its id: `home.homepage`.
|
|
14
|
+
*/
|
|
15
|
+
export type Part<C extends readonly Control[] = readonly Control[]> = {
|
|
16
|
+
readonly [K in C[number] as K['id']]: Handle<K>;
|
|
17
|
+
} & {
|
|
18
|
+
readonly [PART]: PartInfo;
|
|
19
|
+
};
|
|
20
|
+
export declare function makePart<C extends readonly Control[]>(place: Place, controls: C, label?: string): Part<C>;
|
|
21
|
+
export declare function isPart(value: unknown): value is Part;
|
|
22
|
+
/** Where a part sits, in words, for the messages the start-up checks throw. */
|
|
23
|
+
export declare function nameOf(info: PartInfo): string;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Marks a part, so `defineApp` finds it among a module's exports. */
|
|
2
|
+
export const PART = Symbol.for('@tilewise/workbench-client/part');
|
|
3
|
+
export function makePart(place, controls, label) {
|
|
4
|
+
const handles = controls.map((control) => ({ id: control.id, control, place }));
|
|
5
|
+
const info = { place, controls, handles, ...(label !== undefined && { label }) };
|
|
6
|
+
const byId = Object.fromEntries(handles.map((handle) => [handle.id, handle]));
|
|
7
|
+
return Object.assign(byId, { [PART]: info });
|
|
8
|
+
}
|
|
9
|
+
export function isPart(value) {
|
|
10
|
+
return typeof value === 'object' && value !== null && PART in value;
|
|
11
|
+
}
|
|
12
|
+
/** Where a part sits, in words, for the messages the start-up checks throw. */
|
|
13
|
+
export function nameOf(info) {
|
|
14
|
+
switch (info.place.level) {
|
|
15
|
+
case 'global':
|
|
16
|
+
return 'the app';
|
|
17
|
+
case 'screen':
|
|
18
|
+
return `screen "${info.place.screen}"`;
|
|
19
|
+
case 'block':
|
|
20
|
+
return `block "${info.place.block}"`;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { At, Manifest } from '../protocol/types.js';
|
|
2
|
+
/** The app `defineApp` declared, as the bridge needs it. */
|
|
3
|
+
export interface RegisteredApp {
|
|
4
|
+
manifest: Manifest;
|
|
5
|
+
/** The app's navigation, going by state id: false for a state it doesn't have. */
|
|
6
|
+
useNavigation: () => {
|
|
7
|
+
at: At;
|
|
8
|
+
go: (state: string) => boolean;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export declare function registerApp(app: RegisteredApp): void;
|
|
12
|
+
export declare const registeredApp: () => RegisteredApp | null;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type Case } from './choose.js';
|
|
2
|
+
/** What to draw for a line of text: any exact lines, and `other`, required, for the rest. */
|
|
3
|
+
export declare function text<R>(value: string, cases: Readonly<Record<string, Case<string, R>>> & {
|
|
4
|
+
other: Case<string, R>;
|
|
5
|
+
}): R;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { choose } from './choose.js';
|
|
2
|
+
/** What to draw for a line of text: any exact lines, and `other`, required, for the rest. */
|
|
3
|
+
export function text(value, cases) {
|
|
4
|
+
return choose(value !== 'other' && Object.hasOwn(cases, value) ? cases[value] : cases.other, value);
|
|
5
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type Case } from './choose.js';
|
|
2
|
+
type EveryCase<V extends string, R> = {
|
|
3
|
+
[K in V]: Case<K, R>;
|
|
4
|
+
};
|
|
5
|
+
/** Some options, and `other` for the rest: its function gets them without the ones listed. */
|
|
6
|
+
type SomeCases<V extends string, L extends string, R> = {
|
|
7
|
+
[K in L]: K extends 'other' ? Case<Exclude<V, L>, R> : Case<K, R>;
|
|
8
|
+
} & {
|
|
9
|
+
other: unknown;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* What to draw for a variant's value. A call without `other` lists every
|
|
13
|
+
* option, so a new option is a type error until every such call handles it.
|
|
14
|
+
*/
|
|
15
|
+
export declare function variant<V extends string, R>(value: V, cases: EveryCase<V, R>): R;
|
|
16
|
+
export declare function variant<V extends string, L extends V | 'other', R>(value: V, cases: SomeCases<V, L, R>): R;
|
|
17
|
+
export {};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export { ScreenScope } from './blocks/ScreenScope.js';
|
|
2
|
+
export { Bridge } from './bridge/Bridge.js';
|
|
3
|
+
export { resetControl } from './controls/resetControl.js';
|
|
4
|
+
export { setControl } from './controls/setControl.js';
|
|
5
|
+
export type { BooleanControl, ColorControl, ColorOption, Control, Handle, Level, NumberControl, Option, Place, TextControl, Value, ValueOf, VariantControl, } from './controls/types.js';
|
|
6
|
+
export { useControl } from './controls/useControl.js';
|
|
7
|
+
export { defineApp } from './define/defineApp.js';
|
|
8
|
+
export { defineBlock } from './define/defineBlock.js';
|
|
9
|
+
export { defineScreen } from './define/defineScreen.js';
|
|
10
|
+
export type { Part } from './define/part.js';
|
|
11
|
+
export { boolean } from './draw/boolean.js';
|
|
12
|
+
export type { Case } from './draw/choose.js';
|
|
13
|
+
export { color } from './draw/color.js';
|
|
14
|
+
export { number } from './draw/number.js';
|
|
15
|
+
export { text } from './draw/text.js';
|
|
16
|
+
export { variant } from './draw/variant.js';
|
|
17
|
+
export { PROTOCOL } from './protocol/protocol.js';
|
|
18
|
+
export type { AppMessage, AppSays, At, DeviceMessage, Manifest, ManifestBlock, ManifestControl, Navigation, Screen, State, StateKind, Tone, ViewerMessage, ViewerSays, } from './protocol/types.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export { ScreenScope } from './blocks/ScreenScope.js';
|
|
2
|
+
export { Bridge } from './bridge/Bridge.js';
|
|
3
|
+
export { resetControl } from './controls/resetControl.js';
|
|
4
|
+
export { setControl } from './controls/setControl.js';
|
|
5
|
+
export { useControl } from './controls/useControl.js';
|
|
6
|
+
export { defineApp } from './define/defineApp.js';
|
|
7
|
+
export { defineBlock } from './define/defineBlock.js';
|
|
8
|
+
export { defineScreen } from './define/defineScreen.js';
|
|
9
|
+
export { boolean } from './draw/boolean.js';
|
|
10
|
+
export { color } from './draw/color.js';
|
|
11
|
+
export { number } from './draw/number.js';
|
|
12
|
+
export { text } from './draw/text.js';
|
|
13
|
+
export { variant } from './draw/variant.js';
|
|
14
|
+
export { PROTOCOL } from './protocol/protocol.js';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** The protocol this package speaks. */
|
|
2
|
+
export declare const PROTOCOL = 4;
|
|
3
|
+
/**
|
|
4
|
+
* Every message carries `source`, for every app, as builds from before the
|
|
5
|
+
* package send them. Each side ignores any message without the other's tag.
|
|
6
|
+
*/
|
|
7
|
+
export declare const FROM_APP = "aitems";
|
|
8
|
+
export declare const FROM_VIEWER = "aitems-workbench";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** The protocol this package speaks. */
|
|
2
|
+
export const PROTOCOL = 4;
|
|
3
|
+
/**
|
|
4
|
+
* Every message carries `source`, for every app, as builds from before the
|
|
5
|
+
* package send them. Each side ignores any message without the other's tag.
|
|
6
|
+
*/
|
|
7
|
+
export const FROM_APP = 'aitems';
|
|
8
|
+
export const FROM_VIEWER = 'aitems-workbench';
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import type { Control, Value } from '../controls/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Protocol 4: what the app and the viewer say to each other through
|
|
4
|
+
* `postMessage`, between the frame and the page around it. Any change to a
|
|
5
|
+
* message or to the manifest bumps the protocol, so the viewer can still read
|
|
6
|
+
* older builds.
|
|
7
|
+
*/
|
|
8
|
+
export type StateKind = 'state' | 'sheet' | 'overlay';
|
|
9
|
+
/** One place on a screen. The app knows how to get there; the viewer only names it. */
|
|
10
|
+
export interface State {
|
|
11
|
+
/** Unique across the app, and never renamed. */
|
|
12
|
+
id: string;
|
|
13
|
+
label: string;
|
|
14
|
+
kind?: StateKind;
|
|
15
|
+
note?: string;
|
|
16
|
+
/** Only while the screen's `statesBy` control has one of these values. */
|
|
17
|
+
when?: readonly string[];
|
|
18
|
+
}
|
|
19
|
+
export interface Screen<S extends State = State> {
|
|
20
|
+
id: string;
|
|
21
|
+
label: string;
|
|
22
|
+
/** Two letters, for narrow lists. */
|
|
23
|
+
short: string;
|
|
24
|
+
/** The screen it sits under in the route tree. */
|
|
25
|
+
parent?: string;
|
|
26
|
+
/** The tab-bar tab it is the root of. */
|
|
27
|
+
tab?: string;
|
|
28
|
+
/** A heading that holds screens, with no states of its own. */
|
|
29
|
+
group?: boolean;
|
|
30
|
+
/** A page pushed from several screens. */
|
|
31
|
+
page?: boolean;
|
|
32
|
+
/** Where it opens from, in words. */
|
|
33
|
+
where?: string;
|
|
34
|
+
/** A control id: which states it has depends on that value. */
|
|
35
|
+
statesBy?: string;
|
|
36
|
+
/** The source files that draw it; a folder ends in `/`. */
|
|
37
|
+
files?: readonly string[];
|
|
38
|
+
states: readonly S[];
|
|
39
|
+
}
|
|
40
|
+
/** A control as declared, with where it sits. */
|
|
41
|
+
export type ManifestControl = Control & ({
|
|
42
|
+
level: 'global';
|
|
43
|
+
} | {
|
|
44
|
+
level: 'screen';
|
|
45
|
+
screen: string;
|
|
46
|
+
} | {
|
|
47
|
+
level: 'block';
|
|
48
|
+
block: string;
|
|
49
|
+
});
|
|
50
|
+
export interface ManifestBlock {
|
|
51
|
+
/** The component's name. */
|
|
52
|
+
id: string;
|
|
53
|
+
/** Its section's heading in the form. */
|
|
54
|
+
label: string;
|
|
55
|
+
/** Its controls' ids, in order. */
|
|
56
|
+
controls: string[];
|
|
57
|
+
}
|
|
58
|
+
/** Everything the app has, sent once with `hello`. A state goes without its jump. */
|
|
59
|
+
export interface Manifest {
|
|
60
|
+
/** Whose build this is, such as `aitems`. */
|
|
61
|
+
app: string;
|
|
62
|
+
screens: Screen[];
|
|
63
|
+
controls: ManifestControl[];
|
|
64
|
+
blocks: ManifestBlock[];
|
|
65
|
+
}
|
|
66
|
+
export type Tone = 'light' | 'dark';
|
|
67
|
+
/** What the app says. */
|
|
68
|
+
export type AppSays = {
|
|
69
|
+
type: 'hello';
|
|
70
|
+
protocol: 4;
|
|
71
|
+
manifest: Manifest;
|
|
72
|
+
} | {
|
|
73
|
+
type: 'at';
|
|
74
|
+
screen: string;
|
|
75
|
+
state: string | null;
|
|
76
|
+
} | {
|
|
77
|
+
type: 'blocks';
|
|
78
|
+
screen: string;
|
|
79
|
+
blocks: string[];
|
|
80
|
+
} | {
|
|
81
|
+
type: 'values';
|
|
82
|
+
values: Record<string, Value>;
|
|
83
|
+
} | {
|
|
84
|
+
type: 'tone';
|
|
85
|
+
top: Tone;
|
|
86
|
+
} | {
|
|
87
|
+
type: 'height';
|
|
88
|
+
height: number;
|
|
89
|
+
}
|
|
90
|
+
/** The screen as it was when asked, at up to twice its size; null when it couldn't be taken. */
|
|
91
|
+
| {
|
|
92
|
+
type: 'snapshot';
|
|
93
|
+
id: number;
|
|
94
|
+
image: ImageBitmap | null;
|
|
95
|
+
};
|
|
96
|
+
/** What the app says, as sent: tagged `source: 'aitems'`. */
|
|
97
|
+
export type AppMessage = {
|
|
98
|
+
source: 'aitems';
|
|
99
|
+
} & AppSays;
|
|
100
|
+
export interface DeviceMessage {
|
|
101
|
+
type: 'device';
|
|
102
|
+
/** What the status bar and the home indicator take, in px. */
|
|
103
|
+
insets: {
|
|
104
|
+
top: number;
|
|
105
|
+
bottom: number;
|
|
106
|
+
};
|
|
107
|
+
platform: 'ios' | 'android' | null;
|
|
108
|
+
/** Full page: no device, and the frame as tall as the open screen. */
|
|
109
|
+
whole: boolean;
|
|
110
|
+
}
|
|
111
|
+
/** What the viewer says. */
|
|
112
|
+
export type ViewerSays = {
|
|
113
|
+
type: 'hello';
|
|
114
|
+
} | DeviceMessage | {
|
|
115
|
+
type: 'go';
|
|
116
|
+
state: string;
|
|
117
|
+
} | {
|
|
118
|
+
type: 'set';
|
|
119
|
+
id: string;
|
|
120
|
+
value: Value;
|
|
121
|
+
} | {
|
|
122
|
+
type: 'reset';
|
|
123
|
+
id?: string;
|
|
124
|
+
}
|
|
125
|
+
/** A picture of the screen as it is now, answered with the same `id`. */
|
|
126
|
+
| {
|
|
127
|
+
type: 'snapshot';
|
|
128
|
+
id: number;
|
|
129
|
+
};
|
|
130
|
+
/** What the viewer says, as sent: tagged `source: 'aitems-workbench'`. */
|
|
131
|
+
export type ViewerMessage = {
|
|
132
|
+
source: 'aitems-workbench';
|
|
133
|
+
} & ViewerSays;
|
|
134
|
+
/** Where the app is now. */
|
|
135
|
+
export interface At {
|
|
136
|
+
screen: string;
|
|
137
|
+
state: string | null;
|
|
138
|
+
}
|
|
139
|
+
/** How the package moves the app, and learns where it is. */
|
|
140
|
+
export interface Navigation<S extends State = State> {
|
|
141
|
+
/** Make the jump the state describes. */
|
|
142
|
+
go: (state: S) => void;
|
|
143
|
+
at: At;
|
|
144
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** What a fake API answers with: the standard fetch handler, as Hono and most servers give one. */
|
|
2
|
+
export type ApiFetch = (request: Request) => Response | Promise<Response>;
|
|
3
|
+
/**
|
|
4
|
+
* The fetch handler of a fake API's module: its default export, either the
|
|
5
|
+
* function itself or an object with `fetch`.
|
|
6
|
+
*/
|
|
7
|
+
export declare function apiFetchOf(module: unknown): ApiFetch;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The fetch handler of a fake API's module: its default export, either the
|
|
3
|
+
* function itself or an object with `fetch`.
|
|
4
|
+
*/
|
|
5
|
+
export function apiFetchOf(module) {
|
|
6
|
+
const api = module?.default;
|
|
7
|
+
if (typeof api === 'function') {
|
|
8
|
+
return api;
|
|
9
|
+
}
|
|
10
|
+
const fetch = api?.fetch;
|
|
11
|
+
if (typeof fetch === 'function') {
|
|
12
|
+
return fetch.bind(api);
|
|
13
|
+
}
|
|
14
|
+
throw new Error('The fake API has no default export with fetch');
|
|
15
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Each build's fake API, run in a worker of its own: loaded on its first
|
|
3
|
+
* request, kept while it is asked things, so a visit's data stays, and stopped
|
|
4
|
+
* after `idle` with nothing asked, which frees its memory. A worker gets no
|
|
5
|
+
* environment, so a bundle sees none of the dev server's settings.
|
|
6
|
+
*/
|
|
7
|
+
export declare function createApiWorkers(idle?: number): {
|
|
8
|
+
answer: (key: string, file: string, request: Request) => Promise<Response>;
|
|
9
|
+
loaded: () => string[];
|
|
10
|
+
stopAll: () => void;
|
|
11
|
+
};
|