@polyxd/core 0.3.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/LICENSE +202 -0
- package/NOTICE +190 -0
- package/README.md +43 -0
- package/dist/actionbar.d.ts +20 -0
- package/dist/actionbar.js +34 -0
- package/dist/actionbar.js.map +1 -0
- package/dist/actions.d.ts +24 -0
- package/dist/actions.js +33 -0
- package/dist/actions.js.map +1 -0
- package/dist/avatar.d.ts +13 -0
- package/dist/avatar.js +63 -0
- package/dist/avatar.js.map +1 -0
- package/dist/chart.d.ts +41 -0
- package/dist/chart.js +106 -0
- package/dist/chart.js.map +1 -0
- package/dist/choice.d.ts +35 -0
- package/dist/choice.js +32 -0
- package/dist/choice.js.map +1 -0
- package/dist/collection.d.ts +54 -0
- package/dist/collection.js +61 -0
- package/dist/collection.js.map +1 -0
- package/dist/color.d.ts +20 -0
- package/dist/color.js +105 -0
- package/dist/color.js.map +1 -0
- package/dist/comparison.d.ts +21 -0
- package/dist/comparison.js +51 -0
- package/dist/comparison.js.map +1 -0
- package/dist/data.d.ts +30 -0
- package/dist/data.js +67 -0
- package/dist/data.js.map +1 -0
- package/dist/document.d.ts +64 -0
- package/dist/document.js +18 -0
- package/dist/document.js.map +1 -0
- package/dist/files.d.ts +18 -0
- package/dist/files.js +64 -0
- package/dist/files.js.map +1 -0
- package/dist/filter.d.ts +17 -0
- package/dist/filter.js +55 -0
- package/dist/filter.js.map +1 -0
- package/dist/format.d.ts +21 -0
- package/dist/format.js +81 -0
- package/dist/format.js.map +1 -0
- package/dist/frame.d.ts +21 -0
- package/dist/frame.js +30 -0
- package/dist/frame.js.map +1 -0
- package/dist/ids.d.ts +4 -0
- package/dist/ids.js +8 -0
- package/dist/ids.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/marks.d.ts +48 -0
- package/dist/marks.js +57 -0
- package/dist/marks.js.map +1 -0
- package/dist/mask.d.ts +10 -0
- package/dist/mask.js +40 -0
- package/dist/mask.js.map +1 -0
- package/dist/options.d.ts +11 -0
- package/dist/options.js +21 -0
- package/dist/options.js.map +1 -0
- package/dist/qr.d.ts +3 -0
- package/dist/qr.js +242 -0
- package/dist/qr.js.map +1 -0
- package/dist/richtext.d.ts +17 -0
- package/dist/richtext.js +59 -0
- package/dist/richtext.js.map +1 -0
- package/dist/shortcuts.d.ts +32 -0
- package/dist/shortcuts.js +59 -0
- package/dist/shortcuts.js.map +1 -0
- package/dist/skeleton.d.ts +22 -0
- package/dist/skeleton.js +32 -0
- package/dist/skeleton.js.map +1 -0
- package/dist/split.d.ts +53 -0
- package/dist/split.js +55 -0
- package/dist/split.js.map +1 -0
- package/dist/steps.d.ts +32 -0
- package/dist/steps.js +24 -0
- package/dist/steps.js.map +1 -0
- package/dist/surface.d.ts +52 -0
- package/dist/surface.js +64 -0
- package/dist/surface.js.map +1 -0
- package/dist/table.d.ts +34 -0
- package/dist/table.js +30 -0
- package/dist/table.js.map +1 -0
- package/dist/tree.d.ts +58 -0
- package/dist/tree.js +93 -0
- package/dist/tree.js.map +1 -0
- package/dist/views.d.ts +11 -0
- package/dist/views.js +10 -0
- package/dist/views.js.map +1 -0
- package/package.json +36 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Shortcut keys: how each is shown on Apple, shown elsewhere, written in aria-keyshortcuts, and
|
|
3
|
+
* what KeyboardEvent.key reports. Letters, digits and F-keys are derived. 'mod' is a modifier
|
|
4
|
+
* that resolves per platform, so it is handled in parseShortcut.
|
|
5
|
+
*/
|
|
6
|
+
export const SHORTCUT_KEYS = {
|
|
7
|
+
ctrl: ["⌃", "Ctrl", "Control", "ctrlKey"],
|
|
8
|
+
alt: ["⌥", "Alt", "Alt", "altKey"],
|
|
9
|
+
shift: ["⇧", "Shift", "Shift", "shiftKey"],
|
|
10
|
+
enter: ["↵", "Enter", "Enter", "enter"],
|
|
11
|
+
escape: ["⎋", "Esc", "Escape", "escape"],
|
|
12
|
+
space: ["Space", "Space", "Space", " "],
|
|
13
|
+
tab: ["⇥", "Tab", "Tab", "tab"],
|
|
14
|
+
backspace: ["⌫", "Backspace", "Backspace", "backspace"],
|
|
15
|
+
delete: ["⌦", "Del", "Delete", "delete"],
|
|
16
|
+
arrowup: ["↑", "↑", "ArrowUp", "arrowup"],
|
|
17
|
+
arrowdown: ["↓", "↓", "ArrowDown", "arrowdown"],
|
|
18
|
+
arrowleft: ["←", "←", "ArrowLeft", "arrowleft"],
|
|
19
|
+
arrowright: ["→", "→", "ArrowRight", "arrowright"],
|
|
20
|
+
home: ["Home", "Home", "Home", "home"],
|
|
21
|
+
end: ["End", "End", "End", "end"],
|
|
22
|
+
slash: ["/", "/", "/", "/"],
|
|
23
|
+
comma: [",", ",", ",", ","],
|
|
24
|
+
period: [".", ".", ".", "."],
|
|
25
|
+
};
|
|
26
|
+
export const MODIFIER_FLAGS = ["metaKey", "ctrlKey", "altKey", "shiftKey"];
|
|
27
|
+
/** Splits "mod+shift+d" into what to show, what to announce, and what to match on keydown. */
|
|
28
|
+
export function parseShortcut(shortcut, apple) {
|
|
29
|
+
const parts = shortcut.toLowerCase().split("+");
|
|
30
|
+
const key = parts.pop();
|
|
31
|
+
const hint = [];
|
|
32
|
+
const aria = [];
|
|
33
|
+
const flags = new Set();
|
|
34
|
+
for (const m of parts) {
|
|
35
|
+
const [a, o, name, flag] = m === "mod" ? (apple ? ["⌘", "Ctrl", "Meta", "metaKey"] : SHORTCUT_KEYS.ctrl) : SHORTCUT_KEYS[m];
|
|
36
|
+
hint.push(apple ? a : o);
|
|
37
|
+
aria.push(name);
|
|
38
|
+
flags.add(flag);
|
|
39
|
+
}
|
|
40
|
+
const named = SHORTCUT_KEYS[key];
|
|
41
|
+
hint.push(named ? (apple ? named[0] : named[1]) : key.toUpperCase());
|
|
42
|
+
aria.push(named ? named[2] : key.toUpperCase());
|
|
43
|
+
return { hint, aria: aria.join("+"), flags, key: named ? named[3] : key };
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Whether a key event is this shortcut: the modifiers exactly, and the key by name, or by physical
|
|
47
|
+
* key for letters and digits (Alt on a Mac rewrites e.key to a symbol).
|
|
48
|
+
*/
|
|
49
|
+
export function shortcutMatches(s, e) {
|
|
50
|
+
if (!MODIFIER_FLAGS.every((f) => e[f] === s.flags.has(f)))
|
|
51
|
+
return false;
|
|
52
|
+
const physical = /^[a-z0-9]$/.test(s.key) && e.code.toLowerCase() === (/\d/.test(s.key) ? `digit${s.key}` : `key${s.key}`);
|
|
53
|
+
return e.key.toLowerCase() === s.key || physical;
|
|
54
|
+
}
|
|
55
|
+
/** Typing into a field must never fire an unmodified shortcut (shift alone still types). */
|
|
56
|
+
export const unmodified = (s) => !s.flags.has("metaKey") && !s.flags.has("ctrlKey") && !s.flags.has("altKey");
|
|
57
|
+
/** Whether a platform string names an Apple device, where 'mod' is ⌘. */
|
|
58
|
+
export const isApplePlatform = (platform) => /mac|iphone|ipad|ipod/i.test(platform);
|
|
59
|
+
//# sourceMappingURL=shortcuts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shortcuts.js","sourceRoot":"","sources":["../src/shortcuts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** The loading state for a surface that has not arrived yet: the shape it will take. */
|
|
2
|
+
export type SkeletonShape = "list" | "form" | "detail" | "dashboard" | "dialog" | "compare";
|
|
3
|
+
export type BlockKind = "title" | "line" | "small" | "field" | "button" | "square" | "circle" | "badge" | "value" | "chart";
|
|
4
|
+
export type BlockSize = "short" | "medium" | "long" | "full";
|
|
5
|
+
/** One placeholder block, or a group of them: rows, stacked lines, an action row, a list of pairs, cards. */
|
|
6
|
+
export type SkeletonPart = {
|
|
7
|
+
block: BlockKind;
|
|
8
|
+
size?: BlockSize;
|
|
9
|
+
} | {
|
|
10
|
+
group: "row" | "lines" | "actions" | "dl" | "cards" | "card";
|
|
11
|
+
parts: SkeletonPart[];
|
|
12
|
+
};
|
|
13
|
+
/** What each pattern's surface usually looks like, so the placeholder has the right silhouette. */
|
|
14
|
+
export declare const PATTERN_SHAPE: Record<string, SkeletonShape>;
|
|
15
|
+
/** An explicit shape wins; a pattern picks one; otherwise a record page. */
|
|
16
|
+
export declare const skeletonShape: (pattern?: string, shape?: SkeletonShape) => SkeletonShape;
|
|
17
|
+
/** The silhouettes, as data, so every renderer draws the same one. */
|
|
18
|
+
export declare const SKELETON_SHAPES: Record<SkeletonShape, SkeletonPart[]>;
|
|
19
|
+
/** The class each group takes, matching the stylesheet. */
|
|
20
|
+
export declare const SKELETON_GROUP_CLASS: Record<string, string>;
|
|
21
|
+
/** The status a skeleton announces. */
|
|
22
|
+
export declare const skeletonStatus: (title?: string) => string;
|
package/dist/skeleton.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** The loading state for a surface that has not arrived yet: the shape it will take. */
|
|
2
|
+
/** What each pattern's surface usually looks like, so the placeholder has the right silhouette. */
|
|
3
|
+
export const PATTERN_SHAPE = {
|
|
4
|
+
"multi-step-form": "form",
|
|
5
|
+
"filter-and-browse": "list",
|
|
6
|
+
"undo-over-confirm": "list",
|
|
7
|
+
"compare-and-choose": "compare",
|
|
8
|
+
"confirm-destructive": "dialog",
|
|
9
|
+
"review-and-submit": "detail",
|
|
10
|
+
};
|
|
11
|
+
/** An explicit shape wins; a pattern picks one; otherwise a record page. */
|
|
12
|
+
export const skeletonShape = (pattern, shape) => shape ?? (pattern ? PATTERN_SHAPE[pattern] : undefined) ?? "detail";
|
|
13
|
+
const block = (block, size) => ({ block, size });
|
|
14
|
+
const group = (kind, parts) => ({ group: kind, parts });
|
|
15
|
+
const times = (n, f) => Array.from({ length: n }, (_, i) => f(i));
|
|
16
|
+
/** The silhouettes, as data, so every renderer draws the same one. */
|
|
17
|
+
export const SKELETON_SHAPES = {
|
|
18
|
+
list: [block("field", "full"), ...times(5, (i) => group("row", [block("square"), group("lines", [block("line", i % 2 ? "medium" : "long"), block("small", "short")])]))],
|
|
19
|
+
form: [...times(4, (i) => group("lines", [block("small", "short"), block("field", i === 1 ? "medium" : "long")])), group("actions", [block("button"), block("button")])],
|
|
20
|
+
detail: [
|
|
21
|
+
group("row", [block("circle"), group("lines", [group("row", [block("line", "medium"), block("badge")]), block("small", "short")])]),
|
|
22
|
+
group("dl", times(6, (i) => group("row", [block("small", "short"), block("line", i % 3 === 2 ? "medium" : "long")]))),
|
|
23
|
+
],
|
|
24
|
+
dashboard: [group("cards", times(3, () => group("card", [block("small", "short"), block("value", "medium")]))), block("chart", "full")],
|
|
25
|
+
dialog: [block("line", "long"), block("line", "medium"), group("actions", [block("button"), block("button")])],
|
|
26
|
+
compare: [group("cards", times(3, () => group("card", [block("line", "medium"), ...times(5, (i) => block("small", i % 2 ? "short" : "long"))])))],
|
|
27
|
+
};
|
|
28
|
+
/** The class each group takes, matching the stylesheet. */
|
|
29
|
+
export const SKELETON_GROUP_CLASS = { row: "pxd-skeleton-row", lines: "pxd-skeleton-lines", actions: "pxd-skeleton-actions", dl: "pxd-skeleton-dl", cards: "pxd-skeleton-cards", card: "pxd-skeleton-card" };
|
|
30
|
+
/** The status a skeleton announces. */
|
|
31
|
+
export const skeletonStatus = (title) => (title ? `Preparing ${title}` : "Preparing");
|
|
32
|
+
//# sourceMappingURL=skeleton.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skeleton.js","sourceRoot":"","sources":["../src/skeleton.ts"],"names":[],"mappings":"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"}
|
package/dist/split.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Master and detail. Wide: two panes. Compact: the list, then the detail as a page with a Back
|
|
3
|
+
* control. The decisions live here so every renderer shows the same pane at the same width.
|
|
4
|
+
*/
|
|
5
|
+
import { type Scope } from "./data.ts";
|
|
6
|
+
import type { Node } from "./document.ts";
|
|
7
|
+
/** Below this surface width the detail replaces the list instead of sitting beside it. */
|
|
8
|
+
export declare const SPLIT_COMPACT_PX = 640;
|
|
9
|
+
/** The list's share of the width, by ratio, and how far a resizable handle may move it. */
|
|
10
|
+
export declare const SHARE: Record<string, number>;
|
|
11
|
+
export declare const SHARE_MIN = 20;
|
|
12
|
+
export declare const SHARE_MAX = 80;
|
|
13
|
+
export interface SplitState {
|
|
14
|
+
compact: boolean;
|
|
15
|
+
/** Back on compact shows the list again without dropping the selection. */
|
|
16
|
+
listShown: boolean;
|
|
17
|
+
share: number;
|
|
18
|
+
}
|
|
19
|
+
export type SplitAction = {
|
|
20
|
+
type: "measure";
|
|
21
|
+
width: number;
|
|
22
|
+
} | {
|
|
23
|
+
type: "back";
|
|
24
|
+
} | {
|
|
25
|
+
type: "selected";
|
|
26
|
+
} | {
|
|
27
|
+
type: "share";
|
|
28
|
+
value: number;
|
|
29
|
+
} | {
|
|
30
|
+
type: "key";
|
|
31
|
+
key: string;
|
|
32
|
+
shift?: boolean;
|
|
33
|
+
};
|
|
34
|
+
export declare const initialSplit: (ratio: string | undefined) => SplitState;
|
|
35
|
+
export declare const clampShare: (v: number) => number;
|
|
36
|
+
export declare function splitReducer(state: SplitState, action: SplitAction): SplitState;
|
|
37
|
+
/** Which panes show: both when wide; on compact, the detail once something is selected, until Back. */
|
|
38
|
+
export declare function splitPanes(state: SplitState, hasSelection: boolean): {
|
|
39
|
+
showList: boolean;
|
|
40
|
+
showDetail: boolean;
|
|
41
|
+
};
|
|
42
|
+
/** The value the primary selects an item by: its id when it has one, else its index (as Collection and Table do). */
|
|
43
|
+
export declare const splitItemValue: (item: unknown, index: number, valuePath: string | undefined, data: unknown, pointer: string) => unknown;
|
|
44
|
+
export interface SplitSelection {
|
|
45
|
+
has: boolean;
|
|
46
|
+
index: number;
|
|
47
|
+
/** The selected item's scope, so the detail's relative bindings read that item */
|
|
48
|
+
scope?: Scope;
|
|
49
|
+
/** The item's name, for the announcement: what the list shows as its title, else a name-like field */
|
|
50
|
+
name?: string;
|
|
51
|
+
}
|
|
52
|
+
/** What is selected in the primary, found the way the primary itself selects. */
|
|
53
|
+
export declare function splitSelection(node: Node, byId: Map<string, Node>, data: unknown, scope: Scope): SplitSelection;
|
package/dist/split.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Master and detail. Wide: two panes. Compact: the list, then the detail as a page with a Back
|
|
3
|
+
* control. The decisions live here so every renderer shows the same pane at the same width.
|
|
4
|
+
*/
|
|
5
|
+
import { absolute, asList, childPointer, get, resolve } from "./data.js";
|
|
6
|
+
/** Below this surface width the detail replaces the list instead of sitting beside it. */
|
|
7
|
+
export const SPLIT_COMPACT_PX = 640;
|
|
8
|
+
/** The list's share of the width, by ratio, and how far a resizable handle may move it. */
|
|
9
|
+
export const SHARE = { narrow: 33.333, balanced: 50, wide: 66.667 };
|
|
10
|
+
export const SHARE_MIN = 20;
|
|
11
|
+
export const SHARE_MAX = 80;
|
|
12
|
+
export const initialSplit = (ratio) => ({ compact: false, listShown: false, share: SHARE[ratio ?? "narrow"] ?? SHARE.narrow });
|
|
13
|
+
export const clampShare = (v) => Math.min(SHARE_MAX, Math.max(SHARE_MIN, v));
|
|
14
|
+
export function splitReducer(state, action) {
|
|
15
|
+
switch (action.type) {
|
|
16
|
+
case "measure":
|
|
17
|
+
return { ...state, compact: action.width < SPLIT_COMPACT_PX };
|
|
18
|
+
case "back":
|
|
19
|
+
return { ...state, listShown: true };
|
|
20
|
+
// A new selection shows its detail; on compact it takes the screen.
|
|
21
|
+
case "selected":
|
|
22
|
+
return { ...state, listShown: false };
|
|
23
|
+
case "share":
|
|
24
|
+
return { ...state, share: clampShare(action.value) };
|
|
25
|
+
case "key": {
|
|
26
|
+
const step = action.shift ? 10 : 5;
|
|
27
|
+
const next = action.key === "ArrowLeft" ? state.share - step : action.key === "ArrowRight" ? state.share + step : action.key === "Home" ? SHARE_MIN : action.key === "End" ? SHARE_MAX : undefined;
|
|
28
|
+
return next === undefined ? state : { ...state, share: clampShare(next) };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/** Which panes show: both when wide; on compact, the detail once something is selected, until Back. */
|
|
33
|
+
export function splitPanes(state, hasSelection) {
|
|
34
|
+
const showDetail = !state.compact || (hasSelection && !state.listShown);
|
|
35
|
+
return { showList: !state.compact || !showDetail, showDetail };
|
|
36
|
+
}
|
|
37
|
+
/** The value the primary selects an item by: its id when it has one, else its index (as Collection and Table do). */
|
|
38
|
+
export const splitItemValue = (item, index, valuePath, data, pointer) => valuePath ? get(data, absolute(valuePath, { pointer })) : item && typeof item === "object" && "id" in item ? item.id : index;
|
|
39
|
+
/** What is selected in the primary, found the way the primary itself selects. */
|
|
40
|
+
export function splitSelection(node, byId, data, scope) {
|
|
41
|
+
const selected = resolve(node.selected, data, scope);
|
|
42
|
+
const has = selected !== undefined && selected !== null && selected !== "";
|
|
43
|
+
const primary = byId.get(node.primary);
|
|
44
|
+
const listPath = primary?.component === "Table" ? primary.rows?.path : primary?.items?.path;
|
|
45
|
+
const pointer = typeof listPath === "string" ? absolute(listPath, scope) : undefined;
|
|
46
|
+
const items = pointer ? asList(get(data, pointer)) : [];
|
|
47
|
+
const index = pointer ? items.findIndex((item, i) => splitItemValue(item, i, primary?.rowValuePath, data, childPointer(pointer, i)) === selected) : -1;
|
|
48
|
+
const itemScope = pointer && index >= 0 ? { pointer: childPointer(pointer, index) } : undefined;
|
|
49
|
+
const template = primary?.items?.componentId ? byId.get(primary.items.componentId) : undefined;
|
|
50
|
+
const item = index >= 0 ? items[index] : undefined;
|
|
51
|
+
const titled = itemScope && template?.title !== undefined ? resolve(template.title, data, itemScope) : undefined;
|
|
52
|
+
const name = has ? String(titled ?? item?.name ?? item?.title ?? item?.label ?? selected) : undefined;
|
|
53
|
+
return { has, index, scope: itemScope, name };
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=split.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"split.js","sourceRoot":"","sources":["../src/split.ts"],"names":[],"mappings":"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"}
|
package/dist/steps.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** The Steps state machines: a wizard's current step, and a task list's open task. */
|
|
2
|
+
export interface StepsState {
|
|
3
|
+
index: number;
|
|
4
|
+
total: number;
|
|
5
|
+
}
|
|
6
|
+
export type StepsAction = {
|
|
7
|
+
type: "back";
|
|
8
|
+
} | {
|
|
9
|
+
type: "next";
|
|
10
|
+
} | {
|
|
11
|
+
type: "go";
|
|
12
|
+
index: number;
|
|
13
|
+
};
|
|
14
|
+
/** Moves within the steps; never past either end. */
|
|
15
|
+
export declare function stepsReducer(state: StepsState, action: StepsAction): StepsState;
|
|
16
|
+
/** Where a wizard starts: the bound step when the document binds one, else the first. */
|
|
17
|
+
export declare const initialStep: (bound: unknown, total: number) => StepsState;
|
|
18
|
+
export declare const isLastStep: (s: StepsState) => boolean;
|
|
19
|
+
/** What the wizard says above the steps. */
|
|
20
|
+
export declare const stepsProgress: (s: StepsState) => string;
|
|
21
|
+
/** Task statuses (GOV.UK task list) and the tone each is shown in. */
|
|
22
|
+
export declare const TASK_STATUS: Record<string, {
|
|
23
|
+
label: string;
|
|
24
|
+
tone: string;
|
|
25
|
+
}>;
|
|
26
|
+
export declare const taskStatus: (status: string | undefined) => {
|
|
27
|
+
label: string;
|
|
28
|
+
tone: string;
|
|
29
|
+
};
|
|
30
|
+
/** A task opens in place; opening another closes it; opening it again closes it. */
|
|
31
|
+
export declare const tasklistReducer: (open: string | null, key: string) => string | null;
|
|
32
|
+
export declare const tasklistProgress: (done: number, total: number) => string;
|
package/dist/steps.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** The Steps state machines: a wizard's current step, and a task list's open task. */
|
|
2
|
+
const clamp = (i, total) => Math.max(0, Math.min(total - 1, i));
|
|
3
|
+
/** Moves within the steps; never past either end. */
|
|
4
|
+
export function stepsReducer(state, action) {
|
|
5
|
+
const index = action.type === "back" ? state.index - 1 : action.type === "next" ? state.index + 1 : action.index;
|
|
6
|
+
return { ...state, index: clamp(index, state.total) };
|
|
7
|
+
}
|
|
8
|
+
/** Where a wizard starts: the bound step when the document binds one, else the first. */
|
|
9
|
+
export const initialStep = (bound, total) => ({ index: typeof bound === "number" ? clamp(bound, total) : 0, total });
|
|
10
|
+
export const isLastStep = (s) => s.index === s.total - 1;
|
|
11
|
+
/** What the wizard says above the steps. */
|
|
12
|
+
export const stepsProgress = (s) => `Step ${s.index + 1} of ${s.total}`;
|
|
13
|
+
/** Task statuses (GOV.UK task list) and the tone each is shown in. */
|
|
14
|
+
export const TASK_STATUS = {
|
|
15
|
+
todo: { label: "Not started", tone: "neutral" },
|
|
16
|
+
inProgress: { label: "In progress", tone: "info" },
|
|
17
|
+
done: { label: "Completed", tone: "success" },
|
|
18
|
+
blocked: { label: "Cannot start yet", tone: "neutral" },
|
|
19
|
+
};
|
|
20
|
+
export const taskStatus = (status) => TASK_STATUS[status ?? "todo"] ?? TASK_STATUS.todo;
|
|
21
|
+
/** A task opens in place; opening another closes it; opening it again closes it. */
|
|
22
|
+
export const tasklistReducer = (open, key) => (open === key ? null : key);
|
|
23
|
+
export const tasklistProgress = (done, total) => `${done} of ${total} tasks completed`;
|
|
24
|
+
//# sourceMappingURL=steps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"steps.js","sourceRoot":"","sources":["../src/steps.ts"],"names":[],"mappings":"AAAA,sFAAsF;AAStF,MAAM,KAAK,GAAG,CAAC,CAAS,EAAE,KAAa,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAEhF,qDAAqD;AACrD,MAAM,UAAU,YAAY,CAAC,KAAiB,EAAE,MAAmB;IACjE,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;IACjH,OAAO,EAAE,GAAG,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;AACxD,CAAC;AAED,yFAAyF;AACzF,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAc,EAAE,KAAa,EAAc,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;AAElJ,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAa,EAAW,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC;AAE9E,4CAA4C;AAC5C,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAa,EAAU,EAAE,CAAC,QAAQ,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC;AAE5F,sEAAsE;AACtE,MAAM,CAAC,MAAM,WAAW,GAAoD;IAC1E,IAAI,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,SAAS,EAAE;IAC/C,UAAU,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE;IAClD,IAAI,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE;IAC7C,OAAO,EAAE,EAAE,KAAK,EAAE,kBAAkB,EAAE,IAAI,EAAE,SAAS,EAAE;CACxD,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,MAA0B,EAAmC,EAAE,CAAC,WAAW,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC;AAE7I,oFAAoF;AACpF,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,IAAmB,EAAE,GAAW,EAAiB,EAAE,CAAC,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAEhH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,IAAY,EAAE,KAAa,EAAU,EAAE,CAAC,GAAG,IAAI,OAAO,KAAK,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { type Data, type Scope } from "./data.ts";
|
|
2
|
+
import type { Action, ActionEvent, Node, UIDocument } from "./document.ts";
|
|
3
|
+
import { type Format } from "./format.ts";
|
|
4
|
+
export interface SurfaceOptions {
|
|
5
|
+
/** Host data. Defaults to document.data. */
|
|
6
|
+
data?: Data;
|
|
7
|
+
locale?: string;
|
|
8
|
+
/**
|
|
9
|
+
* Derived data: called after every input change with the new data and may return a replacement,
|
|
10
|
+
* so a receipt, a total or a filtered list can follow what the person types. Pure.
|
|
11
|
+
*/
|
|
12
|
+
derive?: (data: Data) => Data | void;
|
|
13
|
+
/** Called for every capability action the user triggers. */
|
|
14
|
+
onAction?: (event: ActionEvent) => void;
|
|
15
|
+
/** Called with the new data whenever an input changes it. */
|
|
16
|
+
onDataChange?: (data: Data) => void;
|
|
17
|
+
/** Called for ui.dismiss (Cancel on a dialog, closing the surface). */
|
|
18
|
+
onDismiss?: () => void;
|
|
19
|
+
}
|
|
20
|
+
export interface Surface {
|
|
21
|
+
document: UIDocument;
|
|
22
|
+
byId: Map<string, Node>;
|
|
23
|
+
/** The current data; a new object after every change. */
|
|
24
|
+
readonly data: Data;
|
|
25
|
+
locale: string;
|
|
26
|
+
/** Writes an input's value at an absolute pointer, derives, and tells the host and the subscribers. */
|
|
27
|
+
setValue: (pointer: string, value: unknown) => void;
|
|
28
|
+
/** Replaces the data wholesale (a shell adopting the host's new copy). */
|
|
29
|
+
replaceData: (data: Data) => void;
|
|
30
|
+
dispatch: (action: Action | undefined, scope: Scope, source: string) => void;
|
|
31
|
+
/** Called after every change to the data; returns the unsubscribe. */
|
|
32
|
+
subscribe: (listener: (data: Data) => void) => () => void;
|
|
33
|
+
/** A literal or binding, resolved in a scope (the root scope by default). */
|
|
34
|
+
resolve: <T = unknown>(value: unknown, scope?: Scope) => T;
|
|
35
|
+
/** A literal or binding as text, formatted when a format is given. */
|
|
36
|
+
text: (value: unknown, format?: Format, scope?: Scope) => string;
|
|
37
|
+
/** The absolute pointer of a binding in a scope. */
|
|
38
|
+
pointer: (binding: {
|
|
39
|
+
path: string;
|
|
40
|
+
}, scope?: Scope) => string;
|
|
41
|
+
/** Writes a binding's value in a scope. */
|
|
42
|
+
write: (binding: {
|
|
43
|
+
path: string;
|
|
44
|
+
}, value: unknown, scope?: Scope) => void;
|
|
45
|
+
/** An action context with its bindings resolved in a scope. */
|
|
46
|
+
context: (context: Record<string, unknown> | undefined, scope?: Scope) => Record<string, unknown>;
|
|
47
|
+
/** Whether a node is visible in a scope: its `visible` binding, when it has one. */
|
|
48
|
+
visible: (node: Node, scope?: Scope) => boolean;
|
|
49
|
+
}
|
|
50
|
+
export declare function createSurface(document: UIDocument, options?: SurfaceOptions): Surface;
|
|
51
|
+
/** Accessibility attributes from a node's `accessibility` block, plus which component rendered the element. */
|
|
52
|
+
export declare function a11yAttributes(node: Node, resolveText: (v: unknown) => string | undefined): Record<string, unknown>;
|
package/dist/surface.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The headless surface: one document, its data, and the semantics every renderer shares, with no
|
|
3
|
+
* DOM and no framework. A renderer walks `byId` from `document.root`, reads values through
|
|
4
|
+
* `resolve` and `text`, writes inputs through `setValue`, sends actions through `dispatch`, and
|
|
5
|
+
* redraws on `subscribe`.
|
|
6
|
+
*/
|
|
7
|
+
import { dispatchAction } from "./actions.js";
|
|
8
|
+
import { ROOT_SCOPE, absolute, resolve, resolveContext, set } from "./data.js";
|
|
9
|
+
import { indexById } from "./document.js";
|
|
10
|
+
import { formatValue, resolveFormat } from "./format.js";
|
|
11
|
+
export function createSurface(document, options = {}) {
|
|
12
|
+
let data = options.data ?? document.data ?? {};
|
|
13
|
+
const listeners = new Set();
|
|
14
|
+
const locale = options.locale ?? "en-GB";
|
|
15
|
+
const notify = () => listeners.forEach((l) => l(data));
|
|
16
|
+
const surface = {
|
|
17
|
+
document,
|
|
18
|
+
byId: indexById(document),
|
|
19
|
+
get data() {
|
|
20
|
+
return data;
|
|
21
|
+
},
|
|
22
|
+
locale,
|
|
23
|
+
setValue(pointer, value) {
|
|
24
|
+
const written = set(data, pointer, value);
|
|
25
|
+
data = options.derive?.(written) ?? written;
|
|
26
|
+
options.onDataChange?.(data);
|
|
27
|
+
notify();
|
|
28
|
+
},
|
|
29
|
+
replaceData(next) {
|
|
30
|
+
data = next;
|
|
31
|
+
notify();
|
|
32
|
+
},
|
|
33
|
+
dispatch: (action, scope, source) => dispatchAction(action, scope, source, data, options),
|
|
34
|
+
subscribe(listener) {
|
|
35
|
+
listeners.add(listener);
|
|
36
|
+
return () => listeners.delete(listener);
|
|
37
|
+
},
|
|
38
|
+
resolve: (value, scope = ROOT_SCOPE) => resolve(value, data, scope),
|
|
39
|
+
text(value, format, scope = ROOT_SCOPE) {
|
|
40
|
+
const r = resolve(value, data, scope);
|
|
41
|
+
return format ? formatValue(r, resolveFormat(format, data, scope), locale) : r === undefined || r === null ? "" : String(r);
|
|
42
|
+
},
|
|
43
|
+
pointer: (binding, scope = ROOT_SCOPE) => absolute(binding.path, scope),
|
|
44
|
+
write: (binding, value, scope = ROOT_SCOPE) => surface.setValue(absolute(binding.path, scope), value),
|
|
45
|
+
context: (context, scope = ROOT_SCOPE) => resolveContext(context, data, scope),
|
|
46
|
+
visible: (node, scope = ROOT_SCOPE) => node.visible === undefined || resolve(node.visible, data, scope) !== false,
|
|
47
|
+
};
|
|
48
|
+
return surface;
|
|
49
|
+
}
|
|
50
|
+
/** Accessibility attributes from a node's `accessibility` block, plus which component rendered the element. */
|
|
51
|
+
export function a11yAttributes(node, resolveText) {
|
|
52
|
+
const ids = { "data-pxd-id": node.id, "data-pxd-component": node.component };
|
|
53
|
+
const a = node.accessibility;
|
|
54
|
+
if (!a)
|
|
55
|
+
return ids;
|
|
56
|
+
return {
|
|
57
|
+
...ids,
|
|
58
|
+
"aria-label": a.label !== undefined ? resolveText(a.label) : undefined,
|
|
59
|
+
"aria-description": a.description !== undefined ? resolveText(a.description) : undefined,
|
|
60
|
+
"aria-live": a.live,
|
|
61
|
+
"aria-hidden": a.hidden || undefined,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=surface.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"surface.js","sourceRoot":"","sources":["../src/surface.ts"],"names":[],"mappings":"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"}
|
package/dist/table.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** Table decisions: when it stacks, which columns are numbers, what a stacked row shows, paging. */
|
|
2
|
+
import { type Scope } from "./data.ts";
|
|
3
|
+
import type { Node } from "./document.ts";
|
|
4
|
+
/** Below this width a table becomes a list of rows. */
|
|
5
|
+
export declare const TABLE_COMPACT_PX = 720;
|
|
6
|
+
export declare const PAGE_SIZES: number[];
|
|
7
|
+
export declare const isNumericColumn: (c: any) => boolean;
|
|
8
|
+
/** A stacked row: the first column as its title, one status badge, and up to three details. */
|
|
9
|
+
export declare function stackedColumns(columns: any[]): {
|
|
10
|
+
first: any;
|
|
11
|
+
status: any | undefined;
|
|
12
|
+
details: any[];
|
|
13
|
+
};
|
|
14
|
+
/** The value a row is selected and expanded by: rowValuePath, else the row's id, else its index. */
|
|
15
|
+
export declare const rowValue: (node: Node, rows: unknown[], i: number, data: unknown, scope: Scope) => unknown;
|
|
16
|
+
export declare const rowScopes: (pointer: string, rows: unknown[]) => Scope[];
|
|
17
|
+
/** Toggles a value in a selection list. */
|
|
18
|
+
export declare const toggleValue: (list: unknown[], v: unknown) => unknown[];
|
|
19
|
+
/** Sorting a column again flips it; sorting another starts ascending. */
|
|
20
|
+
export declare const nextSort: (key: string, column: string | undefined, direction: string | undefined) => "ascending" | "descending";
|
|
21
|
+
/** How many cells a row has, for a detail row that spans them. */
|
|
22
|
+
export declare const columnCount: (node: Node, expandable: boolean, selectable: boolean) => number;
|
|
23
|
+
export interface PagingState {
|
|
24
|
+
index: number;
|
|
25
|
+
size: number;
|
|
26
|
+
total: number;
|
|
27
|
+
pages: number;
|
|
28
|
+
from: number;
|
|
29
|
+
to: number;
|
|
30
|
+
/** The sizes offered, always including the current one */
|
|
31
|
+
sizes: number[];
|
|
32
|
+
}
|
|
33
|
+
/** Rows per page, the range shown, and how many pages there are. */
|
|
34
|
+
export declare function paging(index: unknown, size: unknown, total: unknown, rows: number): PagingState;
|
package/dist/table.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** Table decisions: when it stacks, which columns are numbers, what a stacked row shows, paging. */
|
|
2
|
+
import { absolute, childPointer, get } from "./data.js";
|
|
3
|
+
/** Below this width a table becomes a list of rows. */
|
|
4
|
+
export const TABLE_COMPACT_PX = 720;
|
|
5
|
+
export const PAGE_SIZES = [10, 25, 50, 100];
|
|
6
|
+
const NUMERIC = new Set(["number", "currency", "percent", "duration"]);
|
|
7
|
+
export const isNumericColumn = (c) => c.align === "end" || (c.align !== "start" && (c.kind === "number" || c.kind === "currency" || NUMERIC.has(c.format?.type)));
|
|
8
|
+
/** A stacked row: the first column as its title, one status badge, and up to three details. */
|
|
9
|
+
export function stackedColumns(columns) {
|
|
10
|
+
const [first, ...rest] = columns;
|
|
11
|
+
return { first, status: rest.find((c) => c.kind === "status"), details: rest.filter((c) => c.kind !== "status").slice(0, 3) };
|
|
12
|
+
}
|
|
13
|
+
/** The value a row is selected and expanded by: rowValuePath, else the row's id, else its index. */
|
|
14
|
+
export const rowValue = (node, rows, i, data, scope) => node.rowValuePath ? get(data, absolute(node.rowValuePath, scope)) : (rows[i]?.id ?? i);
|
|
15
|
+
export const rowScopes = (pointer, rows) => rows.map((_, i) => ({ pointer: childPointer(pointer, i) }));
|
|
16
|
+
/** Toggles a value in a selection list. */
|
|
17
|
+
export const toggleValue = (list, v) => (list.includes(v) ? list.filter((x) => x !== v) : [...list, v]);
|
|
18
|
+
/** Sorting a column again flips it; sorting another starts ascending. */
|
|
19
|
+
export const nextSort = (key, column, direction) => (key === column && direction === "ascending" ? "descending" : "ascending");
|
|
20
|
+
/** How many cells a row has, for a detail row that spans them. */
|
|
21
|
+
export const columnCount = (node, expandable, selectable) => node.columns.length + (expandable ? 1 : 0) + (selectable ? 1 : 0) + (node.rowActions || node.rowAction ? 1 : 0);
|
|
22
|
+
/** Rows per page, the range shown, and how many pages there are. */
|
|
23
|
+
export function paging(index, size, total, rows) {
|
|
24
|
+
const i = typeof index === "number" ? index : 1;
|
|
25
|
+
const s = typeof size === "number" ? size : rows;
|
|
26
|
+
const t = typeof total === "number" ? total : rows;
|
|
27
|
+
const pages = Math.max(1, Math.ceil(t / (s || 1)));
|
|
28
|
+
return { index: i, size: s, total: t, pages, from: t === 0 ? 0 : (i - 1) * s + 1, to: Math.min(i * s, t), sizes: [...new Set([...PAGE_SIZES, s])].sort((a, c) => a - c) };
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=table.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"table.js","sourceRoot":"","sources":["../src/table.ts"],"names":[],"mappings":"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"}
|
package/dist/tree.d.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/** Tree: the open part of a hierarchy flattened into rows, and the moves between them. */
|
|
2
|
+
import { type Scope } from "./data.ts";
|
|
3
|
+
import type { Node } from "./document.ts";
|
|
4
|
+
/** Beyond this many visible rows the tree renders only the rows in (and just around) its viewport. */
|
|
5
|
+
export declare const VIRTUAL_LIMIT = 200;
|
|
6
|
+
/** Rows rendered above and below the viewport so keyboard moves and quick scrolls don't flash blank. */
|
|
7
|
+
export declare const OVERSCAN = 10;
|
|
8
|
+
/** Type-ahead resets after this pause. */
|
|
9
|
+
export declare const TYPEAHEAD_MS = 500;
|
|
10
|
+
/** One visible row of the flattened tree. */
|
|
11
|
+
export interface TreeRow {
|
|
12
|
+
/** Pointer to the node in host data; stable identity for keys and focus. */
|
|
13
|
+
key: string;
|
|
14
|
+
scope: Scope;
|
|
15
|
+
level: number;
|
|
16
|
+
setsize: number;
|
|
17
|
+
posinset: number;
|
|
18
|
+
label: string;
|
|
19
|
+
value: unknown;
|
|
20
|
+
detail: string | undefined;
|
|
21
|
+
hasChildren: boolean;
|
|
22
|
+
expanded: boolean;
|
|
23
|
+
/** Index of the parent row in the flat list, -1 at the top level. */
|
|
24
|
+
parent: number;
|
|
25
|
+
}
|
|
26
|
+
/** Flatten the open part of the hierarchy, depth first. Without an expanded set, the first level is open. */
|
|
27
|
+
export declare function treeRows(node: Node, data: unknown, scope: Scope, expanded: Set<unknown> | null): {
|
|
28
|
+
rows: TreeRow[];
|
|
29
|
+
indexByKey: Map<string, number>;
|
|
30
|
+
topValues: unknown[];
|
|
31
|
+
};
|
|
32
|
+
/** Type-ahead: the next row whose label starts with what was typed; the same letter repeated cycles. */
|
|
33
|
+
export declare function typeAheadTarget(rows: TreeRow[], from: number, buffer: string): number;
|
|
34
|
+
/** What a key does in a tree (WAI-ARIA APG tree view): where focus goes, or what toggles. */
|
|
35
|
+
export type TreeMove = {
|
|
36
|
+
focus: number;
|
|
37
|
+
} | {
|
|
38
|
+
toggle: true;
|
|
39
|
+
} | {
|
|
40
|
+
activate: true;
|
|
41
|
+
} | {
|
|
42
|
+
select: true;
|
|
43
|
+
} | {
|
|
44
|
+
expandSiblings: true;
|
|
45
|
+
} | {
|
|
46
|
+
typeAhead: string;
|
|
47
|
+
} | undefined;
|
|
48
|
+
export declare function treeKey(rows: TreeRow[], index: number, e: {
|
|
49
|
+
key: string;
|
|
50
|
+
ctrlKey: boolean;
|
|
51
|
+
metaKey: boolean;
|
|
52
|
+
altKey: boolean;
|
|
53
|
+
}): TreeMove;
|
|
54
|
+
/** The window of rows to draw when virtualised. */
|
|
55
|
+
export declare function visibleWindow(rowCount: number, scrollTop: number, rowHeight: number, viewportHeight: number): {
|
|
56
|
+
start: number;
|
|
57
|
+
end: number;
|
|
58
|
+
};
|