@peripheries/renderer 0.22.0 → 0.23.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/README.md +125 -23
- package/dist/catalog.js +2 -6
- package/dist/chunks/forms-DxA9WzCt.js +336 -0
- package/dist/chunks/{load-CjPvISzH.js → load-b38vUiZM.js} +0 -4
- package/dist/chunks/{page-bundles-DLRIBP8g.js → page-bundles-CPj_vx-J.js} +1 -5
- package/dist/chunks/{persistence-DCMakM9H.js → persistence-hurkUUQ0.js} +0 -6
- package/dist/chunks/{projection-yvYKzMOS.js → projection-zhu32_KJ.js} +1 -15
- package/dist/chunks/{query-BPuCJC1C.js → query-D6xQbTFK.js} +166 -12
- package/dist/chunks/{refs-BLUokra5.js → refs-Csgh6rXq.js} +0 -4
- package/dist/chunks/{structure-o9pYoDjD.js → structure-CKBtQHJq.js} +1 -7
- package/dist/chunks/{validate-4LgH8QMJ.js → validate-BcB_PA1k.js} +20 -13
- package/dist/core.js +138 -47
- package/dist/forms.js +2 -0
- package/dist/print.js +0 -24
- package/dist/react.js +352 -22
- package/dist/runtime.js +2 -12
- package/dist/styles.css +9 -15
- package/dist/testing.js +214 -19
- package/dist/theme.js +0 -10
- package/dist/types/catalog/check.d.ts +0 -13
- package/dist/types/core/actions.d.ts +0 -24
- package/dist/types/core/bundles/load.d.ts +0 -23
- package/dist/types/core/bundles/page-bundles.d.ts +0 -9
- package/dist/types/core/bundles/refs.d.ts +1 -28
- package/dist/types/core/bundles/resolve.d.ts +0 -10
- package/dist/types/core/cell-props.d.ts +0 -20
- package/dist/types/core/cells.d.ts +0 -21
- package/dist/types/core/data-context.d.ts +4 -21
- package/dist/types/core/diagnostics.d.ts +20 -6
- package/dist/types/core/graph.d.ts +6 -44
- package/dist/types/core/index.d.ts +4 -3
- package/dist/types/core/layout.d.ts +0 -9
- package/dist/types/core/load-page.d.ts +30 -88
- package/dist/types/core/query.d.ts +6 -52
- package/dist/types/core/references.d.ts +0 -21
- package/dist/types/core/release.d.ts +11 -0
- package/dist/types/core/rules.d.ts +0 -1
- package/dist/types/core/selected.d.ts +0 -5
- package/dist/types/core/sources.d.ts +10 -63
- package/dist/types/core/store/create-store.d.ts +0 -6
- package/dist/types/core/store/persistence.d.ts +0 -1
- package/dist/types/core/store/projection.d.ts +0 -5
- package/dist/types/core/store/scope-keys.d.ts +0 -1
- package/dist/types/core/store/types.d.ts +0 -6
- package/dist/types/core/structure.d.ts +0 -33
- package/dist/types/core/types.d.ts +2 -13
- package/dist/types/core/validate.d.ts +0 -12
- package/dist/types/core/values.d.ts +0 -6
- package/dist/types/forms/conditions.d.ts +18 -0
- package/dist/types/forms/index.d.ts +3 -0
- package/dist/types/forms/model.d.ts +90 -0
- package/dist/types/forms/port.d.ts +47 -0
- package/dist/types/print/document-bindings.d.ts +0 -61
- package/dist/types/print/document-profile.d.ts +0 -137
- package/dist/types/print/map-staleness.d.ts +0 -66
- package/dist/types/print/page-map.d.ts +1 -334
- package/dist/types/print/paginate.d.ts +0 -190
- package/dist/types/print/print-layout.d.ts +0 -161
- package/dist/types/print/print-lint.d.ts +0 -109
- package/dist/types/print/print-policy.d.ts +0 -184
- package/dist/types/print/print-stylesheet.d.ts +0 -135
- package/dist/types/print/running-header.d.ts +0 -86
- package/dist/types/print/structure-print.d.ts +1 -243
- package/dist/types/react/cell-states.d.ts +0 -2
- package/dist/types/react/cell-view.d.ts +1 -15
- package/dist/types/react/index.d.ts +1 -0
- package/dist/types/react/page-renderer.d.ts +1 -33
- package/dist/types/react/structure-view.d.ts +0 -12
- package/dist/types/react/use-cell-store.d.ts +0 -5
- package/dist/types/react/use-container-size.d.ts +0 -5
- package/dist/types/react/use-forms-runtime.d.ts +147 -0
- package/dist/types/react/use-paging.d.ts +0 -9
- package/dist/types/runtime/boot.d.ts +0 -11
- package/dist/types/runtime/install.d.ts +0 -15
- package/dist/types/runtime/shims.d.ts +0 -8
- package/dist/types/runtime/store-export.d.ts +0 -7
- package/dist/types/testing/base-props.d.ts +0 -1
- package/dist/types/testing/components.d.ts +0 -8
- package/dist/types/testing/form-workbook.d.ts +103 -0
- package/dist/types/testing/golden.d.ts +0 -16
- package/dist/types/testing/ids.d.ts +0 -2
- package/dist/types/testing/index.d.ts +1 -0
- package/dist/types/testing/sources.d.ts +0 -7
- package/dist/types/theme/check.d.ts +0 -2
- package/dist/types/theme/color.d.ts +0 -12
- package/dist/types/theme/derive.d.ts +0 -12
- package/dist/types/theme/parse.d.ts +0 -7
- package/package.json +6 -2
- package/dist/catalog.js.map +0 -1
- package/dist/chunks/load-CjPvISzH.js.map +0 -1
- package/dist/chunks/page-bundles-DLRIBP8g.js.map +0 -1
- package/dist/chunks/persistence-DCMakM9H.js.map +0 -1
- package/dist/chunks/projection-yvYKzMOS.js.map +0 -1
- package/dist/chunks/query-BPuCJC1C.js.map +0 -1
- package/dist/chunks/refs-BLUokra5.js.map +0 -1
- package/dist/chunks/structure-o9pYoDjD.js.map +0 -1
- package/dist/chunks/validate-4LgH8QMJ.js.map +0 -1
- package/dist/core.js.map +0 -1
- package/dist/print.js.map +0 -1
- package/dist/react.js.map +0 -1
- package/dist/runtime.js.map +0 -1
- package/dist/testing.js.map +0 -1
- package/dist/theme.js.map +0 -1
|
@@ -1,48 +1,31 @@
|
|
|
1
|
+
import { type VersionContext } from '@peripheries/runtime';
|
|
1
2
|
import type { CellSource, ResolvedCell } from './cells.js';
|
|
2
3
|
import type { PageRuntime } from './load-page.js';
|
|
3
4
|
import type { StateOrigin } from './types.js';
|
|
4
|
-
|
|
5
|
-
export type PropSource =
|
|
6
|
-
/** A node's state (a declared binding, or an element of an `@each` over one): `path` is inside the state's data. */
|
|
7
|
-
{
|
|
5
|
+
export type PropSource = {
|
|
8
6
|
kind: 'state';
|
|
9
7
|
graphNodeId: string;
|
|
10
8
|
reads: StateOrigin[];
|
|
11
9
|
path: string[];
|
|
12
|
-
}
|
|
13
|
-
/** A literal in the cell's props, at its prop path. */
|
|
14
|
-
| {
|
|
10
|
+
} | {
|
|
15
11
|
kind: 'literal';
|
|
16
12
|
path: string[];
|
|
17
|
-
}
|
|
18
|
-
/** A literal in the page's or the cell's static data (`data.static`): `path` starts with its label. */
|
|
19
|
-
| {
|
|
13
|
+
} | {
|
|
20
14
|
kind: 'static';
|
|
21
15
|
scope: 'page' | 'cell';
|
|
22
16
|
path: string[];
|
|
23
|
-
}
|
|
24
|
-
/** Computed, queried, walked or the host's own: not editable. */
|
|
25
|
-
| {
|
|
17
|
+
} | {
|
|
26
18
|
kind: 'derived';
|
|
27
19
|
why: 'query' | 'walk' | 'record' | 'param' | 'reserved';
|
|
28
20
|
};
|
|
29
|
-
/** A prop path (`['items', '0', 'title']`) and its source. */
|
|
30
21
|
export type PropSourceEntry = {
|
|
31
22
|
prop: string[];
|
|
32
23
|
source: PropSource;
|
|
33
24
|
};
|
|
34
|
-
/** Told of each leaf of a cell's resolved props, with its source. */
|
|
35
25
|
export type OnSource = (prop: string[], source: PropSource) => void;
|
|
36
|
-
/** Keys under a state that only the agency's tools write (data.md §9.5). */
|
|
37
26
|
export declare const TOOL_OWNED_KEYS: readonly ["content_index", "ref_index"];
|
|
38
|
-
/** A section's fields a person edits on the structure itself (data.md §9.5, `doc_edit_structure`). */
|
|
39
27
|
export declare const STRUCTURE_FIELDS: readonly ["title", "applicable", "startsPage", "directed", "status"];
|
|
40
|
-
|
|
41
|
-
* Where an edit of a value goes: the write function and the arguments that come from the source.
|
|
42
|
-
* The new value (and, for a page edit, the version seen) is the caller's. `fn: null` says why the
|
|
43
|
-
* value can't be edited here; the write functions still decide everything that can.
|
|
44
|
-
*/
|
|
45
|
-
export type EditTarget = {
|
|
28
|
+
export type EditTarget = ({
|
|
46
29
|
fn: 'doc_edit_content';
|
|
47
30
|
graphNodeId: string;
|
|
48
31
|
path: string[];
|
|
@@ -59,55 +42,19 @@ export type EditTarget = {
|
|
|
59
42
|
} | {
|
|
60
43
|
fn: 'page_edit_data';
|
|
61
44
|
path: string[];
|
|
45
|
+
}) & {
|
|
46
|
+
versionId?: string;
|
|
62
47
|
} | {
|
|
63
48
|
fn: null;
|
|
64
49
|
reason: EditRefusal;
|
|
65
50
|
};
|
|
66
|
-
export type EditRefusal =
|
|
67
|
-
/** Computed, queried or walked: nothing holds it to edit. */
|
|
68
|
-
'DERIVED'
|
|
69
|
-
/** The cell's content is its node's `page_cell_config`, not the page's. */
|
|
70
|
-
| 'NODE_CONFIG'
|
|
71
|
-
/** A `data.static` literal of a cell whose content is its node's (NODE_CONFIG's case for static data). */
|
|
72
|
-
| 'STATIC'
|
|
73
|
-
/** The read didn't say which state it saw, so no version check is possible. */
|
|
74
|
-
| 'NO_STATE_ID'
|
|
75
|
-
/** The value merges more than one system's state, so which one to write is ambiguous. */
|
|
76
|
-
| 'MERGED_READS'
|
|
77
|
-
/** Not a data state (`<tier>_data`): the document write functions write data states only. */
|
|
78
|
-
| 'NOT_DATA_STATE'
|
|
79
|
-
/** A tool-owned index (`content_index`, `ref_index`). */
|
|
80
|
-
| 'TOOL_OWNED'
|
|
81
|
-
/**
|
|
82
|
-
* An element of a list the write functions refused: a path whose index names no element
|
|
83
|
-
* (`jsonb_set_path`). The host no longer refuses list paths itself: the functions write at a
|
|
84
|
-
* path into a list (DF-SCH-9), and their dry run says whether the element exists.
|
|
85
|
-
*/
|
|
86
|
-
| 'LIST_ELEMENT';
|
|
87
|
-
/** The cell a value is in, and how its content was resolved (ResolvedCell.source). */
|
|
51
|
+
export type EditRefusal = 'DERIVED' | 'NODE_CONFIG' | 'STATIC' | 'NO_STATE_ID' | 'MERGED_READS' | 'NOT_DATA_STATE' | 'TOOL_OWNED' | 'LIST_ELEMENT' | 'VERSION_IS_RELEASE';
|
|
88
52
|
export type EditCell = {
|
|
89
53
|
id: string;
|
|
90
54
|
source?: CellSource;
|
|
91
55
|
};
|
|
92
|
-
|
|
93
|
-
* The write function an edit of this value goes to (design/data.md §9.5):
|
|
94
|
-
* - a node's data state: a section's structure field or `order` to `doc_edit_structure`,
|
|
95
|
-
* anything else to `doc_edit_content`, with the state id the viewer saw;
|
|
96
|
-
* - a literal in an inline cell, or its own `data.static`, to `page_edit_cell`'s path write, which
|
|
97
|
-
* writes the page artifact and the row together;
|
|
98
|
-
* - the page's `data.static` to `page_edit_data`'s path write;
|
|
99
|
-
* - everything else nowhere, with the reason.
|
|
100
|
-
* Paths may run through list indices: the functions write at a path into a list (DF-SCH-9).
|
|
101
|
-
*/
|
|
102
|
-
export declare function editTarget(source: PropSource, cell: EditCell): EditTarget;
|
|
103
|
-
/** A value at a path, as the nested object a patch is (`['props', 'caption']` → `{ props: { caption } }`). */
|
|
56
|
+
export declare function editTarget(source: PropSource, cell: EditCell, version?: VersionContext): EditTarget;
|
|
104
57
|
export declare function patchAt(path: readonly string[], value: unknown): unknown;
|
|
105
|
-
/**
|
|
106
|
-
* One cell's props as the renderer resolves them (CellView), with each leaf's source and value,
|
|
107
|
-
* without rendering: what an assistant reads to plan an edit (docs-forms M3). Null when the cell's
|
|
108
|
-
* conditions hide it. The same resolution context CellView builds, from the same runtime; paged
|
|
109
|
-
* labels' later pages aren't loaded, so a paged list reads its first page.
|
|
110
|
-
*/
|
|
111
58
|
export declare function cellPropSources(runtime: Pick<PageRuntime, 'page' | 'data' | 'declared' | 'cellData'>, cell: ResolvedCell, env?: {
|
|
112
59
|
params?: Record<string, unknown>;
|
|
113
60
|
baseProps?: unknown;
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import { Store } from '@tanstack/store';
|
|
2
2
|
import type { LiveEntry, ScopeId, SelectionsScope, StackStoreData, StackStoreState, ViewStateScope } from './types.js';
|
|
3
3
|
export type StackStoreApi = ReturnType<typeof createStackStore>;
|
|
4
|
-
/**
|
|
5
|
-
* The shared store, on TanStack Store (design/bundles.md §5). One instance per
|
|
6
|
-
* page tree. `getState()` returns the data with the actions, the shape the
|
|
7
|
-
* PWA's zustand store exposed to the escape-hatch API.
|
|
8
|
-
*/
|
|
9
4
|
export declare function createStackStore(initial?: Partial<StackStoreData>): {
|
|
10
5
|
getState: () => StackStoreState;
|
|
11
6
|
subscribe: (listener: (state: StackStoreState) => void) => import("@tanstack/store").Subscription;
|
|
@@ -22,6 +17,5 @@ export declare function createStackStore(initial?: Partial<StackStoreData>): {
|
|
|
22
17
|
};
|
|
23
18
|
_clearScope: (scope: ScopeId) => void;
|
|
24
19
|
_reset: () => void;
|
|
25
|
-
/** The underlying TanStack store, for `useSelector`. */
|
|
26
20
|
store: Store<StackStoreData, never>;
|
|
27
21
|
};
|
|
@@ -7,5 +7,4 @@ export interface PersistedScope {
|
|
|
7
7
|
export declare function loadScope(scope: ScopeId, mode: StorageMode): PersistedScope | null;
|
|
8
8
|
export declare function saveScope(scope: ScopeId, slice: PersistedScope, mode: StorageMode): void;
|
|
9
9
|
export declare function clearScope(scope: ScopeId, mode: StorageMode): void;
|
|
10
|
-
/** Removes every persisted scope from session and local storage: a different viewer starts clean. */
|
|
11
10
|
export declare function clearAllScopes(): void;
|
|
@@ -2,14 +2,9 @@ import type { StackStoreApi } from './create-store.js';
|
|
|
2
2
|
import { type ScopeContext } from './scope-keys.js';
|
|
3
3
|
import type { LiveDeclarations, ProjectedBundle, ScopeId, SelectionDeclarations, StackStoreData, ViewStateDeclarations } from './types.js';
|
|
4
4
|
export declare function projectSelections(decls: SelectionDeclarations | undefined, state: StackStoreData, ctx: ScopeContext): ProjectedBundle | undefined;
|
|
5
|
-
/** Selections are read-only unless `writable`. */
|
|
6
5
|
export declare function attachSelectionSetters(values: ProjectedBundle, decls: SelectionDeclarations, store: StackStoreApi, ctx: ScopeContext): ProjectedBundle;
|
|
7
6
|
export declare function projectViewState(decls: ViewStateDeclarations | undefined, state: StackStoreData, ctx: ScopeContext): ProjectedBundle | undefined;
|
|
8
|
-
/** viewState is writable unless `writable: false`. */
|
|
9
7
|
export declare function attachViewStateSetters(values: ProjectedBundle, decls: ViewStateDeclarations, store: StackStoreApi, ctx: ScopeContext): ProjectedBundle;
|
|
10
|
-
/** `live.<name>` is the data; `live.<name>Status` the envelope. */
|
|
11
8
|
export declare function projectLive(decls: LiveDeclarations | undefined, state: StackStoreData): ProjectedBundle | undefined;
|
|
12
|
-
/** Equality for a selector: re-render only when a projected channel changes. */
|
|
13
9
|
export declare function shallowEqualBundle(a: ProjectedBundle | undefined, b: ProjectedBundle | undefined): boolean;
|
|
14
|
-
/** Every scope a cell's declarations touch (for hydration and persistence). */
|
|
15
10
|
export declare function collectScopeIds(ctx: ScopeContext, selections?: SelectionDeclarations, viewState?: ViewStateDeclarations): ScopeId[];
|
|
@@ -11,14 +11,11 @@ export interface LiveEntry<T = unknown> {
|
|
|
11
11
|
export interface StackStoreData {
|
|
12
12
|
selections: Record<ScopeId, SelectionsScope>;
|
|
13
13
|
viewState: Record<ScopeId, ViewStateScope>;
|
|
14
|
-
/** Global, not scoped: a channel is one source. */
|
|
15
14
|
live: Record<string, LiveEntry>;
|
|
16
15
|
}
|
|
17
16
|
export interface StackStoreActions {
|
|
18
|
-
/** Cell-facing, through projected setter props. */
|
|
19
17
|
setSelection: (scope: ScopeId, channel: string, value: unknown) => void;
|
|
20
18
|
setViewState: (scope: ScopeId, key: string, value: unknown) => void;
|
|
21
|
-
/** Host-internal. */
|
|
22
19
|
_setLive: (channel: string, entry: LiveEntry) => void;
|
|
23
20
|
_hydrateScope: (scope: ScopeId, slice: {
|
|
24
21
|
selections?: SelectionsScope;
|
|
@@ -29,11 +26,8 @@ export interface StackStoreActions {
|
|
|
29
26
|
viewState: ViewStateScope;
|
|
30
27
|
};
|
|
31
28
|
_clearScope: (scope: ScopeId) => void;
|
|
32
|
-
/** Empties selections, view state and live data: a different viewer starts clean. */
|
|
33
29
|
_reset: () => void;
|
|
34
30
|
}
|
|
35
|
-
/** What a selector sees: the data plus the actions, as the PWA's zustand store exposed. */
|
|
36
31
|
export type StackStoreState = StackStoreData & StackStoreActions;
|
|
37
32
|
export type { LiveDecl, LiveDeclarations, SelectionDecl, SelectionDeclarations, ViewStateDecl, ViewStateDeclarations, } from '@peripheries/runtime';
|
|
38
|
-
/** Spread onto a cell's `selections` / `viewState` / `live` props. */
|
|
39
33
|
export type ProjectedBundle = Record<string, unknown>;
|
|
@@ -5,28 +5,17 @@ export type { LayoutNode, SectionKind, SectionReference };
|
|
|
5
5
|
export type ResolvedLayoutNode = Omit<LayoutNode, 'children'> & {
|
|
6
6
|
children?: ResolvedLayoutNode[];
|
|
7
7
|
};
|
|
8
|
-
/** The page's own document, which almost every page is. */
|
|
9
8
|
export declare const PAGE_DOCUMENT = "__page__";
|
|
10
|
-
/** A string child is sugar for `{ cellId }`. */
|
|
11
9
|
export declare function normalizeStructure(nodes: ReadonlyArray<LayoutNode | string> | null | undefined): ResolvedLayoutNode[];
|
|
12
|
-
/** Siblings by `order` (default 0), stable. */
|
|
13
10
|
export declare const sortByOrder: <T extends {
|
|
14
11
|
order?: number;
|
|
15
12
|
}>(nodes: readonly T[]) => T[];
|
|
16
13
|
export declare const isSectionNode: (n: ResolvedLayoutNode) => boolean;
|
|
17
14
|
export declare const isSectionKind: (v: unknown) => v is SectionKind;
|
|
18
|
-
/** A section's anchor: its cell, else its section id (the same value `DocumentSection` and the contents use). */
|
|
19
15
|
export declare const sectionAnchor: (n: Pick<ResolvedLayoutNode, "cellId" | "sectionId">) => string;
|
|
20
|
-
/**
|
|
21
|
-
* Hierarchical rendering when the structure wants it: `type: 'document'`, or
|
|
22
|
-
* any top-level node naming a section or carrying children. A flat list of
|
|
23
|
-
* `{ cellId }` is only an ordering hint for print, and renders flat.
|
|
24
|
-
*/
|
|
25
16
|
export declare function usesStructureLayout(layout: Record<string, unknown> | null | undefined): boolean;
|
|
26
17
|
export type DocumentNumbering = {
|
|
27
|
-
/** Only `kind: 'article'` sections are numbered, per document, prefixed by the parent trail. */
|
|
28
18
|
numbers: Record<string, number[]>;
|
|
29
|
-
/** Structural depth of each section. */
|
|
30
19
|
levels: Record<string, number>;
|
|
31
20
|
authoredLevels: Record<string, number>;
|
|
32
21
|
titles: Record<string, string>;
|
|
@@ -42,35 +31,19 @@ export type SectionNumbering = {
|
|
|
42
31
|
};
|
|
43
32
|
export declare const numberingFor: (numbering: SectionNumbering | undefined, documentId: string | undefined) => DocumentNumbering;
|
|
44
33
|
export declare function deriveSectionNumbering(structure: ReadonlyArray<LayoutNode | string> | null | undefined): SectionNumbering;
|
|
45
|
-
/** Per document: every target a cell in it may cite, by role (`residue`), `label:role`, or `role#clause`. */
|
|
46
34
|
export type SectionReferences = Record<string, Record<string, SectionReference>>;
|
|
47
35
|
type Documents = Record<string, {
|
|
48
36
|
label?: unknown;
|
|
49
37
|
}> | null | undefined;
|
|
50
|
-
/** Same-page section references: a document's own roles, plus `label:role` for every uniquely labelled document. */
|
|
51
38
|
export declare function deriveSectionReferences(numbering: SectionNumbering, documents: Documents): SectionReferences;
|
|
52
|
-
/**
|
|
53
|
-
* Clause citations (`role#clauseId`): each section's cells' resolved
|
|
54
|
-
* `props.blocks`, where a `clause` block's items carry ids. The item's index
|
|
55
|
-
* and the clause shape let a Reference render the clause's number.
|
|
56
|
-
*/
|
|
57
39
|
export declare function deriveElementReferences(structure: ReadonlyArray<LayoutNode | string> | null | undefined, blocksByCellId: Readonly<Record<string, unknown>>, documents: Documents): SectionReferences;
|
|
58
|
-
/** Same-page references win over data-derived ones (clauses; cross-page arrive in R5). */
|
|
59
40
|
export declare function mergeSectionReferences(samePage: SectionReferences, other: SectionReferences | undefined): SectionReferences;
|
|
60
41
|
export declare const referencesFor: (refs: SectionReferences | undefined, documentId: string | undefined) => Record<string, SectionReference>;
|
|
61
|
-
/** What stops a structure rendering: a node naming a missing cell, or an unknown section kind (a refusal, by design). */
|
|
62
42
|
export declare function structureIssues(structure: ReadonlyArray<LayoutNode | string> | null | undefined, cells: PageCell[]): string[];
|
|
63
|
-
/**
|
|
64
|
-
* A node's extrinsic pagination: a page break before, keep-with-previous
|
|
65
|
-
* (break-before: avoid), or avoid breaking inside. `breakInside: 'auto'` is
|
|
66
|
-
* dropped, so a node can't relax what a component declares; a break before
|
|
67
|
-
* wins over keep-with-previous. The component's own @printPolicy joins in R5.
|
|
68
|
-
*/
|
|
69
43
|
export declare function nodePrintStyle(node: Pick<LayoutNode, 'print'>): {
|
|
70
44
|
breakBefore?: 'page' | 'avoid';
|
|
71
45
|
breakInside?: 'avoid';
|
|
72
46
|
} | undefined;
|
|
73
|
-
/** One entry in a document's table of contents. */
|
|
74
47
|
export type ContentsEntry = {
|
|
75
48
|
sectionId: string;
|
|
76
49
|
anchor: string;
|
|
@@ -79,10 +52,4 @@ export type ContentsEntry = {
|
|
|
79
52
|
level: number;
|
|
80
53
|
children: ContentsEntry[];
|
|
81
54
|
};
|
|
82
|
-
/**
|
|
83
|
-
* A document's table of contents (INV-DOC-1): its sections in order, nested, with the numbers
|
|
84
|
-
* articles get and the anchors the page renders (`sectionAnchor`). A section's title is its
|
|
85
|
-
* structure node's, else its cell's `title` prop, else its id. `tocHidden` sections are left out,
|
|
86
|
-
* their children kept in their place. Only the page's own document.
|
|
87
|
-
*/
|
|
88
55
|
export declare function tableOfContents(structure: ReadonlyArray<LayoutNode | string> | null | undefined, cells?: ReadonlyArray<PageCell>): ContentsEntry[];
|
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
import type { DeclaredBinding, PageCell, QueryDescriptor } from '@peripheries/runtime';
|
|
2
|
-
/** One source in a DataContext: the value and its state. */
|
|
3
|
-
/** A paged label's position (QueryDescriptor.paging): what loading its next page needs. */
|
|
4
2
|
export type DataPage = {
|
|
5
3
|
hasMore: boolean;
|
|
6
4
|
endCursor: string | null;
|
|
7
5
|
descriptor: QueryDescriptor;
|
|
8
6
|
variables: Record<string, unknown>;
|
|
9
7
|
};
|
|
10
|
-
/**
|
|
11
|
-
* A label's read. `unresolved` names the references that resolved to nothing, so the query never
|
|
12
|
-
* ran (QUERY_UNRESOLVED): there is nothing to show yet, which is not a failed read.
|
|
13
|
-
*/
|
|
14
8
|
export type DataEntry = {
|
|
15
9
|
data: unknown;
|
|
16
10
|
isLoading: boolean;
|
|
@@ -19,18 +13,13 @@ export type DataEntry = {
|
|
|
19
13
|
unresolved?: string[];
|
|
20
14
|
origin?: DataOrigin;
|
|
21
15
|
};
|
|
22
|
-
/** A system a label's value was read from, and the newest state seen there (null: none, or the source doesn't say). */
|
|
23
16
|
export type StateOrigin = {
|
|
24
17
|
systemId: string;
|
|
25
18
|
name?: string;
|
|
26
19
|
stateId: string | null;
|
|
20
|
+
versionId?: string | null;
|
|
21
|
+
outOfScope?: boolean;
|
|
27
22
|
};
|
|
28
|
-
/**
|
|
29
|
-
* Where a label's value came from (INV-DOC-6), so an edit can go back to it (design/data.md §9.5).
|
|
30
|
-
* `at` is the path inside the source to the label's value: inside the state's data (a binding's
|
|
31
|
-
* `field`, an `@each` element's index), or the label and its path in the page's or cell's static data.
|
|
32
|
-
* A label without an origin was read some other way (a query): it isn't editable.
|
|
33
|
-
*/
|
|
34
23
|
export type DataOrigin = {
|
|
35
24
|
kind: 'state';
|
|
36
25
|
graphNodeId: string;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { type Diagnostic } from './graph.js';
|
|
2
2
|
import { type Each } from './references.js';
|
|
3
3
|
import type { PageCell, ProjectPage } from './types.js';
|
|
4
|
-
/** What validation knows about the components in scope. Stream 3 fills it from the catalog. */
|
|
5
4
|
export type Catalog = {
|
|
6
5
|
components: Record<string, {
|
|
7
6
|
props_schema?: {
|
|
@@ -11,34 +10,23 @@ export type Catalog = {
|
|
|
11
10
|
} | null;
|
|
12
11
|
} | undefined>;
|
|
13
12
|
};
|
|
14
|
-
/**
|
|
15
|
-
* The names nearest a name that isn't in scope, nearest first: a near spelling
|
|
16
|
-
* (`Prse`), or each of its words starting a word of the name (`DocSection` →
|
|
17
|
-
* `DocumentSection`). Full-text search can't find either.
|
|
18
|
-
*/
|
|
19
13
|
export declare function nearestNames(name: string, names: Iterable<string>, limit?: number): string[];
|
|
20
14
|
export declare const RESPONSIVE_BUCKETS: readonly ["narrow", "compact", "wide"];
|
|
21
15
|
export declare const STORE_SCOPES: readonly ["page", "project"];
|
|
22
16
|
export declare const WALK_DIRECTIONS: readonly ["incoming", "outgoing", "both"];
|
|
23
|
-
/** Options: `template` for a page template, whose node bindings are filled when it is instantiated. */
|
|
24
17
|
export type ValidateOptions = {
|
|
25
18
|
template?: boolean;
|
|
26
19
|
};
|
|
27
|
-
/** What is wrong with a projection's form, if anything: the one judgement EACH_INVALID and validatePageProps share. */
|
|
28
20
|
export declare function eachFormProblems(value: Each): string[];
|
|
29
|
-
/** One cell's configuration. `ids` are the page's cell ids, for `children`. */
|
|
30
21
|
export declare function validateCell(cell: PageCell, catalog?: Catalog, path?: string, ids?: ReadonlySet<string>, options?: ValidateOptions): Diagnostic[];
|
|
31
|
-
/** A whole page: every cell, the page's own declarations, unique cell ids, and its document structure. */
|
|
32
22
|
export declare function validatePage(page: Pick<ProjectPage, 'content' | 'layout'> & {
|
|
33
23
|
is_template?: boolean | null;
|
|
34
24
|
}, catalog?: Catalog): Diagnostic[];
|
|
35
|
-
/** A slot a component declares in its props schema: `properties.<name>["x-slot"]` (ui-consistency.md §2.8). */
|
|
36
25
|
export type SlotDeclaration = {
|
|
37
26
|
name: string;
|
|
38
27
|
accepts?: readonly string[];
|
|
39
28
|
max?: number;
|
|
40
29
|
};
|
|
41
|
-
/** The slots a catalog entry declares, by name. */
|
|
42
30
|
export declare function declaredSlots(schema: {
|
|
43
31
|
properties?: Record<string, unknown>;
|
|
44
32
|
} | null | undefined): Map<string, SlotDeclaration>;
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
import type { Traversal } from '@peripheries/runtime';
|
|
2
2
|
import type { PageRuntime } from './load-page.js';
|
|
3
3
|
import type { ProjectPage } from './types.js';
|
|
4
|
-
/**
|
|
5
|
-
* `values` are labels and their resolved values, on top of the page's static
|
|
6
|
-
* data. `traversal` is `@_traversal` for every walking cell: one subgraph for
|
|
7
|
-
* all of them, or one per cell id; a walking cell it doesn't cover gets an
|
|
8
|
-
* empty one, as the host gives a walk that found nothing.
|
|
9
|
-
*/
|
|
10
4
|
export declare function pageRuntimeFromValues(page: ProjectPage, { values, traversal }?: {
|
|
11
5
|
values?: Record<string, unknown>;
|
|
12
6
|
traversal?: Traversal | Record<string, Traversal>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare const CONDITION_OPS: readonly ["eq", "ne", "in", "not_in", "gt", "lt", "gte", "lte", "contains", "not_contains", "empty", "not_empty"];
|
|
2
|
+
export type ConditionOp = (typeof CONDITION_OPS)[number];
|
|
3
|
+
export interface ConditionClause {
|
|
4
|
+
q: string;
|
|
5
|
+
op: ConditionOp | (string & {});
|
|
6
|
+
value?: unknown;
|
|
7
|
+
}
|
|
8
|
+
export interface Condition {
|
|
9
|
+
all: ConditionClause[];
|
|
10
|
+
not?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare function isConditionOp(op: unknown): op is ConditionOp;
|
|
13
|
+
export declare function evaluateCondition(condition: Condition | null | undefined, answers: Record<string, unknown>, onProblem?: (problem: string) => void): boolean;
|
|
14
|
+
export declare function normalizeOperator(op: unknown): ConditionOp | null;
|
|
15
|
+
export declare function normalizeCondition(legacy: unknown): {
|
|
16
|
+
condition: Condition | null;
|
|
17
|
+
problems: string[];
|
|
18
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { CONDITION_OPS, evaluateCondition, isConditionOp, normalizeCondition, normalizeOperator, type Condition, type ConditionClause, type ConditionOp } from './conditions.js';
|
|
2
|
+
export { defaultMode, enterAdvances, fromPageSteps, goTo, goToQuestion, isReadOnlyStatus, linkTo, missing, move, positionFromLink, positionsOf, progress, questionsOf, settle, stepKind, visibleSteps, type DisplayMode, type FormChapter, type FormItem, type FormItemKind, type FormLink, type FormModel, type FormQuestion, type FormQuestionDefinition, type FormStep, type Position, type StepKind, type StepProgress, type SubmissionStatus, } from './model.js';
|
|
3
|
+
export type { AnswerToSave, FileToUpload, FormsPort, FormsRefusal, FormsResult } from './port.js';
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { type Condition } from './conditions.js';
|
|
2
|
+
export type FormQuestion = {
|
|
3
|
+
key: string;
|
|
4
|
+
label: string;
|
|
5
|
+
required: boolean;
|
|
6
|
+
singleLine: boolean;
|
|
7
|
+
when?: Condition | null;
|
|
8
|
+
node?: string;
|
|
9
|
+
definition?: FormQuestionDefinition;
|
|
10
|
+
};
|
|
11
|
+
export type FormQuestionDefinition = {
|
|
12
|
+
type: string;
|
|
13
|
+
options?: unknown[];
|
|
14
|
+
validation?: Record<string, unknown>;
|
|
15
|
+
description?: string;
|
|
16
|
+
helpText?: string;
|
|
17
|
+
};
|
|
18
|
+
export type FormItemKind = 'question' | 'content' | 'document' | 'review' | 'upload' | 'other';
|
|
19
|
+
export type FormItem = {
|
|
20
|
+
id: string;
|
|
21
|
+
kind: FormItemKind;
|
|
22
|
+
questions: FormQuestion[];
|
|
23
|
+
when?: Condition | null;
|
|
24
|
+
};
|
|
25
|
+
export type FormStep = {
|
|
26
|
+
id: string;
|
|
27
|
+
title: string;
|
|
28
|
+
chapter?: string;
|
|
29
|
+
label?: string;
|
|
30
|
+
items: FormItem[];
|
|
31
|
+
when?: Condition | null;
|
|
32
|
+
};
|
|
33
|
+
export type FormChapter = {
|
|
34
|
+
id: string;
|
|
35
|
+
title: string;
|
|
36
|
+
};
|
|
37
|
+
export type FormModel = {
|
|
38
|
+
title: string;
|
|
39
|
+
chapters: FormChapter[];
|
|
40
|
+
steps: FormStep[];
|
|
41
|
+
submitRequired: 'warn' | 'block';
|
|
42
|
+
allowBack: boolean;
|
|
43
|
+
submittable?: boolean;
|
|
44
|
+
};
|
|
45
|
+
export type StepKind = 'answer' | 'read' | 'review' | 'upload' | 'submit';
|
|
46
|
+
export type SubmissionStatus = 'in_progress' | 'submitted' | 'changes_requested' | 'completed';
|
|
47
|
+
export type DisplayMode = 'step' | 'question';
|
|
48
|
+
export declare function visibleSteps(model: FormModel, values: Record<string, unknown>): FormStep[];
|
|
49
|
+
export declare const questionsOf: (step: FormStep) => FormQuestion[];
|
|
50
|
+
export declare function stepKind(step: FormStep, isLast: boolean): StepKind;
|
|
51
|
+
export type Position = {
|
|
52
|
+
step: string;
|
|
53
|
+
question?: string;
|
|
54
|
+
};
|
|
55
|
+
export declare function positionsOf(steps: FormStep[], mode: DisplayMode): Position[];
|
|
56
|
+
export declare function settle(steps: FormStep[], mode: DisplayMode, at: Position | null): Position | null;
|
|
57
|
+
export declare function move(steps: FormStep[], mode: DisplayMode, at: Position, by: 1 | -1): Position | null;
|
|
58
|
+
export declare function goTo(steps: FormStep[], mode: DisplayMode, stepId: string, values: Record<string, unknown>): Position | null;
|
|
59
|
+
export declare function goToQuestion(steps: FormStep[], mode: DisplayMode, key: string): Position | null;
|
|
60
|
+
export declare function enterAdvances(step: FormStep, mode: DisplayMode, question?: string): boolean;
|
|
61
|
+
export declare function missing(steps: FormStep[], values: Record<string, unknown>, stepId?: string): FormQuestion[];
|
|
62
|
+
export type StepProgress = {
|
|
63
|
+
answered: number;
|
|
64
|
+
total: number;
|
|
65
|
+
complete: boolean;
|
|
66
|
+
};
|
|
67
|
+
export declare function progress(steps: FormStep[], values: Record<string, unknown>, visited: ReadonlySet<string>): {
|
|
68
|
+
answered: number;
|
|
69
|
+
required: number;
|
|
70
|
+
ratio: number;
|
|
71
|
+
total: {
|
|
72
|
+
answered: number;
|
|
73
|
+
count: number;
|
|
74
|
+
};
|
|
75
|
+
perStep: Record<string, StepProgress>;
|
|
76
|
+
};
|
|
77
|
+
export declare const isReadOnlyStatus: (status: SubmissionStatus | null | undefined) => status is "submitted" | "completed";
|
|
78
|
+
export declare const defaultMode: (phone: boolean) => DisplayMode;
|
|
79
|
+
export declare function fromPageSteps(page: {
|
|
80
|
+
name?: string | null;
|
|
81
|
+
layout?: Record<string, unknown> | null;
|
|
82
|
+
}, itemOf: (cellId: string) => FormItem | null): FormModel;
|
|
83
|
+
export type FormLink = {
|
|
84
|
+
mode?: 'question';
|
|
85
|
+
page?: string;
|
|
86
|
+
section?: string;
|
|
87
|
+
question?: string;
|
|
88
|
+
};
|
|
89
|
+
export declare function positionFromLink(steps: FormStep[], mode: DisplayMode, link: FormLink): Position | null;
|
|
90
|
+
export declare function linkTo(steps: FormStep[], mode: DisplayMode, at: Position): FormLink;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { FileAnswer } from '@peripheries/runtime';
|
|
2
|
+
export type FormsRefusal = 'CONFLICT' | 'ANSWER_TYPE' | 'ANSWER_OPTION' | 'ANSWER_REQUIRED' | 'ANSWER_FILE_PATH' | 'ANSWER_VALIDATION' | 'FORM_INCOMPLETE' | 'FORM_NOT_OPEN' | 'FORM_COMPLETED' | 'FORM_STEP_UNKNOWN' | 'NO_CAPABILITY' | 'NETWORK' | (string & {});
|
|
3
|
+
export type FormsResult<T extends object = object> = ({
|
|
4
|
+
ok: true;
|
|
5
|
+
} & T) | {
|
|
6
|
+
ok: false;
|
|
7
|
+
code: FormsRefusal;
|
|
8
|
+
message?: string;
|
|
9
|
+
detail?: unknown;
|
|
10
|
+
};
|
|
11
|
+
export type FileToUpload = Blob & {
|
|
12
|
+
readonly name: string;
|
|
13
|
+
};
|
|
14
|
+
export type AnswerToSave = {
|
|
15
|
+
key: string;
|
|
16
|
+
node?: string;
|
|
17
|
+
value: unknown;
|
|
18
|
+
expectedStateId?: string | null;
|
|
19
|
+
};
|
|
20
|
+
export interface FormsPort {
|
|
21
|
+
save(answer: AnswerToSave): Promise<FormsResult<{
|
|
22
|
+
stateId?: string | null;
|
|
23
|
+
}>>;
|
|
24
|
+
submit(input: {
|
|
25
|
+
missing: string[];
|
|
26
|
+
}): Promise<FormsResult<{
|
|
27
|
+
status: 'submitted';
|
|
28
|
+
missing: string[];
|
|
29
|
+
}>>;
|
|
30
|
+
reopen(): Promise<FormsResult<{
|
|
31
|
+
status: 'in_progress';
|
|
32
|
+
}>>;
|
|
33
|
+
visit(stepId: string): Promise<FormsResult>;
|
|
34
|
+
upload?(input: {
|
|
35
|
+
key: string;
|
|
36
|
+
node?: string;
|
|
37
|
+
file: FileToUpload;
|
|
38
|
+
}): Promise<FormsResult<{
|
|
39
|
+
answer: {
|
|
40
|
+
v: 1;
|
|
41
|
+
file: FileAnswer;
|
|
42
|
+
};
|
|
43
|
+
}>>;
|
|
44
|
+
openFile?(file: FileAnswer): Promise<FormsResult<{
|
|
45
|
+
url: string;
|
|
46
|
+
}>>;
|
|
47
|
+
}
|
|
@@ -1,41 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Values for the region bindings a profile names.
|
|
3
|
-
*
|
|
4
|
-
* ── The gap this closes ─────────────────────────────────────────────────────
|
|
5
|
-
*
|
|
6
|
-
* A profile says WHICH margin box holds WHAT: `instrument`'s footer is
|
|
7
|
-
* `{ left: 'execution-state', right: 'page-x-of-y' }`. Only the second is
|
|
8
|
-
* computable — CSS produces page numbers during pagination. The rest are facts
|
|
9
|
-
* about *this document*, which the bundle cannot know and the host must supply.
|
|
10
|
-
*
|
|
11
|
-
* Until now it supplied none, so every `instrument` page was unprintable:
|
|
12
|
-
* `execution-state` is in `requiredBindings`, and a will that does not say
|
|
13
|
-
* "Not for execution" is a will that does not say it is a draft.
|
|
14
|
-
*
|
|
15
|
-
* ── Why the page declares them, keyed by binding name ───────────────────────
|
|
16
|
-
*
|
|
17
|
-
* `project_page.metadata.document.bindings` — a flat map from binding name to
|
|
18
|
-
* string. Keyed by the binding name itself rather than by some host-side
|
|
19
|
-
* camelCase alias, because a translation layer is one more place for
|
|
20
|
-
* `document-id` and `documentId` to disagree, and because a binding a bundle adds
|
|
21
|
-
* then works with no host change at all.
|
|
22
|
-
*
|
|
23
|
-
* ── What this deliberately does NOT do ──────────────────────────────────────
|
|
24
|
-
*
|
|
25
|
-
* It does not DERIVE anything. `execution-state` could plausibly be computed
|
|
26
|
-
* from a document status — an org's naming system defines DRAFT / REVIEW /
|
|
27
|
-
* FINAL / EXECUTED, and is emphatic that *"`FINAL` and `EXECUTED` are not the
|
|
28
|
-
* same thing… never collapse these"*. Encoding that mapping here would be
|
|
29
|
-
* inventing legal policy in a stylesheet helper, and getting it wrong prints a
|
|
30
|
-
* document asserting the wrong status — the exact failure `requiredBindings`
|
|
31
|
-
* exists to prevent, arriving through the fix for it.
|
|
32
|
-
*
|
|
33
|
-
* So: declared values only. A page that has not declared them stays unprintable,
|
|
34
|
-
* visibly, with the reason on the button. That is the correct state for a
|
|
35
|
-
* document nobody has said the status of.
|
|
36
|
-
*/
|
|
37
1
|
import type { PageRegionValues } from './print-stylesheet.js';
|
|
38
|
-
/** The `metadata.document` shape. Open — a profile may name bindings we predate. */
|
|
39
2
|
export interface DocumentBindingsMetadata {
|
|
40
3
|
bindings?: Record<string, unknown>;
|
|
41
4
|
}
|
|
@@ -45,32 +8,8 @@ interface PageLike {
|
|
|
45
8
|
}
|
|
46
9
|
export interface ResolvedBindings {
|
|
47
10
|
values: PageRegionValues;
|
|
48
|
-
/** Declared keys whose value was not a usable string. Named, never coerced. */
|
|
49
11
|
malformed: string[];
|
|
50
12
|
}
|
|
51
|
-
/**
|
|
52
|
-
* Read declared binding values off a page record.
|
|
53
|
-
*
|
|
54
|
-
* Non-string values are DROPPED and reported rather than stringified. `42` would
|
|
55
|
-
* render as "42" in a footer and look deliberate; `null` would render as "null".
|
|
56
|
-
* A footer is read as an assertion about the document, so a value that arrived
|
|
57
|
-
* by accident must not reach one.
|
|
58
|
-
*/
|
|
59
13
|
export declare function resolveRegionBindings(page: PageLike | null | undefined): ResolvedBindings;
|
|
60
|
-
/**
|
|
61
|
-
* The profile id the page names, plus a detector for the second copy of it.
|
|
62
|
-
*
|
|
63
|
-
* `layout.profile` is authoritative — a profile is geometry and belongs beside
|
|
64
|
-
* `structure`. But the proof page carries `metadata.profile` as well, with
|
|
65
|
-
* the same value, and **the host reads only one of them**. Today they agree; the
|
|
66
|
-
* database has 1 page with each key and 0 disagreements. That is two sources for
|
|
67
|
-
* one fact, in sync by luck, with no detector — the shape this pair of repos has
|
|
68
|
-
* now caught four times (`PaperConfig` vs the profile, two type scales, two
|
|
69
|
-
* paginators, and the carried-field lists).
|
|
70
|
-
*
|
|
71
|
-
* Rather than reading both and picking, or silently ignoring one: read `layout`,
|
|
72
|
-
* and say so loudly the moment the copies disagree. Enforcement is cheap here
|
|
73
|
-
* precisely because it is not yet a problem.
|
|
74
|
-
*/
|
|
75
14
|
export declare function resolveProfileId(page: PageLike | null | undefined): string | undefined;
|
|
76
15
|
export {};
|