@peripheries/renderer 0.23.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.
Files changed (100) hide show
  1. package/README.md +45 -33
  2. package/dist/catalog.js +2 -6
  3. package/dist/chunks/{forms-CCAE7sCu.js → forms-DxA9WzCt.js} +0 -6
  4. package/dist/chunks/{load-CjPvISzH.js → load-b38vUiZM.js} +0 -4
  5. package/dist/chunks/{page-bundles-DLRIBP8g.js → page-bundles-CPj_vx-J.js} +1 -5
  6. package/dist/chunks/{persistence-DCMakM9H.js → persistence-hurkUUQ0.js} +0 -6
  7. package/dist/chunks/{projection-yvYKzMOS.js → projection-zhu32_KJ.js} +1 -15
  8. package/dist/chunks/{query-LnTbQghF.js → query-D6xQbTFK.js} +0 -6
  9. package/dist/chunks/{refs-BLUokra5.js → refs-Csgh6rXq.js} +0 -4
  10. package/dist/chunks/{structure-BrKSgzRJ.js → structure-CKBtQHJq.js} +1 -7
  11. package/dist/chunks/{validate-B_g7719l.js → validate-BcB_PA1k.js} +2 -10
  12. package/dist/core.js +9 -25
  13. package/dist/forms.js +1 -1
  14. package/dist/print.js +0 -24
  15. package/dist/react.js +4 -22
  16. package/dist/runtime.js +2 -12
  17. package/dist/styles.css +9 -15
  18. package/dist/testing.js +5 -21
  19. package/dist/theme.js +0 -10
  20. package/dist/types/catalog/check.d.ts +0 -13
  21. package/dist/types/core/actions.d.ts +0 -24
  22. package/dist/types/core/bundles/load.d.ts +0 -23
  23. package/dist/types/core/bundles/page-bundles.d.ts +0 -9
  24. package/dist/types/core/bundles/refs.d.ts +1 -28
  25. package/dist/types/core/bundles/resolve.d.ts +0 -10
  26. package/dist/types/core/cell-props.d.ts +0 -20
  27. package/dist/types/core/cells.d.ts +0 -21
  28. package/dist/types/core/data-context.d.ts +0 -22
  29. package/dist/types/core/diagnostics.d.ts +1 -3
  30. package/dist/types/core/graph.d.ts +0 -54
  31. package/dist/types/core/layout.d.ts +0 -9
  32. package/dist/types/core/load-page.d.ts +0 -111
  33. package/dist/types/core/query.d.ts +0 -64
  34. package/dist/types/core/references.d.ts +0 -21
  35. package/dist/types/core/release.d.ts +0 -10
  36. package/dist/types/core/rules.d.ts +0 -1
  37. package/dist/types/core/selected.d.ts +0 -5
  38. package/dist/types/core/sources.d.ts +5 -64
  39. package/dist/types/core/store/create-store.d.ts +0 -6
  40. package/dist/types/core/store/persistence.d.ts +0 -1
  41. package/dist/types/core/store/projection.d.ts +0 -5
  42. package/dist/types/core/store/scope-keys.d.ts +0 -1
  43. package/dist/types/core/store/types.d.ts +0 -6
  44. package/dist/types/core/structure.d.ts +0 -33
  45. package/dist/types/core/types.d.ts +0 -13
  46. package/dist/types/core/validate.d.ts +0 -12
  47. package/dist/types/core/values.d.ts +0 -6
  48. package/dist/types/forms/conditions.d.ts +0 -37
  49. package/dist/types/forms/model.d.ts +0 -44
  50. package/dist/types/forms/port.d.ts +0 -22
  51. package/dist/types/print/document-bindings.d.ts +0 -61
  52. package/dist/types/print/document-profile.d.ts +0 -137
  53. package/dist/types/print/map-staleness.d.ts +0 -66
  54. package/dist/types/print/page-map.d.ts +1 -334
  55. package/dist/types/print/paginate.d.ts +0 -190
  56. package/dist/types/print/print-layout.d.ts +0 -161
  57. package/dist/types/print/print-lint.d.ts +0 -109
  58. package/dist/types/print/print-policy.d.ts +0 -184
  59. package/dist/types/print/print-stylesheet.d.ts +0 -135
  60. package/dist/types/print/running-header.d.ts +0 -86
  61. package/dist/types/print/structure-print.d.ts +1 -243
  62. package/dist/types/react/cell-states.d.ts +0 -2
  63. package/dist/types/react/cell-view.d.ts +0 -16
  64. package/dist/types/react/page-renderer.d.ts +0 -37
  65. package/dist/types/react/structure-view.d.ts +0 -12
  66. package/dist/types/react/use-cell-store.d.ts +0 -5
  67. package/dist/types/react/use-container-size.d.ts +0 -5
  68. package/dist/types/react/use-forms-runtime.d.ts +1 -55
  69. package/dist/types/react/use-paging.d.ts +0 -9
  70. package/dist/types/runtime/boot.d.ts +0 -11
  71. package/dist/types/runtime/install.d.ts +0 -15
  72. package/dist/types/runtime/shims.d.ts +0 -8
  73. package/dist/types/runtime/store-export.d.ts +0 -7
  74. package/dist/types/testing/base-props.d.ts +0 -1
  75. package/dist/types/testing/components.d.ts +0 -8
  76. package/dist/types/testing/form-workbook.d.ts +0 -3
  77. package/dist/types/testing/golden.d.ts +0 -16
  78. package/dist/types/testing/ids.d.ts +0 -2
  79. package/dist/types/testing/sources.d.ts +0 -7
  80. package/dist/types/theme/check.d.ts +0 -2
  81. package/dist/types/theme/color.d.ts +0 -12
  82. package/dist/types/theme/derive.d.ts +0 -12
  83. package/dist/types/theme/parse.d.ts +0 -7
  84. package/package.json +2 -2
  85. package/dist/catalog.js.map +0 -1
  86. package/dist/chunks/forms-CCAE7sCu.js.map +0 -1
  87. package/dist/chunks/load-CjPvISzH.js.map +0 -1
  88. package/dist/chunks/page-bundles-DLRIBP8g.js.map +0 -1
  89. package/dist/chunks/persistence-DCMakM9H.js.map +0 -1
  90. package/dist/chunks/projection-yvYKzMOS.js.map +0 -1
  91. package/dist/chunks/query-LnTbQghF.js.map +0 -1
  92. package/dist/chunks/refs-BLUokra5.js.map +0 -1
  93. package/dist/chunks/structure-BrKSgzRJ.js.map +0 -1
  94. package/dist/chunks/validate-B_g7719l.js.map +0 -1
  95. package/dist/core.js.map +0 -1
  96. package/dist/print.js.map +0 -1
  97. package/dist/react.js.map +0 -1
  98. package/dist/runtime.js.map +0 -1
  99. package/dist/testing.js.map +0 -1
  100. package/dist/theme.js.map +0 -1
