Checklist — cdx_checklist
cdx_checklist is an agnostic, composable checklist editor / runner / viewer with JSON-in / JSON-out semantics. It composes vyuh_cdx_ui, cdx_field_formatting, and Vyuh form/editor packages. Templates are authored in the editor, executed by the runner (with capture data + approvals), and re-rendered by the viewer for read-only history.
import 'package:cdx_checklist/cdx_checklist.dart';This page is a high-level overview — see the package source for the full API.
Top-level widgets
| Widget | Use |
|---|---|
ChecklistEditor | Author / edit a ChecklistModel (sets, instructions, capture variants) |
ChecklistRunner | Execute a checklist — operator captures responses, optional approvals |
ChecklistViewer | Read-only render — history, audits, print preview |
ChecklistEditor(
controller: ChecklistEditorController(
model: existingTemplate, // ChecklistModel
onChanged: (next) => store.update(next),
),
registry: appChecklistRegistry,
theme: ChecklistTheme.of(context),
)
ChecklistRunner(
controller: ChecklistRunnerController(
template: template,
usage: existingUsage, // ChecklistUsage — execution state
onEvent: (event) => store.dispatch(event),
),
)
ChecklistViewer(
controller: ChecklistViewerController(
snapshot: SetSnapshot.fromUsage(usage),
),
)Model
A ChecklistModel is a serializable tree. The shape:
DataCapture variants (sealed)
Each instruction owns one of these capture types:
| Variant | Use |
|---|---|
YesNoCapture | Binary check — pass / fail / N/A |
ToggleCapture | Multi-state toggle (e.g. "before / during / after") |
InlineFormCapture | Inline form fields rendered directly in the runner |
FormTemplateCapture | Reference to a separate form template |
UnknownCapture | Forward-compatibility placeholder for new server-side types the client doesn't yet know |
Capture serialization goes through DataCaptureCodec.
Approval workflow
ApprovalConfig describes a per-set approval workflow (topology + approver groups + rework policy). ApprovalEvent records each step; ApprovalStatus tracks the current state.
| Type | Purpose |
|---|---|
ApprovalTopology | singleApprover / sequentialChain / parallelAny etc. |
ApproverGroup | A named group of users eligible to approve |
ApprovalAction | submit / approve / reject / requestRevision |
RejectionReason | Structured reason captured on rejection |
ReworkPolicy | What happens on revision (clear set state, etc.) |
Controllers
| Controller | Owns |
|---|---|
ChecklistEditorController | The editing model + dirty state + undo/redo |
ChecklistRunnerController | The runtime usage + capture state + attachment requests |
ChecklistViewerController | Read-only snapshot navigation |
Each controller emits typed events from the ChecklistEvent hierarchy (lifecycle / approval / response events) so the host can persist changes server-side.
Registry
ChecklistRegistry lets the host register custom layout descriptors, icon overrides, and theme colors per app:
final registry = ChecklistRegistry()
..registerEditorLayout(ColumnarEditorLayout())
..registerRunnerLayout(ThreePaneRunnerLayout())
..registerViewerLayout(PrintPreviewViewerLayout())
..icons = ChecklistIcons.fluent()
..colors = ChecklistColors.fromCdx(context);
ChecklistRegistryScope(
registry: registry,
child: const ChecklistEditor(...),
)Built-in layouts include:
ColumnarEditorLayout— standard editorSinglePaneRunnerLayout/ThreePaneRunnerLayout— runner shapesPrintPreviewViewerLayout— print-friendly viewer
Theme
ChecklistTheme carries colors, density, and icon registry. Bridge it to the CDX color palette:
ChecklistTheme(
colors: ChecklistColors.fromCdx(context), // pulls success / warning / etc. from CdxConfig
density: ChecklistDensity.regular, // regular / compact
icons: ChecklistIcons.fluent(),
)Validation
final report = ChecklistValidator.validate(model);
for (final issue in report.issues) {
print('${issue.severity}: ${issue.message} at ${issue.path}');
}ValidationReport carries ValidationIssues with severity (error / warning) and a path to the offending node.
JSON round-trip
Every model class implements toJson / fromJson and round-trips losslessly:
final json = model.toJson();
final restored = ChecklistModel.fromJson(json);
assert(restored == model);