@peripheries/renderer 0.23.1 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,13 +6,13 @@ the same in each.
6
6
 
7
7
  | Entry | Holds |
8
8
  |---|---|
9
- | `@peripheries/renderer/core` | Framework-free: cells and thin-ref hydration, references and conditions, the data context, walks and state names, cell props, layout, document structure, bundle refs and resolution, the shared store, `loadPageData(page, source)`, validation, `DIAGNOSTICS` and `PAGE_RULES` |
9
+ | `@peripheries/renderer/core` | Framework-free: cells and thin-ref hydration, references and conditions, the data context, walks and state names (`layerName`, the layer catalog `LAYER_ROLES`), cell props, layout, document structure, bundle refs and resolution, the shared store, `loadPageData(page, source)`, validation, `DIAGNOSTICS` and `PAGE_RULES` |
10
10
  | `@peripheries/renderer/catalog` | `checkCatalog`: what a component repo runs on the knowledge it emits. The only entry with a JSON Schema validator (ajv) |
11
11
  | `@peripheries/renderer/react` | `PageRenderer`, `CellView`, `StructureView`, the cell states, `useContainerSize`, `useFormsRuntime` and its `FormSlotProps` and `FormAnswer` |
12
12
  | `@peripheries/renderer/runtime` | What a page boots with: the import map and boot script, the shims, `installRuntime`, the store bundles import |
13
13
  | `@peripheries/renderer/theme` | The org theme pipeline: `parseTheme` (version 1 or 2 in, version 2 out, with diagnostics), `themeTokens` (semantic overrides derived in OKLCH), `themeCss` (the `theme` layer), `checkTheme` (WCAG contrast) |