@@ -2,47 +2,29 @@ import { type VersionContext } from '@peripheries/runtime';
2
2
  import type { CellSource, ResolvedCell } from './cells.js';
3
3
  import type { PageRuntime } from './load-page.js';
4
4
  import type { StateOrigin } from './types.js';
5
- /** Where one prop's value came from. `path` is where the value sits in its source. */
6
- export type PropSource =
7
- /** A node's state (a declared binding, or an element of an `@each` over one): `path` is inside the state's data. */
8
- {
5
+ export type PropSource = {
9
6
  kind: 'state';
10
7
  graphNodeId: string;
11
8
  reads: StateOrigin[];
12
9
  path: string[];
13
- }
14
- /** A literal in the cell's props, at its prop path. */
15
- | {
10
+ } | {
16
11
  kind: 'literal';
17
12
  path: string[];
18
- }
19
- /** A literal in the page's or the cell's static data (`data.static`): `path` starts with its label. */
20
- | {
13
+ } | {
21
14
  kind: 'static';
22
15
  scope: 'page' | 'cell';
23
16
  path: string[];
24
- }
25
- /** Computed, queried, walked or the host's own: not editable. */
26
- | {
17
+ } | {
27
18
  kind: 'derived';
28
19
  why: 'query' | 'walk' | 'record' | 'param' | 'reserved';
29
20
  };
30
- /** A prop path (`['items', '0', 'title']`) and its source. */
31
21
  export type PropSourceEntry = {
32
22
  prop: string[];
33
23
  source: PropSource;
34
24
  };
35
- /** Told of each leaf of a cell's resolved props, with its source. */
36
25
  export type OnSource = (prop: string[], source: PropSource) => void;
37
- /** Keys under a state that only the agency's tools write (data.md §9.5). */
38
26
  export declare const TOOL_OWNED_KEYS: readonly ["content_index", "ref_index"];
39
- /** A section's fields a person edits on the structure itself (data.md §9.5, `doc_edit_structure`). */
40
27
  export declare const STRUCTURE_FIELDS: readonly ["title", "applicable", "startsPage", "directed", "status"];
41
- /**
42
- * Where an edit of a value goes: the write function and the arguments that come from the source.
43
- * The new value (and, for a page edit, the version seen) is the caller's. `fn: null` says why the
44
- * value can't be edited here; the write functions still decide everything that can.
45
- */
46
28
  export type EditTarget = ({
47
29
  fn: 'doc_edit_content';
48
30
  graphNodeId: string;
@@ -61,59 +43,18 @@ export type EditTarget = ({
61
43
  fn: 'page_edit_data';
62
44
  path: string[];
63
45
  }) & {
64
- /** The branch the edit writes (`p_version_id`, versions.md §4.3); absent on main. */
65
46
  versionId?: string;
66
47
  } | {
67
48
  fn: null;
68
49
  reason: EditRefusal;
69
50
  };
70
- export type EditRefusal =
71
- /** Computed, queried or walked: nothing holds it to edit. */
72
- 'DERIVED'
73
- /** The cell's content is its node's `page_cell_config`, not the page's. */
74
- | 'NODE_CONFIG'
75
- /** A `data.static` literal of a cell whose content is its node's (NODE_CONFIG's case for static data). */
76
- | 'STATIC'
77
- /** The read didn't say which state it saw, so no version check is possible. */
78
- | 'NO_STATE_ID'
79
- /** The value merges more than one system's state, so which one to write is ambiguous. */
80
- | 'MERGED_READS'
81
- /** Not a data state (`<tier>_data`): the document write functions write data states only. */
82
- | 'NOT_DATA_STATE'
83
- /** A tool-owned index (`content_index`, `ref_index`). */
84
- | 'TOOL_OWNED'
85
- /**
86
- * An element of a list the write functions refused: a path whose index names no element
87
- * (`jsonb_set_path`). The host no longer refuses list paths itself: the functions write at a
88
- * path into a list (DF-SCH-9), and their dry run says whether the element exists.
89
- */
90
- | 'LIST_ELEMENT'
91
- /** Read at a release or a channel (or another scope's published version): releases are read-only (versions.md §5.3). */
92
- | 'VERSION_IS_RELEASE';
93
- /** 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';
94
52
  export type EditCell = {
95
53
  id: string;
96
54
  source?: CellSource;
97
55
  };
98
- /**
99
- * The write function an edit of this value goes to (design/data.md §9.5):
100
- * - a node's data state: a section's structure field or `order` to `doc_edit_structure`,
101
- * anything else to `doc_edit_content`, with the state id the viewer saw;
102
- * - a literal in an inline cell, or its own `data.static`, to `page_edit_cell`'s path write, which
103
- * writes the page artifact and the row together;
104
- * - the page's `data.static` to `page_edit_data`'s path write;
105
- * - everything else nowhere, with the reason.
106
- * Paths may run through list indices: the functions write at a path into a list (DF-SCH-9).
107
- */
108
56
  export declare function editTarget(source: PropSource, cell: EditCell, version?: VersionContext): EditTarget;
109
- /** A value at a path, as the nested object a patch is (`['props', 'caption']` → `{ props: { caption } }`). */
110
57
  export declare function patchAt(path: readonly string[], value: unknown): unknown;
111
- /**
112
- * One cell's props as the renderer resolves them (CellView), with each leaf's source and value,
113
- * without rendering: what an assistant reads to plan an edit (docs-forms M3). Null when the cell's
114
- * conditions hide it. The same resolution context CellView builds, from the same runtime; paged
115
- * labels' later pages aren't loaded, so a paged list reads its first page.
116
- */
117
58
  export declare function cellPropSources(runtime: Pick<PageRuntime, 'page' | 'data' | 'declared' | 'cellData'>, cell: ResolvedCell, env?: {
118
59
  params?: Record<string, unknown>;
119
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[];
@@ -6,5 +6,4 @@ export interface ScopeContext {
6
6
  pageId?: string | null;
7
7
  projectId?: string | null;
8
8
  }
9
- /** `null` when the context lacks the id: no scope, so no value and no setter. */
10
9
  export declare function resolveScopeId(kind: ScopeKind, ctx: ScopeContext): ScopeId | null;
@@ -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,7 +13,6 @@ 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;
@@ -27,12 +20,6 @@ export type StateOrigin = {
27
20
  versionId?: string | null;
28
21
  outOfScope?: boolean;
29
22
  };
30
- /**
31
- * Where a label's value came from (INV-DOC-6), so an edit can go back to it (design/data.md §9.5).
32
- * `at` is the path inside the source to the label's value: inside the state's data (a binding's
33
- * `field`, an `@each` element's index), or the label and its path in the page's or cell's static data.
34
- * A label without an origin was read some other way (a query): it isn't editable.
35
- */
36
23
  export type DataOrigin = {
37
24
  kind: 'state';
38
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>;
@@ -1,26 +1,7 @@
1
- /**
2
- * Conditions on pages, sections, questions and content blocks (design/forms.md §3.1).
3
- *
4
- * One shape: `{ all: [{ q: '<question key>', op, value }], not?: boolean }`, operators
5
- * in lower case only. Ported from the PWA's `lib/forms/evaluate-conditional.ts` and
6
- * `lib/forms/normalize-conditional-logic.ts`; the semantics are theirs:
7
- *
8
- * - every clause must hold (AND); `not: true` negates the result;
9
- * - absent or empty conditions show the target;
10
- * - an unknown operator, or an error while evaluating, SHOWS the target. Hiding would
11
- * silently remove a question from a workbook; an extra one is visible and correctable.
12
- *
13
- * The PWA had two stored shapes and mixed operator casing (`equals`, `not_equals`,
14
- * `notEquals`, `is_not_empty`, `greaterThan` …). `normalizeCondition` maps all of them
15
- * to this shape once, at migration and validation time, so the evaluator reads only
16
- * the canonical operators.
17
- */
18
1
  export declare const CONDITION_OPS: readonly ["eq", "ne", "in", "not_in", "gt", "lt", "gte", "lte", "contains", "not_contains", "empty", "not_empty"];
19
2
  export type ConditionOp = (typeof CONDITION_OPS)[number];
20
3
  export interface ConditionClause {
21
- /** The question key the clause reads from the answers. */
22
4
  q: string;
23
- /** A `ConditionOp`; anything else shows the target and is reported. */
24
5
  op: ConditionOp | (string & {});
25
6
  value?: unknown;
26
7
  }
@@ -29,26 +10,8 @@ export interface Condition {
29
10
  not?: boolean;
30
11
  }
31
12
  export declare function isConditionOp(op: unknown): op is ConditionOp;
32
- /**
33
- * True when the condition passes and the target should render.
34
- *
35
- * @param answers Answers keyed by question key, unwrapped (`unwrapAnswerValue`).
36
- * @param onProblem Called for an unknown operator or an evaluation error; the target
37
- * is shown in both cases.
38
- */
39
13
  export declare function evaluateCondition(condition: Condition | null | undefined, answers: Record<string, unknown>, onProblem?: (problem: string) => void): boolean;
40
- /** The canonical operator for a legacy spelling, or null when it is not one we know. */
41
14
  export declare function normalizeOperator(op: unknown): ConditionOp | null;
42
- /**
43
- * Map a stored condition to the one shape.
44
- *
45
- * Accepts the new shape, the PWA's current `{ conditions: [{ questionId, operator, value }],
46
- * not? }`, its legacy `[{ when, operator, is }]`, and any of them as a JSON string (the
47
- * column is jsonb and some seeding wrote it stringified).
48
- *
49
- * `condition: null` means UNGATED, i.e. the target shows: the safe direction for input
50
- * that is absent or unusable. Unusable input and dropped clauses are listed in `problems`.
51
- */
52
15
  export declare function normalizeCondition(legacy: unknown): {
53
16
  condition: Condition | null;
54
17
  problems: string[];
@@ -1,27 +1,13 @@
1
1
  import { type Condition } from './conditions.js';
2
- /**
3
- * A form as the forms runtime reads it (forms-as-pages.md §4.2–§4.3): steps, an overlay on the
4
- * page's flat cells, each holding items (cells) and the questions they ask. Where it comes from
5
- * is an adapter's business: a page's `layout.steps` (`fromPageSteps`) or, until forms are pages
6
- * (SCH M3b), the legacy definition (the host's adapter). Pure: no React, no network.
7
- */
8
2
  export type FormQuestion = {
9
- /** The answer's key: what conditions, progress and the port name. */
10
3
  key: string;
11
4
  label: string;
12
5
  required: boolean;
13
- /** Enter may move on from it (forms-as-pages.md §4.3): a one-line question. */
14
6
  singleLine: boolean;
15
7
  when?: Condition | null;
16
- /** The question node an answer is saved against (answer_save's p_question_node), when the form is a page. */
17
8
  node?: string;
18
- /** How to ask it, from the question node's state: what a cell renders its control from. */
19
9
  definition?: FormQuestionDefinition;
20
10
  };
21
- /**
22
- * A question's definition as its node's state holds it (forms-as-pages.md §4.2): the control's
23
- * type, its options, validation and help. The runtime passes it through to the cell untouched.
24
- */
25
11
  export type FormQuestionDefinition = {
26
12
  type: string;
27
13
  options?: unknown[];
@@ -30,14 +16,12 @@ export type FormQuestionDefinition = {
30
16
  helpText?: string;
31
17
  };
32
18
  export type FormItemKind = 'question' | 'content' | 'document' | 'review' | 'upload' | 'other';
33
- /** One cell of a step: its questions, if any. */
34
19
  export type FormItem = {
35
20
  id: string;
36
21
  kind: FormItemKind;
37
22
  questions: FormQuestion[];
38
23
  when?: Condition | null;
39
24
  };
40
- /** `label`: an authored word for the step shown in place of its derived kind's (advisor review, status); the kind stays derived. */
41
25
  export type FormStep = {
42
26
  id: string;
43
27
  title: string;
@@ -54,50 +38,32 @@ export type FormModel = {
54
38
  title: string;
55
39
  chapters: FormChapter[];
56
40
  steps: FormStep[];
57
- /** On submit: `warn` lists what's missing and submits; `block` refuses until it's answered (owner, Q-F7; default warn). */
58
41
  submitRequired: 'warn' | 'block';
59
- /** Back is offered (the template's `allow_back`, default true). */
60
42
  allowBack: boolean;
61
- /** The form takes a submission (false for a legacy form, which has none); default true. */
62
43
  submittable?: boolean;
63
44
  };
64
- /** A step's kind, derived from its cells (§4.2): for labels and progress. */
65
45
  export type StepKind = 'answer' | 'read' | 'review' | 'upload' | 'submit';
66
- /** Where a submission stands (the `submission` layer's status, schema-g2.md §2.7). */
67
46
  export type SubmissionStatus = 'in_progress' | 'submitted' | 'changes_requested' | 'completed';
68
47
  export type DisplayMode = 'step' | 'question';
69
- /** Steps, cells and questions whose conditions hold for these answers; a step left with nothing visible is skipped. */
70
48
  export declare function visibleSteps(model: FormModel, values: Record<string, unknown>): FormStep[];
71
49
  export declare const questionsOf: (step: FormStep) => FormQuestion[];
72
50
  export declare function stepKind(step: FormStep, isLast: boolean): StepKind;
73
- /** Where a person is: a step, and in question mode one of its questions. */
74
51
  export type Position = {
75
52
  step: string;
76
53
  question?: string;
77
54
  };
78
- /** The places Next and Back move through: a step each, or in question mode each question (a step with none counts once). */
79
55
  export declare function positionsOf(steps: FormStep[], mode: DisplayMode): Position[];
80
- /** A position in these steps: the same, else its step's first, else the first. */
81
56
  export declare function settle(steps: FormStep[], mode: DisplayMode, at: Position | null): Position | null;
82
- /** One move on, or back; null at either end. A move across a step boundary is a step change (it pushes history). */
83
57
  export declare function move(steps: FormStep[], mode: DisplayMode, at: Position, by: 1 | -1): Position | null;
84
- /** The contents click (§4.3): that step, in question mode at its first unanswered question, else its first. */
85
58
  export declare function goTo(steps: FormStep[], mode: DisplayMode, stepId: string, values: Record<string, unknown>): Position | null;
86
- /** A question's place (§4.3 question mode, `?question=`): its step, settled for the mode. Null when no visible step has it. */
87
59
  export declare function goToQuestion(steps: FormStep[], mode: DisplayMode, key: string): Position | null;
88
- /** Enter moves on (§4.3): a step with exactly one visible one-line question, or a one-line question in question mode. */
89
60
  export declare function enterAdvances(step: FormStep, mode: DisplayMode, question?: string): boolean;
90
- /** Required questions not yet answered, in order: in one step, or (no step) in the whole form. */
91
61
  export declare function missing(steps: FormStep[], values: Record<string, unknown>, stepId?: string): FormQuestion[];
92
62
  export type StepProgress = {
93
63
  answered: number;
94
64
  total: number;
95
65
  complete: boolean;
96
66
  };
97
- /**
98
- * Progress (§4.3): overall, required answered of required visible; per step, answered of visible
99
- * questions, complete when all its required ones are answered. A read step counts once visited.
100
- */
101
67
  export declare function progress(steps: FormStep[], values: Record<string, unknown>, visited: ReadonlySet<string>): {
102
68
  answered: number;
103
69
  required: number;
@@ -108,27 +74,17 @@ export declare function progress(steps: FormStep[], values: Record<string, unkno
108
74
  };
109
75
  perStep: Record<string, StepProgress>;
110
76
  };
111
- /** Answers can't change: submitted or completed (Edit answers reopens a submitted form). */
112
77
  export declare const isReadOnlyStatus: (status: SubmissionStatus | null | undefined) => status is "submitted" | "completed";
113
- /** Step mode on desktop, one question at a time on a phone (§4.3). */
114
78
  export declare const defaultMode: (phone: boolean) => DisplayMode;
115
- /**
116
- * Steps from a page's overlay (§4.2): `layout.steps: [{ id, title, chapter?, cell_ids, when? }]`
117
- * and `layout.chapters`, each cell's questions from `questionsOfCell` (the page knows its
118
- * question cells' bindings). Cells the overlay doesn't name aren't in the form.
119
- */
120
79
  export declare function fromPageSteps(page: {
121
80
  name?: string | null;
122
81
  layout?: Record<string, unknown> | null;
123
82
  }, itemOf: (cellId: string) => FormItem | null): FormModel;
124
- /** A deep link (§4.3, the URL contract `?mode=&page=&section=&question=`): `section` a step id, `page` a chapter id, `question` a question key. */
125
83
  export type FormLink = {
126
84
  mode?: 'question';
127
85
  page?: string;
128
86
  section?: string;
129
87
  question?: string;
130
88
  };
131
- /** Where a link lands: the step it names (and question), else its chapter's first step, else the first. */
132
89
  export declare function positionFromLink(steps: FormStep[], mode: DisplayMode, link: FormLink): Position | null;
133
- /** The link to a position, as an assistant reply carries it. */
134
90
  export declare function linkTo(steps: FormStep[], mode: DisplayMode, at: Position): FormLink;
@@ -1,11 +1,4 @@
1
- /**
2
- * How the forms runtime saves (joint-releases.md §2.4): an injected port, so the runtime never
3
- * names a table or a function. The legacy adapter (the host's, over form_answer_save) implements
4
- * it in G2; answer_save, form_submit, form_visit and form_reopen (SCH M3b; schema-g2.md §2.7) in
5
- * G3, with no renderer release. A refusal is a code, never a throw, so it's said in words like an edit's.
6
- */
7
1
  import type { FileAnswer } from '@peripheries/runtime';
8
- /** The codes a port answers with (schema-g2.md §2.7), and NETWORK when the call didn't arrive. */
9
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 & {});
10
3
  export type FormsResult<T extends object = object> = ({
11
4
  ok: true;
@@ -15,11 +8,9 @@ export type FormsResult<T extends object = object> = ({
15
8
  message?: string;
16
9
  detail?: unknown;
17
10
  };
18
- /** A file to upload for an answer: any Blob with a name (a File in the browser). */
19
11
  export type FileToUpload = Blob & {
20
12
  readonly name: string;
21
13
  };
22
- /** One answer to save: its key, the question node when the form is a page, and the state it replaces. */
23
14
  export type AnswerToSave = {
24
15
  key: string;
25
16
  node?: string;
@@ -27,31 +18,19 @@ export type AnswerToSave = {
27
18
  expectedStateId?: string | null;
28
19
  };
29
20
  export interface FormsPort {
30
- /** Save one answer; the state it wrote is what the next save of that key expects (CONFLICT otherwise). */
31
21
  save(answer: AnswerToSave): Promise<FormsResult<{
32
22
  stateId?: string | null;
33
23
  }>>;
34
- /** Submit: `missing` is what the runtime found unanswered (recorded under `warn`; `block` refuses FORM_INCOMPLETE). */
35
24
  submit(input: {
36
25
  missing: string[];
37
26
  }): Promise<FormsResult<{
38
27
  status: 'submitted';
39
28
  missing: string[];
40
29
  }>>;
41
- /**
42
- * Edit answers (forms-as-pages.md §4.3): a submitted form back to `in_progress`, recorded in the
43
- * submission. Refused once staff have completed it (FORM_COMPLETED).
44
- */
45
30
  reopen(): Promise<FormsResult<{
46
31
  status: 'in_progress';
47
32
  }>>;
48
- /** A step was seen (`submission.visited_steps`): read steps count once visited. A repeat is a no-op. */
49
33
  visit(stepId: string): Promise<FormsResult>;
50
- /**
51
- * Upload a file for a file question, as the viewer: the adapter stores it where answer_save
52
- * accepts it and returns the answer to save (`{ v: 1, file }`); saving it is `save`'s. Absent
53
- * where the host takes no files.
54
- */
55
34
  upload?(input: {
56
35
  key: string;
57
36
  node?: string;
@@ -62,7 +41,6 @@ export interface FormsPort {
62
41
  file: FileAnswer;
63
42
  };
64
43
  }>>;
65
- /** A short-lived URL to open a saved file answer, as the viewer (storage decides who may). */
66
44
  openFile?(file: FileAnswer): Promise<FormsResult<{
67
45
  url: string;
68
46
  }>>;