14
14
  | `@peripheries/renderer/print` | The print pipeline, framework-free: `collectBlocks` (the page map), `paginate`, `buildPrintLayout` (the packer's decision as CSS), `buildPageStylesheet` (`@page` geometry and margin boxes), running headers, `@printPolicy` parsing, print lint, `resolveDocumentProfile`, region bindings, map staleness, and the `layout.structure[].print` writer |
15
- | `@peripheries/renderer/forms` | The forms runtime, framework-free: the steps overlay and its model, conditions, modes, navigation, progress, deep links, and the persistence port (`FormsPort`); the React hook is `useFormsRuntime` in `/react` |
15
+ | `@peripheries/renderer/forms` | The forms runtime, framework-free: the steps overlay and its model, conditions, modes, navigation, progress, deep links, and the persistence port (`FormsPort`), and the form-section contract's type (`FormSection`, `FormContentBlock`); the React hook is `useFormsRuntime` in `/react` |
16
16
  | `@peripheries/renderer/testing` | The golden pages, synthetic fixtures, and sources that serve them |
17
17
  | `@peripheries/renderer/styles.css` | Page and cell containers, the responsive buckets, placeholders and notices, in the `renderer` layer |
18
18
 
@@ -77,6 +77,22 @@ bundle's `ThemeProvider` export.
77
77
 
78
78
  ## Versions
79
79
 
80
+ - **0.24.0** (2026-10-20): one renderer batch (CX).
81
+ - **`layerName(system)` and `LAYER_ROLES`** in `/core`: a system's state name (its layer's role,
82
+ else a registered layer's own type, `question`, `answer`, …) from the layer catalog, which is
83
+ generated from `public.system_layer` (`npm run gen:layers`; CI checks it is current). A host
84
+ and BEA's preview resolve a page's state names alike. An unregistered type has no name.
85
+ - **`FormSection` and `FormContentBlock`** in `/forms`: a form section cell's `props.section`,
86
+ contract v1 (`contracts/form-section.schema.json`): the section node's `id`, its authored
87
+ `sectionId`, `title`, `description?`, `sectionType?`, its `questions` (`{ key, label, required,
88
+ definition }`, the definition the form-definition contract's question or null) and its
89
+ `content` blocks (the form-definition contract's content block). Static: visibility, answers
90
+ and totals stay runtime (`forms.*`, `FormAnswer`, unchanged). v1 is the target shape: the
91
+ component engine doesn't emit `props.section` yet; the cutover is in the stack's
92
+ `contracts/README.md`.
93
+ - **`FormQuestionDefinition`'s** `options`, `validation`, `description` and `helpText` may be
94
+ null, as the form-definition contract's question has them.
95
+
80
96
  - **0.23.1** (2026-10-15): the published files carry no comments and no
81
97
  source maps (declarations included); this README is the documentation.
82
98
  No API change.
package/dist/core.js CHANGED
@@ -90,6 +90,22 @@ function buildDataContext(input) {
90
90
  }
91
91
  return ctx;
92
92
  }
93
+ var LAYER_ROLES = {
94
+ "answer": null,
95
+ "appraisal-system": "appraisal",
96
+ "data-system": "data",
97
+ "edits": null,
98
+ "model-system": "model",
99
+ "organisation": null,
100
+ "process-system": "process",
101
+ "question": null,
102
+ "submission": null
103
+ };
104
+ function layerName(s) {
105
+ if (s.system_layer) return s.system_layer.role ?? s.system_type ?? null;
106
+ if (!s.system_type || !Object.hasOwn(LAYER_ROLES, s.system_type)) return null;
107
+ return LAYER_ROLES[s.system_type] ?? s.system_type;
108
+ }
93
109
  async function resolveSystems(source, page) {
94
110
  const systems = !page.process_id ? {} : source.graphSystems ? systemsFromGraphs(await source.graphSystems(page.process_id)) : systemsFromProcess(await source.processSystems?.(page.process_id));
95
111
  if (!systems.eng_data) {
@@ -1116,4 +1132,4 @@ function manifestPageFrom(graphNodeId, data) {
1116
1132
  }
1117
1133
  };
1118
1134
  }
1119
- export { CONTENT_FIELDS, CORE_SPECIFIER, DIAGNOSTICS, EACH, EACH_DEFAULT_AS, HYDRATED_CELL_FIELDS, LAYOUT_TYPES, MAIN, PAGE_DOCUMENT, PAGE_RULES, PAGING_VARIABLES, PUBLIC, RENDER_FUNCTIONS, RENDER_FUNCTIONS_AHEAD, RESERVED_LABELS, RESPONSIVE_BUCKETS, SECTION_KINDS, STORE_FIELDS, STORE_SCOPES, STRUCTURE_FIELDS, TOOL_OWNED_KEYS, UnsafeDocumentError, VARIABLE_NAMESPACES, WALK_DIRECTIONS, _clearBundleCache, actionBindingKey, actionProblems, actionReferences, assembleCellProps, attachSelectionSetters, attachViewStateSetters, buildDataContext, bundleScope, cellAttributes, cellContext, cellPlacementStyle, cellPropSources, cellResolutionContext, clearScope, collectDeclarations, collectDescriptors, collectScopeIds, collectStatic, createStackStore, declaredActions, deriveElementReferences, deriveSectionNumbering, deriveSectionReferences, descriptorShape, eachFormProblems, editTarget, hasRef, isComponentExport, isEach, loadBundle, loadBundles, loadBundlesSettled, loadPageData, loadScope, manifestPageFrom, mergeSectionReferences, mergeStates, nearestNames, needsWalk, nodePrintStyle, normalizeActionDeclaration, normalizeCell, normalizeRef, normalizeStructure, numberingFor, orderByVariable, pageBundleRefs, pageBundles, pageContainerStyle, pageContext, pageRuntimeFromValues, pageScopeKey, pageVariables, passesConditions, patchAt, prepareDocument, projectCellActions, projectCellData, projectLive, projectModule, projectScopeKey, projectSelections, projectViewState, queryKey, readField, readWalk, refKey, referencedLabels, referencesFor, resolveAction, resolveCell, resolveComponent, resolveDataSystem, resolveDeclarations, resolveDescriptorVariables, resolveReferences, resolveScopeId, resolveSystems, resolveWalkStart, rootCells, runtimeReady, saveScope, sectionAnchor, selectionIssues, selectionShape, settled, shallowEqualBundle, shapeAt, stateNames, stateValue, structureIssues, systemsFromGraphs, systemsFromProcess, tableOfContents, usesStructureLayout, validateCell, validateDescriptor, validateManifest, validatePage, variableLabels, variableReferences, walkKey, walkRequest };
1135
+ export { CONTENT_FIELDS, CORE_SPECIFIER, DIAGNOSTICS, EACH, EACH_DEFAULT_AS, HYDRATED_CELL_FIELDS, LAYER_ROLES, LAYOUT_TYPES, MAIN, PAGE_DOCUMENT, PAGE_RULES, PAGING_VARIABLES, PUBLIC, RENDER_FUNCTIONS, RENDER_FUNCTIONS_AHEAD, RESERVED_LABELS, RESPONSIVE_BUCKETS, SECTION_KINDS, STORE_FIELDS, STORE_SCOPES, STRUCTURE_FIELDS, TOOL_OWNED_KEYS, UnsafeDocumentError, VARIABLE_NAMESPACES, WALK_DIRECTIONS, _clearBundleCache, actionBindingKey, actionProblems, actionReferences, assembleCellProps, attachSelectionSetters, attachViewStateSetters, buildDataContext, bundleScope, cellAttributes, cellContext, cellPlacementStyle, cellPropSources, cellResolutionContext, clearScope, collectDeclarations, collectDescriptors, collectScopeIds, collectStatic, createStackStore, declaredActions, deriveElementReferences, deriveSectionNumbering, deriveSectionReferences, descriptorShape, eachFormProblems, editTarget, hasRef, isComponentExport, isEach, layerName, loadBundle, loadBundles, loadBundlesSettled, loadPageData, loadScope, manifestPageFrom, mergeSectionReferences, mergeStates, nearestNames, needsWalk, nodePrintStyle, normalizeActionDeclaration, normalizeCell, normalizeRef, normalizeStructure, numberingFor, orderByVariable, pageBundleRefs, pageBundles, pageContainerStyle, pageContext, pageRuntimeFromValues, pageScopeKey, pageVariables, passesConditions, patchAt, prepareDocument, projectCellActions, projectCellData, projectLive, projectModule, projectScopeKey, projectSelections, projectViewState, queryKey, readField, readWalk, refKey, referencedLabels, referencesFor, resolveAction, resolveCell, resolveComponent, resolveDataSystem, resolveDeclarations, resolveDescriptorVariables, resolveReferences, resolveScopeId, resolveSystems, resolveWalkStart, rootCells, runtimeReady, saveScope, sectionAnchor, selectionIssues, selectionShape, settled, shallowEqualBundle, shapeAt, stateNames, stateValue, structureIssues, systemsFromGraphs, systemsFromProcess, tableOfContents, usesStructureLayout, validateCell, validateDescriptor, validateManifest, validatePage, variableLabels, variableReferences, walkKey, walkRequest };
package/dist/react.js CHANGED
@@ -662,7 +662,7 @@ function useFormsRuntime(o) {
662
662
  const steps = useMemo(() => visibleSteps(o.model, values), [o.model, values]);
663
663
  const [at, setAt] = useState(() => positionFromLink(visibleSteps(o.model, answeredOf(o.initial)), mode, o.link ?? {}));
664
664
  const here = settle(steps, mode, at);
665
- const readOnly = isReadOnlyStatus(status);
665
+ const readOnly = o.readOnly === true || isReadOnlyStatus(status);
666
666
  const opts = useRef(o);
667
667
  opts.current = o;
668
668
  const expected = useRef(new Map(Object.entries(o.initial).map(([k, a]) => [k, a.stateId ?? null])));
@@ -713,7 +713,7 @@ function useFormsRuntime(o) {
713
713
  return chain.current;
714
714
  }, []);
715
715
  const change = useCallback((key, value) => {
716
- if (isReadOnlyStatus(status)) return;
716
+ if (readOnly) return;
717
717
  setValues((v) => ({
718
718
  ...v,
719
719
  [key]: value
@@ -721,7 +721,7 @@ function useFormsRuntime(o) {
721
721
  pending.current.set(key, value);
722
722
  if (timer.current) clearTimeout(timer.current);
723
723
  timer.current = setTimeout(() => void flush(), FORM_SAVE_DEBOUNCE_MS);
724
- }, [flush, status]);
724
+ }, [flush, readOnly]);
725
725
  useEffect(() => {
726
726
  const onLeave = () => void flush();
727
727
  window.addEventListener("pagehide", onLeave);
@@ -841,7 +841,7 @@ function useFormsRuntime(o) {
841
841
  refusal: refusals[q.key] ?? null,
842
842
  inputId: answerInputId(q.key),
843
843
  ...port.upload ? { upload: async (file) => {
844
- if (isReadOnlyStatus(status)) return {
844
+ if (readOnly) return {
845
845
  ok: false,
846
846
  refusal: words("FORM_NOT_OPEN")
847
847
  };
@@ -919,7 +919,7 @@ function useFormsRuntime(o) {
919
919
  run: () => void runSubmit(),
920
920
  blocked: o.model.submitRequired === "block" && allMissing.length > 0
921
921
  } : null,
922
- reopen: status === "submitted" && o.model.submittable !== false ? {
922
+ reopen: status === "submitted" && !o.readOnly && o.model.submittable !== false ? {
923
923
  label: "Edit answers",
924
924
  run: () => void runReopen()
925
925
  } : null,
@@ -1,6 +1,7 @@
1
1
  export { CONTENT_FIELDS, hasRef, HYDRATED_CELL_FIELDS, normalizeCell, resolveCell, rootCells, STORE_FIELDS, type CellSource, type ResolvedCell } from './cells.js';
2
2
  export { buildDataContext, collectDeclarations, collectDescriptors, collectStatic, readField, resolveDeclarations, type ResolvedDeclaration, type StateRead } from './data-context.js';
3
3
  export { mergeStates, needsWalk, readWalk, referencedLabels, RESERVED_LABELS, resolveWalkStart, stateNames, stateValue, systemsFromGraphs, systemsFromProcess, walkKey, walkRequest, type Diagnostic, type GraphSystem, type ProcessSystems, type RawWalk, type WalkBinding, type WalkRequest, type WalkStart, } from './graph.js';
4
+ export { LAYER_ROLES, layerName, type LayerType } from './layers.js';
4
5
  export { loadPageData, resolveDataSystem, resolveSystems, type CellData, type CellWalk, type GraphSource, type NodeRecordRow, type PageRuntime, type PageScope, type QueryPage, type ReadContext, type StateRow } from './load-page.js';
5
6
  export { descriptorShape, orderByVariable, PAGING_VARIABLES, pageVariables, prepareDocument, queryKey, RENDER_FUNCTIONS, RENDER_FUNCTIONS_AHEAD, resolveDescriptorVariables, selectionShape, shapeAt, UnsafeDocumentError, validateDescriptor, VARIABLE_NAMESPACES, variableLabels, variableReferences, type PreparedDocument, type ResolvedVariables, type SelectionShape, } from './query.js';
6
7
  export { selectionIssues } from './selected.js';
@@ -0,0 +1,8 @@
1
+ import { LAYER_ROLES, type LayerType } from './layers.gen.js';
2
+ export { LAYER_ROLES, type LayerType };
3
+ export declare function layerName(s: {
4
+ system_type: string | null;
5
+ system_layer?: {
6
+ role: string | null;
7
+ } | null;
8
+ }): string | null;
@@ -0,0 +1,12 @@
1
+ export declare const LAYER_ROLES: {
2
+ readonly answer: null;
3
+ readonly "appraisal-system": "appraisal";
4
+ readonly "data-system": "data";
5
+ readonly edits: null;
6
+ readonly "model-system": "model";
7
+ readonly organisation: null;
8
+ readonly "process-system": "process";
9
+ readonly question: null;
10
+ readonly submission: null;
11
+ };
12
+ export type LayerType = keyof typeof LAYER_ROLES;
@@ -1,3 +1,4 @@
1
1
  export { CONDITION_OPS, evaluateCondition, isConditionOp, normalizeCondition, normalizeOperator, type Condition, type ConditionClause, type ConditionOp } from './conditions.js';
2
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
3
  export type { AnswerToSave, FileToUpload, FormsPort, FormsRefusal, FormsResult } from './port.js';
4
+ export type { FormContentBlock, FormSection } from './section.js';
@@ -10,10 +10,10 @@ export type FormQuestion = {
10
10
  };
11
11
  export type FormQuestionDefinition = {
12
12
  type: string;
13
- options?: unknown[];
14
- validation?: Record<string, unknown>;
15
- description?: string;
16
- helpText?: string;
13
+ options?: unknown[] | null;
14
+ validation?: Record<string, unknown> | null;
15
+ description?: string | null;
16
+ helpText?: string | null;
17
17
  };
18
18
  export type FormItemKind = 'question' | 'content' | 'document' | 'review' | 'upload' | 'other';
19
19
  export type FormItem = {
@@ -0,0 +1,22 @@
1
+ import type { Condition } from './conditions.js';
2
+ import type { FormQuestionDefinition } from './model.js';
3
+ export type FormContentBlock = {
4
+ id: string;
5
+ type: string;
6
+ when?: Condition | null;
7
+ [prop: string]: unknown;
8
+ };
9
+ export type FormSection = {
10
+ id: string;
11
+ sectionId: string;
12
+ title: string;
13
+ description?: string;
14
+ sectionType?: string;
15
+ questions: Array<{
16
+ key: string;
17
+ label: string;
18
+ required: boolean;
19
+ definition: FormQuestionDefinition | null;
20
+ }>;
21
+ content: FormContentBlock[];
22
+ };
@@ -114,6 +114,7 @@ export type FormsRuntimeOptions = {
114
114
  stateId?: string | null;
115
115
  }>;
116
116
  status: SubmissionStatus | null;
117
+ readOnly?: boolean;
117
118
  visited?: string[];
118
119
  link?: FormLink;
119
120
  phone?: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peripheries/renderer",
3
- "version": "0.23.1",
3
+ "version": "0.24.0",
4
4
  "description": "The one renderer for pages of federated component bundles: a framework-free core, a React renderer, the runtime a page boots with, and golden pages for testing.",
5
5
  "type": "module",
6
6
  "sideEffects": [