AppSpring Docs

SpringML elements

The SpringML elements, their props, helpers, handles and refusals, as JSON generated from ELEMENTS (@canonify/spring-schema).

{
 "name": "Spring UI",
 "version": "3.4",
 "counts": {
  "template": 2,
  "component": 33,
  "part": 22,
  "data": 5,
  "total": 62
 },
 "elements": {
  "Page": {
   "kind": "template",
   "summary": "A screen. Data elements first, then content; Action children are header verbs.",
   "parents": [],
   "children": [
    "Query",
    "Record",
    "Aggregate",
    "State",
    "Section",
    "Split",
    "Columns",
    "Grid",
    "Tabs",
    "Toolbar",
    "Value",
    "Text",
    "Badge",
    "Callout",
    "Stat",
    "Ratio",
    "Meter",
    "Chart",
    "Facts",
    "Breakdown",
    "History",
    "Lifecycle",
    "Table",
    "List",
    "Board",
    "Matrix",
    "Timeline",
    "DayGrid",
    "Filters",
    "Search",
    "Control",
    "PeriodNav",
    "Files",
    "Compare",
    "Link",
    "Form",
    "Action",
    "Empty"
   ],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "title",
     "type": "text|element",
     "required": true,
     "meaning": "the page title; text, an expression or a record (its title)",
     "elements": [
      "Text",
      "Value"
     ]
    },
    {
     "name": "subtitle",
     "type": "text|element",
     "required": false,
     "meaning": "the author's line under the title (e.g. the order of the queue)",
     "elements": [
      "Text",
      "Value"
     ]
    },
    {
     "name": "lead",
     "type": "ref:Query|list:ref:Query",
     "required": false,
     "meaning": "the collection(s) that drive the header summary and the nav badge; required when the page has more than one Query; a list sums the attention of each (\"2 over · 3 unassigned\"). The count is in the type's noun (\"23 events\"), or, when the lead's `where` (or its active Preset) keeps only rows holding a named condition that names a count (both `label` and `labelOne`), in that noun (`where={i => i.is_overdue}` with label \"overdue instalments\" → \"14 overdue instalments\", `labelOne` for 1); a condition with a `label` alone (\"Live\") is a tag and leaves the type's noun; a lead whose `where` holds two such conditions is refused (`lead_noun_ambiguous`): declare one condition that is both, with the noun the count reads in; a lead whose `where` keeps rows of a condition that names no count compiles with a warning (`lead_noun_missing`) — declare its `label` and `labelOne` (\"overdue instalments\" / \"overdue instalment\"), or the header counts those rows in the type's noun as if they were all of them"
    },
    {
     "name": "params",
     "type": "object",
     "required": false,
     "meaning": "the view's parameters and their types: {event: \"event\"}; param() reads them"
    },
    {
     "name": "audience",
     "type": "list:group",
     "required": false,
     "meaning": "groups that may open this view (checked against the org's groups); others do not see it in nav or links (reads stay policy-checked)"
    },
    {
     "name": "navLabel",
     "type": "text",
     "required": false,
     "meaning": "the page's name in the app's nav, breadcrumb and Home (literal text); default: the title when it is text, else the view name's last part (`Sales.dashboard` → \"Dashboard\"). A reader who sees two nav entries with the same name sees each followed by its audience (\"Dashboard · Sales\"), else its page name"
    },
    {
     "name": "icon",
     "type": "text",
     "required": false,
     "meaning": "the page's glyph in the app's nav (literal text): a kebab-case Lucide name from the platform's pinned set (lucide.dev/icons), e.g. \"banknote\". Default, by what the page is: a RecordPage \"file-text\"; else the first the page holds of Board \"kanban\", Timeline \"chart-gantt\", DayGrid \"calendar-days\", Matrix \"calendar-range\", Form \"square-pen\", Compare \"file-diff\", Files \"paperclip\", Chart \"chart-column\", Table or List \"list\"; else \"layout-dashboard\". Give each nav page its own"
    }
   ]
  },
  "RecordPage": {
   "kind": "template",
   "summary": "A record's screen. Reads param(\"id\"); the record is in scope as `record`; Action children are record header verbs.",
   "parents": [],
   "children": [
    "Query",
    "Record",
    "Aggregate",
    "State",
    "Meta",
    "Section",
    "Split",
    "Columns",
    "Grid",
    "Tabs",
    "Toolbar",
    "Value",
    "Text",
    "Badge",
    "Callout",
    "Stat",
    "Ratio",
    "Meter",
    "Chart",
    "Facts",
    "Breakdown",
    "History",
    "Lifecycle",
    "Table",
    "List",
    "Board",
    "Matrix",
    "Timeline",
    "DayGrid",
    "Filters",
    "Search",
    "Control",
    "PeriodNav",
    "Files",
    "Compare",
    "Link",
    "Form",
    "Action",
    "Empty"
   ],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "type",
     "type": "name:type",
     "required": true,
     "meaning": "the record's type"
    },
    {
     "name": "subtitle",
     "type": "text|element",
     "required": false,
     "meaning": "",
     "elements": [
      "Text",
      "Value"
     ]
    },
    {
     "name": "lead",
     "type": "ref:Query",
     "required": false,
     "meaning": ""
    },
    {
     "name": "audience",
     "type": "list:group",
     "required": false,
     "meaning": ""
    },
    {
     "name": "icon",
     "type": "text",
     "required": false,
     "meaning": "the page's glyph in the app's nav (literal text): a kebab-case Lucide name from the platform's pinned set (lucide.dev/icons), e.g. \"banknote\". Default, by what the page is: a RecordPage \"file-text\"; else the first the page holds of Board \"kanban\", Timeline \"chart-gantt\", DayGrid \"calendar-days\", Matrix \"calendar-range\", Form \"square-pen\", Compare \"file-diff\", Files \"paperclip\", Chart \"chart-column\", Table or List \"list\"; else \"layout-dashboard\". Give each nav page its own"
    }
   ]
  },
  "Query": {
   "kind": "data",
   "summary": "The collection: a declared slice of one type plus the reader's working state (preset, facets, search, sort, page, selection). Served by one server batch.",
   "parents": [
    "Page",
    "RecordPage",
    "Section"
   ],
   "children": [
    "Preset",
    "Flag"
   ],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {
    "Section": {
     "requiresAncestor": [
      "Expand"
     ]
    }
   },
   "props": [
    {
     "name": "id",
     "type": "id",
     "required": true,
     "meaning": "the name in expressions; may not shadow a helper or scope name"
    },
    {
     "name": "type",
     "type": "name:type",
     "required": true,
     "meaning": ""
    },
    {
     "name": "where",
     "type": "predicate",
     "required": false,
     "meaning": "thin narrowing (§B6.1)"
    },
    {
     "name": "sort",
     "type": "field|list:field",
     "required": false,
     "meaning": "\"due_on\", \"-version\" or a list; own or 1-hop fields; a link sorts by its target's title; an enum by its declared values; a named condition sorts true first with \"-\" (\"-is_full\"); blanks always last"
    },
    {
     "name": "page",
     "type": "number",
     "required": false,
     "meaning": "rows per page (≤ 200); 0 = unpaged (≤ 500). A Query a Timeline, DayGrid, Span or Matrix draws takes no page: those have no pager and read it whole over what they show (≤ 500 rows, then \"Showing 500 of N\")",
     "default": 25
    },
    {
     "name": "search",
     "type": "list:field|boolean",
     "required": false,
     "meaning": "own or 1-hop text fields; default the type's searchable; false turns Search off"
    },
    {
     "name": "facets",
     "type": "list:field",
     "required": false,
     "meaning": "≤ 3 enum, set<enum> or link fields shown as facet chips"
    },
    {
     "name": "current",
     "type": "predicate",
     "required": false,
     "meaning": "the first row in sort order that matches and carries no critical condition is the current (\"→ Next\") row"
    },
    {
     "name": "nameBy",
     "type": "field",
     "required": false,
     "meaning": "the field that names a row in the queue header (\"late: 07:15 SR-14\"), e.g. the vehicle; default the title, or the eyebrow when the title is longer than 24 characters"
    }
   ]
  },
  "Preset": {
   "kind": "part",
   "summary": "A saved view of the collection; Filters shows it as a chip with its live count.",
   "parents": [
    "Query"
   ],
   "children": [],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "id",
     "type": "id",
     "required": true,
     "meaning": ""
    },
    {
     "name": "label",
     "type": "text",
     "required": true,
     "meaning": ""
    },
    {
     "name": "where",
     "type": "predicate",
     "required": false,
     "meaning": "no where = all rows"
    },
    {
     "name": "default",
     "type": "boolean",
     "required": false,
     "meaning": "at most one; none = the first Preset",
     "default": false
    },
    {
     "name": "short",
     "type": "text",
     "required": false,
     "meaning": "the chip label at phone width (\"Due 14 d\"); a chip never clips its label"
    },
    {
     "name": "verbs",
     "type": "enum",
     "required": false,
     "meaning": "the collection's verbs mode while this preset is active (\"Ready to issue\" → job, \"Overdue\" → flag)",
     "enum": [
      "flag",
      "job",
      "menu"
     ]
    }
   ]
  },
  "Flag": {
   "kind": "part",
   "summary": "Marks rows that need attention, from a named condition of the row type.",
   "parents": [
    "Query"
   ],
   "children": [],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "condition",
     "type": "name:condition",
     "required": true,
     "meaning": "a named condition (Part A PA-3); meaning, level, on, amount and label come from the model"
    }
   ]
  },
  "Record": {
   "kind": "data",
   "summary": "One record by key.",
   "parents": [
    "Page",
    "RecordPage"
   ],
   "children": [],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "id",
     "type": "id",
     "required": true,
     "meaning": ""
    },
    {
     "name": "type",
     "type": "name:type",
     "required": true,
     "meaning": ""
    },
    {
     "name": "key",
     "type": "expr",
     "required": true,
     "meaning": "the record's key: param(\"trip\"), another Record's link, or a date for a per-day type whose ids are dates; a type with prefixed ids (\"day_…\") is read by its date field with a Query and a State auto=\"single\" (a date key is refused)"
    }
   ]
  },
  "Aggregate": {
   "kind": "data",
   "summary": "One grouped read, keyed; read with `.at()`.",
   "parents": [
    "Page",
    "RecordPage"
   ],
   "children": [],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "id",
     "type": "id",
     "required": true,
     "meaning": ""
    },
    {
     "name": "type",
     "type": "name:type",
     "required": false,
     "meaning": "the type to aggregate; or use `of`"
    },
    {
     "name": "of",
     "type": "ref:Query",
     "required": false,
     "meaning": "inherit the Query's type and the rows it reads: its base where (incl. bound States) and the window the components drawing it show (a Matrix's columns, a Timeline's or DayGrid's range, a State's weekdays), never its page, preset or search; may only narrow — so a Stat of it agrees with the Matrix, Timeline or DayGrid that draws the Query"
    },
    {
     "name": "op",
     "type": "enum",
     "required": true,
     "meaning": "",
     "enum": [
      "count",
      "sum",
      "min",
      "max",
      "avg",
      "list"
     ]
    },
    {
     "name": "property",
     "type": "field",
     "required": false,
     "meaning": "the measured field (sum/min/max/avg); for list: the link whose target records are listed — without it the aggregated rows themselves are listed (they are the popover records)"
    },
    {
     "name": "by",
     "type": "field|list:field",
     "required": false,
     "meaning": "≤ 2 keys: own or 1-hop fields; date keys may end in @day, @week, @month, @bucket; with span the day key is written `date`"
    },
    {
     "name": "on",
     "type": "field",
     "required": false,
     "meaning": "the date or timestamp that places a row on a day (default: the single date key)"
    },
    {
     "name": "span",
     "type": "list:field",
     "required": false,
     "meaning": "[start, end]: the row counts on every day it covers"
    },
    {
     "name": "over",
     "type": "expr",
     "required": false,
     "meaning": "a day series: days(week)"
    },
    {
     "name": "window",
     "type": "object",
     "required": false,
     "meaning": "{last: n} buckets for @week/@month keys"
    },
    {
     "name": "where",
     "type": "predicate",
     "required": false,
     "meaning": ""
    },
    {
     "name": "facts",
     "type": "list:field",
     "required": false,
     "meaning": "with op=list: ≤ 3 fields of each listed record (the rows, or the `property` targets), shown in the popover"
    },
    {
     "name": "decimals",
     "type": "number",
     "required": false,
     "meaning": "decimal places its numbers are written to (0–6), the word a number property's `scale: { decimals }` uses; default: the measure's declared decimals — an `avg` of a field that declares none to 1 place"
    }
   ]
  },
  "State": {
   "kind": "data",
   "summary": "A value the reader chooses; kept in the URL under its id.",
   "parents": [
    "Page",
    "RecordPage"
   ],
   "children": [],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "id",
     "type": "id",
     "required": true,
     "meaning": ""
    },
    {
     "name": "type",
     "type": "enum|name:type",
     "required": true,
     "meaning": "or an ObjectType name = a ref State",
     "enum": [
      "date",
      "week",
      "range",
      "month",
      "boolean",
      "number",
      "string",
      "enum"
     ]
    },
    {
     "name": "initial",
     "type": "expr",
     "required": false,
     "meaning": "required for date/week/range/month; a range's is {from: <date>, days: <whole number>}, e.g. {{from: today(), days: 14}} (never {start, end}); wins over auto when not null"
    },
    {
     "name": "options",
     "type": "list:object",
     "required": false,
     "meaning": "enum States: [{value, label}]"
    },
    {
     "name": "where",
     "type": "predicate",
     "required": false,
     "meaning": "ref States without `from`: the choices"
    },
    {
     "name": "sort",
     "type": "field|list:field",
     "required": false,
     "meaning": "ref States without `from`; a link sorts by its target's title, as a Query's"
    },
    {
     "name": "from",
     "type": "ref:Query",
     "required": false,
     "meaning": "ref States: the choices are this Query's rows — its where, active preset, chosen facets and search, in its sort, never just its page — so the picker lists what the page lists; no where or sort of its own"
    },
    {
     "name": "auto",
     "type": "enum",
     "required": false,
     "meaning": "ref States: pick the only choice, the first/second in sort, or the `from` Query's current row. Without auto nothing is picked until the reader chooses (a filter State reads null as \"all\"): `from={upcoming} auto=\"first\"` opens on the first upcoming row",
     "enum": [
      "single",
      "first",
      "second",
      "current"
     ]
    },
    {
     "name": "weekdays",
     "type": "list:string",
     "required": false,
     "meaning": "week/range States: the days shown, e.g. [\"mon\",…,\"sat\"]; default every day. days(week), a Matrix, a Timeline day axis, a week DayGrid and PeriodNav (its label and day strip) show only these"
    }
   ]
  },
  "Preview": {
   "kind": "data",
   "summary": "The Form action's live preview outputs as `pv.<output>` (typed, policy-checked).",
   "parents": [
    "Form"
   ],
   "children": [],
   "fnReturns": [],
   "requiresAncestor": [
    "Form"
   ],
   "parentRules": {},
   "props": [
    {
     "name": "id",
     "type": "id",
     "required": true,
     "meaning": ""
    }
   ]
  },
  "Section": {
   "kind": "component",
   "summary": "A titled region; a top-level Section is one card with its title in the header.",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Tab",
    "Expand",
    "Form",
    "Step"
   ],
   "children": [
    "Section",
    "Split",
    "Columns",
    "Grid",
    "Tabs",
    "Toolbar",
    "Value",
    "Text",
    "Badge",
    "Callout",
    "Stat",
    "Ratio",
    "Meter",
    "Chart",
    "Facts",
    "Breakdown",
    "History",
    "Lifecycle",
    "Table",
    "List",
    "Board",
    "Matrix",
    "Timeline",
    "DayGrid",
    "Filters",
    "Search",
    "Control",
    "PeriodNav",
    "Files",
    "Compare",
    "Link",
    "Form",
    "Action",
    "Empty",
    "Query",
    "Field",
    "Lines",
    "Step",
    "Submit",
    "Candidates"
   ],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "title",
     "type": "text|element|expr",
     "required": false,
     "meaning": "text, or a record expression (its title)",
     "elements": [
      "Text",
      "Value"
     ]
    },
    {
     "name": "of",
     "type": "expr",
     "required": false,
     "meaning": "the section's record: scope for verbs (incl. its Toolbar), default record of Facts; when null, a record title hides, components that read it render nothing and the Section's Empty speaks"
    },
    {
     "name": "when",
     "type": "expr",
     "required": false,
     "meaning": "render expression; false hides the element (UX only, never security). A withheld operand makes it false."
    },
    {
     "name": "audience",
     "type": "list:group",
     "required": false,
     "meaning": "groups it is drawn for (checked against the org's groups); a reader in none of them is not served it at all — no title, no lock rows (owners and admins see every one); decided on the server, not a data boundary (reads stay policy-checked)"
    }
   ]
  },
  "Split": {
   "kind": "component",
   "summary": "Main + aside, exactly two children; the aside is sticky at ≥ 1024 px when it holds a Form summary. In a Form, the side holding its inputs (Field, Lines, Step, Submit, Candidates) is sized by its fields and the result side takes the rest, in either order.",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Tab",
    "Form"
   ],
   "children": [
    "Section",
    "Split",
    "Columns",
    "Grid",
    "Tabs",
    "Toolbar",
    "Value",
    "Text",
    "Badge",
    "Callout",
    "Stat",
    "Ratio",
    "Meter",
    "Chart",
    "Facts",
    "Breakdown",
    "History",
    "Lifecycle",
    "Table",
    "List",
    "Board",
    "Matrix",
    "Timeline",
    "DayGrid",
    "Filters",
    "Search",
    "Control",
    "PeriodNav",
    "Files",
    "Compare",
    "Link",
    "Form",
    "Field",
    "Lines",
    "Step",
    "Submit",
    "Candidates"
   ],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": []
  },
  "Columns": {
   "kind": "component",
   "summary": "2–4 different children side by side when the container is ≥ 960 px; stacked otherwise.",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Tab",
    "Form"
   ],
   "children": [
    "Section",
    "Split",
    "Columns",
    "Grid",
    "Tabs",
    "Toolbar",
    "Value",
    "Text",
    "Badge",
    "Callout",
    "Stat",
    "Ratio",
    "Meter",
    "Chart",
    "Facts",
    "Breakdown",
    "History",
    "Lifecycle",
    "Table",
    "List",
    "Board",
    "Matrix",
    "Timeline",
    "DayGrid",
    "Filters",
    "Search",
    "Control",
    "PeriodNav",
    "Files",
    "Compare",
    "Link",
    "Form"
   ],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": []
  },
  "Grid": {
   "kind": "component",
   "summary": "Like items only: Stat or Files tiles; the tile count picks the tracks at every width — wide, 2–5 tiles one track each (3 tiles → 3, never 3 of 4), 6 → 3, 7 or more → 4; on phone 2 (3 for 3, 1 for 5 or 7) — so the first row has no empty track and no later row is an orphan; tiles never stretch; a withheld tile reflows the rest left.",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Tab",
    "Form"
   ],
   "children": [
    "Stat",
    "Files"
   ],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": []
  },
  "Tabs": {
   "kind": "component",
   "summary": "A tool's views (a builder, an editor), or record sections you group yourself; a long RecordPage draws its sections as tabs on its own.",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Tab",
    "Form"
   ],
   "children": [
    "Tab"
   ],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": []
  },
  "Tab": {
   "kind": "part",
   "summary": "One tab.",
   "parents": [
    "Tabs"
   ],
   "children": [
    "Section",
    "Split",
    "Columns",
    "Grid",
    "Tabs",
    "Toolbar",
    "Value",
    "Text",
    "Badge",
    "Callout",
    "Stat",
    "Ratio",
    "Meter",
    "Chart",
    "Facts",
    "Breakdown",
    "History",
    "Lifecycle",
    "Table",
    "List",
    "Board",
    "Matrix",
    "Timeline",
    "DayGrid",
    "Filters",
    "Search",
    "Control",
    "PeriodNav",
    "Files",
    "Compare",
    "Link",
    "Form",
    "Action",
    "Empty",
    "Field",
    "Lines",
    "Step",
    "Submit",
    "Candidates"
   ],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "label",
     "type": "text",
     "required": true,
     "meaning": ""
    },
    {
     "name": "lead",
     "type": "ref:Query",
     "required": false,
     "meaning": "the collection whose total is the tab's count badge (default: the tab's first collection)"
    },
    {
     "name": "audience",
     "type": "list:group",
     "required": false,
     "meaning": "groups it is drawn for (checked against the org's groups); a reader in none of them is not served it at all — no title, no lock rows (owners and admins see every one); decided on the server, not a data boundary (reads stay policy-checked)"
    }
   ]
  },
  "Toolbar": {
   "kind": "component",
   "summary": "Inputs and verbs for the page or a section (a Section's first child).",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Tab",
    "Form"
   ],
   "children": [
    "Search",
    "Filters",
    "Control",
    "PeriodNav",
    "Action"
   ],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": []
  },
  "Value": {
   "kind": "component",
   "summary": "One field or typed expression, shown the one way its type and container show it.",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Tab",
    "Text",
    "Badge",
    "Callout",
    "Empty",
    "Cell",
    "Form",
    "Lines"
   ],
   "children": [],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "of",
     "type": "expr",
     "required": true,
     "meaning": "a field, link, aggregate cell, list, handle or typed expression"
    },
    {
     "name": "change",
     "type": "boolean",
     "required": false,
     "meaning": "this is a difference: show the sign (+15) and the `better` tone",
     "default": false
    }
   ]
  },
  "Text": {
   "kind": "component",
   "summary": "Prose with inline values.",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Tab",
    "Cell",
    "Form"
   ],
   "children": [
    "TEXT",
    "Value",
    "Link",
    "Badge"
   ],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "when",
     "type": "expr",
     "required": false,
     "meaning": "render expression; false hides the element (UX only, never security). A withheld operand makes it false."
    }
   ]
  },
  "Badge": {
   "kind": "component",
   "summary": "A neutral mark with text (\"Rush\", \"Repeat\"); attention marks come from Flags, never from a Badge.",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Tab",
    "Text",
    "Callout",
    "Item",
    "Form"
   ],
   "children": [
    "TEXT",
    "Value"
   ],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "when",
     "type": "expr",
     "required": false,
     "meaning": "render expression; false hides the element (UX only, never security). A withheld operand makes it false."
    }
   ]
  },
  "Callout": {
   "kind": "component",
   "summary": "A note the author writes: info, or a warning about the screen's content (not a refusal, not a data exception).",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Tab",
    "Form"
   ],
   "children": [
    "TEXT",
    "Value",
    "Link",
    "Badge"
   ],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "tone",
     "type": "enum",
     "required": false,
     "meaning": "",
     "default": "info",
     "enum": [
      "info",
      "warn"
     ]
    },
    {
     "name": "title",
     "type": "text",
     "required": false,
     "meaning": ""
    },
    {
     "name": "when",
     "type": "expr",
     "required": false,
     "meaning": "render expression; false hides the element (UX only, never security). A withheld operand makes it false."
    }
   ]
  },
  "Stat": {
   "kind": "component",
   "summary": "A KPI tile: label, value, optional delta, foot line and sparkline.",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Grid",
    "Tab",
    "Form"
   ],
   "children": [
    "Ratio"
   ],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "label",
     "type": "text",
     "required": true,
     "meaning": ""
    },
    {
     "name": "value",
     "type": "expr",
     "required": false,
     "meaning": "number, money or duration; or a Ratio child"
    },
    {
     "name": "compare",
     "type": "enum",
     "required": false,
     "meaning": "shifts the time key of the Aggregate in value; a period in progress is set against the same elapsed span of the earlier one (\"on 1–10 Nov\"); for the whole earlier period, show its total in a Ratio child instead",
     "enum": [
      "previous_period",
      "same_period_last_year"
     ]
    },
    {
     "name": "better",
     "type": "enum",
     "required": false,
     "meaning": "default from the field's `better`",
     "enum": [
      "up",
      "down"
     ]
    },
    {
     "name": "context",
     "type": "element",
     "required": false,
     "meaning": "the foot line",
     "elements": [
      "Text",
      "Value"
     ]
    },
    {
     "name": "trend",
     "type": "ref:Aggregate",
     "required": false,
     "meaning": "keyed by time → sparkline"
    },
    {
     "name": "decimals",
     "type": "number",
     "required": false,
     "meaning": "decimal places a number value is written to (0–6), the word a number property's `scale: { decimals }` uses; default: its field's or Aggregate's decimals; a computed figure (`a.value * 100 / b.value`) that is not whole to 1 place, and arithmetic keeps the unit of its typed side"
    },
    {
     "name": "when",
     "type": "expr",
     "required": false,
     "meaning": "render expression; false hides the element (UX only, never security). A withheld operand makes it false."
    }
   ]
  },
  "Ratio": {
   "kind": "component",
   "summary": "\"assigned / needed\": the numerator in 600 ink, \"/ needed\" muted. Its tone comes from its two numbers, never from a prop: `of` is a whole (capacity), `need` a requirement.",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Tab",
    "Stat",
    "Cell",
    "Form"
   ],
   "children": [],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "value",
     "type": "expr",
     "required": true,
     "meaning": ""
    },
    {
     "name": "of",
     "type": "expr",
     "required": false,
     "meaning": "the whole the value is a share of (capacity, available, total): over it is critical \"over by n\"; at or under it the pair is neutral; a literal (`of={2400}`) is in the value's unit (minutes: \"40 h\")"
    },
    {
     "name": "need",
     "type": "expr",
     "required": false,
     "meaning": "what is needed (staff per shift, coaches per trip): below it is short — critical \"short n\"; at it met — a check; above it over — warn \"over by n\"; a literal is in the value's unit"
    },
    {
     "name": "remainder",
     "type": "text",
     "required": false,
     "meaning": "with `need`: the words for what is still missing below it, after its count — `remainder=\"to check\"` reads \"26 / 35 · 9 to check\" where the default reads \"short 9\" (lines not yet checked are not short); literal text"
    }
   ]
  },
  "Meter": {
   "kind": "component",
   "summary": "A bar with its number; tone from the field's `thresholds` (model), healthy = neutral ink.",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Tab",
    "Form"
   ],
   "children": [],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "value",
     "type": "expr",
     "required": true,
     "meaning": ""
    },
    {
     "name": "of",
     "type": "expr",
     "required": true,
     "meaning": ""
    }
   ]
  },
  "Chart": {
   "kind": "component",
   "summary": "A chart by question; the platform picks bars/lines/stacking.",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Tab",
    "Form"
   ],
   "children": [
    "Series"
   ],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "shows",
     "type": "enum",
     "required": true,
     "meaning": "",
     "enum": [
      "trend",
      "composition",
      "comparison",
      "capacity"
     ]
    },
    {
     "name": "limit",
     "type": "expr",
     "required": false,
     "meaning": "capacity line"
    },
    {
     "name": "when",
     "type": "expr",
     "required": false,
     "meaning": "render expression; false hides the element (UX only, never security). A withheld operand makes it false."
    }
   ]
  },
  "Series": {
   "kind": "part",
   "summary": "One series of a Chart.",
   "parents": [
    "Chart"
   ],
   "children": [],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "of",
     "type": "ref:Aggregate",
     "required": true,
     "meaning": ""
    },
    {
     "name": "label",
     "type": "text",
     "required": true,
     "meaning": ""
    }
   ]
  },
  "Facts": {
   "kind": "component",
   "summary": "Key–value facts of a record.",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Tab",
    "Form"
   ],
   "children": [
    "Fact"
   ],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "of",
     "type": "expr",
     "required": false,
     "meaning": "the record (default: the nearest Section's `of`, else `record`); a link (record.space) carries the target's title only, so its Facts are refused: read it with a Record and name that"
    }
   ]
  },
  "Fact": {
   "kind": "part",
   "summary": "One fact.",
   "parents": [
    "Facts",
    "Meta"
   ],
   "children": [],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "field",
     "type": "field",
     "required": false,
     "meaning": "a field or link of the record"
    },
    {
     "name": "value",
     "type": "expr",
     "required": false,
     "meaning": ""
    },
    {
     "name": "label",
     "type": "text",
     "required": false,
     "meaning": "default from the field; required with value or span"
    },
    {
     "name": "sub",
     "type": "expr|element",
     "required": false,
     "meaning": "a grey line: \"in 3 days\"",
     "elements": [
      "Text",
      "Value"
     ]
    },
    {
     "name": "span",
     "type": "list:field",
     "required": false,
     "meaning": "[start, end] dates, times or timestamps shown as one value \"07:00–19:30\""
    }
   ]
  },
  "Meta": {
   "kind": "part",
   "summary": "≤ 6 Facts on one line under the record title.",
   "parents": [
    "RecordPage"
   ],
   "children": [
    "Fact"
   ],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": []
  },
  "Breakdown": {
   "kind": "component",
   "summary": "A money summary; lines in written order (it shows, it does not add).",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Tab",
    "Form"
   ],
   "children": [
    "Line"
   ],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "of",
     "type": "expr",
     "required": true,
     "meaning": "a record or a Preview"
    }
   ]
  },
  "Line": {
   "kind": "part",
   "summary": "One money line.",
   "parents": [
    "Breakdown"
   ],
   "children": [],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "field",
     "type": "field",
     "required": false,
     "meaning": ""
    },
    {
     "name": "value",
     "type": "expr",
     "required": false,
     "meaning": ""
    },
    {
     "name": "label",
     "type": "text",
     "required": false,
     "meaning": ""
    },
    {
     "name": "kind",
     "type": "enum",
     "required": false,
     "meaning": "subtotal = a ruled line (\"Net\"); total and due 16/700; credit = a credit note; minus = discounts, cuts, paid, shown with −; part = an \"of which\" line, indented, not part of the sum",
     "enum": [
      "subtotal",
      "total",
      "due",
      "credit",
      "minus",
      "part"
     ]
    },
    {
     "name": "each",
     "type": "expr",
     "required": false,
     "meaning": "a keyed preview output (one line per key, labelled with the key and its base: \"VAT 13 % on €5,060.00\") or a to-many link of the record (one line per row: `field` = the row's money field, `label` = the row's label field); zero lines hidden"
    },
    {
     "name": "when",
     "type": "expr",
     "required": false,
     "meaning": "render expression; false hides the element (UX only, never security). A withheld operand makes it false."
    }
   ]
  },
  "History": {
   "kind": "component",
   "summary": "A record's changes: its transitions and its history: true fields (PA-8), or a declared event log.",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Tab",
    "Form"
   ],
   "children": [],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "of",
     "type": "expr",
     "required": true,
     "meaning": ""
    },
    {
     "name": "fields",
     "type": "list:field",
     "required": false,
     "meaning": "the type's opt-in history fields"
    },
    {
     "name": "log",
     "type": "field",
     "required": false,
     "meaning": "a to-many link of an event type to read instead of the transition log"
    },
    {
     "name": "at",
     "type": "field",
     "required": false,
     "meaning": "the event's date or timestamp",
     "default": "at"
    },
    {
     "name": "by",
     "type": "field",
     "required": false,
     "meaning": "who: a field or a link (its record's title)",
     "default": "by"
    },
    {
     "name": "action",
     "type": "field",
     "required": false,
     "meaning": "",
     "default": "action"
    },
    {
     "name": "note",
     "type": "field",
     "required": false,
     "meaning": "",
     "default": "note"
    }
   ]
  },
  "Lifecycle": {
   "kind": "component",
   "summary": "Where a record is in its process: the machine's main path with dates; a taken branch replaces the rest of the path.",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Tab",
    "Form"
   ],
   "children": [],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "of",
     "type": "expr",
     "required": true,
     "meaning": ""
    }
   ]
  },
  "Table": {
   "kind": "component",
   "summary": "Aligned columns over a collection.",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Tab",
    "Form"
   ],
   "children": [
    "Column",
    "Action",
    "BulkAction",
    "Group",
    "Expand",
    "Check",
    "Empty"
   ],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "of",
     "type": "ref:Query|ref:Aggregate|expr",
     "required": true,
     "meaning": "a Query, an Aggregate (one row per key) or a Preview array (pv.items)"
    },
    {
     "name": "opens",
     "type": "expr|string",
     "required": false,
     "meaning": "\"auto\" (the type's record view; rows of a type without one, Aggregate rows and preview rows do not open), a view name, a record expression (opens its view) or \"none\"",
     "default": "auto"
    },
    {
     "name": "picks",
     "type": "ref:State",
     "required": false,
     "meaning": "a ref State of the row type: a row click sets it (master–detail); not drawn yet, refused at compile: choose the record with a Control on the ref State, or let the rows open their record (opens)"
    },
    {
     "name": "verbs",
     "type": "enum",
     "required": false,
     "meaning": "flag (default): a verb is visible only on rows whose flag it fixes (the condition's `fix`), as a bordered button; job: the first offered verb is the page's per-row job — a quiet text button (the action's `shortLabel`: \"Record\") on every eligible row, bordered on flagged rows; `rest` is a synonym of job; menu: every verb in ⋯. A queue (a Query with `current`, or a Check) defaults to job. A verb whose preCheck guard fails never shows at rest. ⋯ appears only when it holds a verb (opening the record is the title's job, not a menu item); a job column may show different verbs per row (the first offered differs by state); a create with no subject may be a row verb, its inputs filled from the row.",
     "default": "flag",
     "enum": [
      "flag",
      "job",
      "rest",
      "menu"
     ]
    },
    {
     "name": "when",
     "type": "expr",
     "required": false,
     "meaning": "render expression; false hides the element (UX only, never security). A withheld operand makes it false."
    }
   ]
  },
  "Column": {
   "kind": "part",
   "summary": "One column.",
   "parents": [
    "Table"
   ],
   "children": [],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "field",
     "type": "field",
     "required": false,
     "meaning": "own field, 1-hop path, rollup, or a to-many path (a capped list of ≤ 3 linked titles + \"+N\")"
    },
    {
     "name": "value",
     "type": "fn",
     "required": false,
     "meaning": "a row function: r => …"
    },
    {
     "name": "label",
     "type": "text",
     "required": false,
     "meaning": "default from the field; required with value"
    },
    {
     "name": "importance",
     "type": "enum",
     "required": false,
     "meaning": "auto: first column primary, money and status secondary, the rest detail",
     "default": "auto",
     "enum": [
      "auto",
      "primary",
      "eyebrow",
      "secondary",
      "detail"
     ]
    },
    {
     "name": "total",
     "type": "enum",
     "required": false,
     "meaning": "money/number fields; over the whole filtered set; nulls count as 0, \"—\" when every value is null",
     "enum": [
      "sum",
      "count"
     ]
    },
    {
     "name": "sort",
     "type": "boolean",
     "required": false,
     "meaning": "default true for fields"
    },
    {
     "name": "sortBy",
     "type": "field",
     "required": false,
     "meaning": "with value: the field a value column sorts by"
    },
    {
     "name": "sub",
     "type": "fn",
     "required": false,
     "meaning": "a row function for a sub-line: r => …; a number or amount read from a field is written with that field's label (\"Staff needed 9\"), never bare — for assigned of needed write value={r => <Ratio value={r.assigned} need={r.needed} />}"
    }
   ]
  },
  "List": {
   "kind": "component",
   "summary": "Free rows with the card anatomy (queues, run sheets).",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Tab",
    "Form"
   ],
   "children": [
    "FN",
    "Action",
    "Group",
    "Check",
    "Empty"
   ],
   "fnReturns": [
    "Item"
   ],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "of",
     "type": "ref:Query|expr",
     "required": true,
     "meaning": "a Query or a Preview array"
    },
    {
     "name": "opens",
     "type": "expr|string",
     "required": false,
     "meaning": "\"auto\" (the type's record view; rows of a type without one, Aggregate rows and preview rows do not open), a view name, a record expression (opens its view) or \"none\"",
     "default": "auto"
    },
    {
     "name": "picks",
     "type": "ref:State",
     "required": false,
     "meaning": "not drawn yet, refused at compile: choose the record with a Control on the ref State, or let the rows open their record (opens)"
    },
    {
     "name": "verbs",
     "type": "enum",
     "required": false,
     "meaning": "flag (default): a verb is visible only on rows whose flag it fixes (the condition's `fix`), as a bordered button; job: the first offered verb is the page's per-row job — a quiet text button (the action's `shortLabel`: \"Record\") on every eligible row, bordered on flagged rows; `rest` is a synonym of job; menu: every verb in ⋯. A queue (a Query with `current`, or a Check) defaults to job. A verb whose preCheck guard fails never shows at rest. ⋯ appears only when it holds a verb (opening the record is the title's job, not a menu item); a job column may show different verbs per row (the first offered differs by state); a create with no subject may be a row verb, its inputs filled from the row.",
     "default": "flag",
     "enum": [
      "flag",
      "job",
      "rest",
      "menu"
     ]
    },
    {
     "name": "when",
     "type": "expr",
     "required": false,
     "meaning": "render expression; false hides the element (UX only, never security). A withheld operand makes it false."
    }
   ]
  },
  "Item": {
   "kind": "part",
   "summary": "The row/card template: eyebrow, title, ≤ 2 sub facts, value, ≤ 2 Badges after the title (a List row and a Board card; a Timeline bar and a DayGrid block draw its eyebrow, title, lead, sub, value and detail, no Badge); the status pill is automatic.",
   "parents": [
    "List",
    "Board",
    "Timeline",
    "DayGrid"
   ],
   "children": [
    "Badge"
   ],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "title",
     "type": "expr",
     "required": true,
     "meaning": "the human name (15 px); the row's link"
    },
    {
     "name": "eyebrow",
     "type": "expr",
     "required": false,
     "meaning": "default the type's code field (display.code), unless the title starts with it or another slot shows it; in containers ≥ 1200 px a muted inline prefix on the title line (\"EV-1187 · Team lunch\"), above the title only in card form"
    },
    {
     "name": "lead",
     "type": "expr",
     "required": false,
     "meaning": "a time or a person; the time leads when the Query is sorted by it; on a Timeline bar or DayGrid block a time lead is the bar's own time (never repeated), a person the first fact"
    },
    {
     "name": "sub",
     "type": "list:expr",
     "required": false,
     "meaning": "≤ 2 render expressions or to-many paths; bare numbers show their label; null facts are hidden"
    },
    {
     "name": "value",
     "type": "expr",
     "required": false,
     "meaning": "number or money, right"
    },
    {
     "name": "detail",
     "type": "list:expr",
     "required": false,
     "meaning": "≤ 3 short labelled facts on one muted line (\"3 sessions · approved €410\"); dropped first on phone; null facts are hidden"
    }
   ]
  },
  "Group": {
   "kind": "part",
   "summary": "Groups rows by a key; an Action child is a group verb whose subject is the group's key record.",
   "parents": [
    "Table",
    "List"
   ],
   "children": [
    "Action"
   ],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "by",
     "type": "field",
     "required": true,
     "meaning": "a path, optional @day/@week/@month/@bucket (Overdue / Today / This week / Later)"
    },
    {
     "name": "order",
     "type": "list:string",
     "required": false,
     "meaning": "key order; default: an enum key's declared order, else by first appearance in the Query's sort"
    },
    {
     "name": "collapsed",
     "type": "list:string",
     "required": false,
     "meaning": "keys collapsed by default"
    },
    {
     "name": "measure",
     "type": "field",
     "required": false,
     "meaning": "numeric field summed in the header"
    }
   ]
  },
  "Expand": {
   "kind": "part",
   "summary": "The row opens in place; may hold one scoped Query whose where reads the row (read on open).",
   "parents": [
    "Table"
   ],
   "children": [
    "FN"
   ],
   "fnReturns": [
    "Section"
   ],
   "requiresAncestor": [],
   "parentRules": {},
   "props": []
  },
  "Check": {
   "kind": "part",
   "summary": "A leading 24 px check control (44 px hit area on phone).",
   "parents": [
    "Table",
    "List"
   ],
   "children": [],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "run",
     "type": "name:action",
     "required": true,
     "meaning": "the transition to done"
    },
    {
     "name": "undo",
     "type": "name:action",
     "required": true,
     "meaning": "its inverse"
    },
    {
     "name": "done",
     "type": "name:condition",
     "required": false,
     "meaning": "the condition that counts as checked (default: run's target state)"
    }
   ]
  },
  "BulkAction": {
   "kind": "part",
   "summary": "Runs a one-subject action over the selected rows (invoke_many, ≤ 100).",
   "parents": [
    "Table"
   ],
   "children": [],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "run",
     "type": "name:action",
     "required": true,
     "meaning": ""
    }
   ]
  },
  "Empty": {
   "kind": "part",
   "summary": "The empty state: a title, a reason and ≤ 1 Action; several Empty parts, first match wins.",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Tab",
    "Table",
    "List",
    "Board",
    "Matrix",
    "Timeline",
    "DayGrid",
    "Form"
   ],
   "children": [
    "TEXT",
    "Value",
    "Link",
    "Action"
   ],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "title",
     "type": "text",
     "required": true,
     "meaning": ""
    },
    {
     "name": "when",
     "type": "expr",
     "required": false,
     "meaning": "render expression; false hides the element (UX only, never security). A withheld operand makes it false."
    }
   ]
  },
  "Board": {
   "kind": "component",
   "summary": "Cards in lanes of a process.",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Tab",
    "Form"
   ],
   "children": [
    "FN",
    "Action",
    "Empty"
   ],
   "fnReturns": [
    "Item"
   ],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "of",
     "type": "ref:Query",
     "required": true,
     "meaning": "the collection"
    },
    {
     "name": "opens",
     "type": "expr|string",
     "required": false,
     "meaning": "\"auto\" (the type's record view; rows of a type without one, Aggregate rows and preview rows do not open), a view name, a record expression (opens its view) or \"none\"",
     "default": "auto"
    },
    {
     "name": "by",
     "type": "field",
     "required": true,
     "meaning": "an enum or state-machine field"
    },
    {
     "name": "sum",
     "type": "field",
     "required": false,
     "meaning": "money/number (incl. rollups) summed in each lane header"
    },
    {
     "name": "when",
     "type": "expr",
     "required": false,
     "meaning": "render expression; false hides the element (UX only, never security). A withheld operand makes it false."
    }
   ]
  },
  "Matrix": {
   "kind": "component",
   "summary": "Rows × columns of cells.",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Tab",
    "Form"
   ],
   "children": [
    "Rows",
    "Empty"
   ],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "cols",
     "type": "expr",
     "required": true,
     "meaning": "the grain: days(week) (honours the State's weekdays), weeks(range) or months(range), hours(day), or an enum field \"type.field\""
    },
    {
     "name": "cells",
     "type": "ref:Query",
     "required": false,
     "meaning": "default for every Rows: a Query of a per-cell type (e.g. class_day) whose Flags give each cell its attention"
    },
    {
     "name": "cellKey",
     "type": "list:field",
     "required": false,
     "meaning": "the cells type's fields matching (row, column), e.g. [\"vehicle_class\", \"date\"]; [\"date\"] for a fixed row"
    },
    {
     "name": "closed",
     "type": "ref:Query",
     "required": false,
     "meaning": "the closed days (a plant's holidays and Sundays): each row closes the day column its `closedKey` date falls on, read whole over the columns' days, so its where needs no window term"
    },
    {
     "name": "closedKey",
     "type": "field",
     "required": false,
     "meaning": "the closed Query's date field, e.g. \"date\" (required with `closed`)"
    },
    {
     "name": "closedReason",
     "type": "field",
     "required": false,
     "meaning": "the closed Query's field naming why, e.g. \"holiday_name\" (default: the row's title)"
    },
    {
     "name": "corner",
     "type": "text",
     "required": false,
     "meaning": ""
    },
    {
     "name": "opens",
     "type": "expr|string",
     "required": false,
     "meaning": "the row label's target (auto: the row record's view when rows are records)",
     "default": "auto"
    },
    {
     "name": "when",
     "type": "expr",
     "required": false,
     "meaning": "render expression; false hides the element (UX only, never security). A withheld operand makes it false."
    }
   ]
  },
  "Rows": {
   "kind": "part",
   "summary": "One row set of a Matrix: records, enum values or one fixed row.",
   "parents": [
    "Matrix"
   ],
   "children": [
    "FN"
   ],
   "fnReturns": [
    "Cell"
   ],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "of",
     "type": "ref:Query",
     "required": false,
     "meaning": "one row per record, every record of the Query (read whole, never a page)"
    },
    {
     "name": "values",
     "type": "field",
     "required": false,
     "meaning": "an enum field \"type.field\": one row per value"
    },
    {
     "name": "label",
     "type": "text",
     "required": false,
     "meaning": "one fixed row (row = null)"
    },
    {
     "name": "sub",
     "type": "fn",
     "required": false,
     "meaning": "row → a sub-line"
    },
    {
     "name": "cells",
     "type": "ref:Query",
     "required": false,
     "meaning": "this row set's cell records (overrides the Matrix's)"
    },
    {
     "name": "cellKey",
     "type": "list:field",
     "required": false,
     "meaning": ""
    }
   ]
  },
  "Cell": {
   "kind": "part",
   "summary": "One matrix cell: ≤ 4 inline facts (text, never interactive) and one target.",
   "parents": [
    "Rows"
   ],
   "children": [
    "Ratio",
    "Value",
    "Text",
    "Action"
   ],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "opens",
     "type": "expr",
     "required": false,
     "meaning": "a record: the cell opens it (with `list` or Actions: the popover's first row is \"Open <record>\")"
    },
    {
     "name": "list",
     "type": "expr",
     "required": false,
     "meaning": "a list Aggregate cell: the records the popover lists (not counted as a fact)"
    },
    {
     "name": "current",
     "type": "boolean",
     "required": false,
     "meaning": ""
    }
   ]
  },
  "Timeline": {
   "kind": "component",
   "summary": "Items over time in lanes.",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Tab",
    "Form"
   ],
   "children": [
    "FN",
    "Span",
    "Action",
    "Empty"
   ],
   "fnReturns": [
    "Item"
   ],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "of",
     "type": "ref:Query",
     "required": true,
     "meaning": ""
    },
    {
     "name": "lane",
     "type": "field",
     "required": true,
     "meaning": "a link or enum field; null lanes collect in a derived lane"
    },
    {
     "name": "lanes",
     "type": "ref:Query",
     "required": false,
     "meaning": "a link lane's lane records: a Query of the link's target type, every row a lane in its order, an empty lane kept (the whole fleet, idle coaches too), and no other: an item on a lane it leaves out is not drawn. Omitted: only the lanes that hold an item in the range, in title order. An enum lane draws every value"
    },
    {
     "name": "start",
     "type": "field|list:field",
     "required": true,
     "meaning": "a timestamp or date, or [date, time]"
    },
    {
     "name": "end",
     "type": "field|list:field",
     "required": true,
     "meaning": "blank on a row = open-ended: drawn to the axis end with an open-end mark; never coalesce it to a far date. The Timeline reads its Query over the range itself, so the Query needs no window term: one on the end field (`c.end_date >= span.start`) drops every open-ended item, since a blank never matches `>=`"
    },
    {
     "name": "range",
     "type": "ref:State|expr",
     "required": true,
     "meaning": "a week, range or month State, or a row-free expression; a date State is an hour axis"
    },
    {
     "name": "grain",
     "type": "enum",
     "required": false,
     "meaning": "the axis columns: days, the weeks (from the org's week start) or the months the range touches; not with a date State",
     "default": "day",
     "enum": [
      "day",
      "week",
      "month"
     ]
    },
    {
     "name": "capacity",
     "type": "expr|string",
     "required": false,
     "meaning": "how much one lane holds at once; a bar is marked Conflict only while its lane holds more. 1 (the default: a coach, a room or a person does one thing at a time) marks any two bars at once; a number or a row-free expression (`capacity={record.owned_qty}`) is every lane's; a lane function over the `lanes` records (`capacity={k => k.owned_qty}`) is each lane's own; with a second parameter, the day, it is a capacity per day (`capacity={(k, d) => k.owned_qty + hired.at(k, d)}`: owned plus that day's hire-ins, hired a sum Aggregate keyed by lane and date), measured at every day start as well as every bar start; \"none\" marks no overlap (a lane of notes, a day of events). A lane whose capacity reads blank or withheld marks no overlap",
     "default": "1"
    },
    {
     "name": "amount",
     "type": "field",
     "required": false,
     "meaning": "a number field of the item: how much of its lane's capacity each bar takes (`amount=\"qty\"`: 30 + 20 tables of 45 owned is over, 30 + 10 is not); without it each bar takes 1; a blank or withheld amount takes 0. Needs a capacity other than \"none\". Kit hire: `<Timeline of={res} lanes={kit} lane=\"kit_item\" start=\"out_on\" end=\"back_on\" range={span} capacity={k => k.owned_qty} amount=\"qty\">`"
    },
    {
     "name": "opens",
     "type": "expr|string",
     "required": false,
     "meaning": "",
     "default": "auto"
    },
    {
     "name": "move",
     "type": "name:action",
     "required": false,
     "meaning": "not drawn yet, refused at compile: put <Action run=…> inside the Timeline, each bar offers it with the bar as its subject"
    },
    {
     "name": "when",
     "type": "expr",
     "required": false,
     "meaning": "render expression; false hides the element (UX only, never security). A withheld operand makes it false."
    }
   ]
  },
  "Span": {
   "kind": "part",
   "summary": "A shaded stretch of time: dates cover whole days, timestamps cover the stretch.",
   "parents": [
    "Timeline",
    "DayGrid"
   ],
   "children": [],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "of",
     "type": "ref:Query",
     "required": true,
     "meaning": ""
    },
    {
     "name": "kind",
     "type": "enum",
     "required": true,
     "meaning": "",
     "enum": [
      "blocked",
      "available"
     ]
    },
    {
     "name": "lane",
     "type": "field",
     "required": false,
     "meaning": "no lane = all lanes"
    },
    {
     "name": "start",
     "type": "field",
     "required": true,
     "meaning": ""
    },
    {
     "name": "end",
     "type": "field",
     "required": true,
     "meaning": ""
    },
    {
     "name": "label",
     "type": "field",
     "required": false,
     "meaning": "the visible text, e.g. \"Time off: course\""
    }
   ]
  },
  "DayGrid": {
   "kind": "component",
   "summary": "The calendar: lanes × time of day.",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Tab",
    "Form"
   ],
   "children": [
    "FN",
    "Span",
    "Action",
    "Empty"
   ],
   "fnReturns": [
    "Item"
   ],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "of",
     "type": "ref:Query",
     "required": true,
     "meaning": ""
    },
    {
     "name": "lanes",
     "type": "ref:Query",
     "required": false,
     "meaning": "resources; may be a per-day type; omitted with a week range = one column per day"
    },
    {
     "name": "laneKey",
     "type": "field",
     "required": false,
     "meaning": "the lanes row's link to the lane record (when lanes is a per-day type)"
    },
    {
     "name": "lane",
     "type": "field",
     "required": false,
     "meaning": "the item's link to the lane record; required with `lanes`"
    },
    {
     "name": "start",
     "type": "field",
     "required": true,
     "meaning": ""
    },
    {
     "name": "end",
     "type": "field",
     "required": true,
     "meaning": ""
    },
    {
     "name": "range",
     "type": "ref:State|expr",
     "required": true,
     "meaning": ""
    },
    {
     "name": "hours",
     "type": "object",
     "required": false,
     "meaning": "{from: \"08:00\", to: \"19:00\"}"
    },
    {
     "name": "slot",
     "type": "enum",
     "required": false,
     "meaning": "",
     "default": "15",
     "enum": [
      "15",
      "30",
      "60"
     ]
    },
    {
     "name": "create",
     "type": "name:action",
     "required": false,
     "meaning": "not drawn yet, refused at compile: put <Action run=…> on the page or its Section, its dialog asks for the start and the lane"
    },
    {
     "name": "move",
     "type": "name:action",
     "required": false,
     "meaning": "not drawn yet, refused at compile: put <Action run=…> inside the DayGrid, each block offers it with the block as its subject"
    },
    {
     "name": "opens",
     "type": "expr|string",
     "required": false,
     "meaning": "",
     "default": "auto"
    },
    {
     "name": "when",
     "type": "expr",
     "required": false,
     "meaning": "render expression; false hides the element (UX only, never security). A withheld operand makes it false."
    }
   ]
  },
  "Filters": {
   "kind": "component",
   "summary": "Preset chips and facet chips with live counts.",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Tab",
    "Toolbar",
    "Form"
   ],
   "children": [],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "of",
     "type": "ref:Query",
     "required": true,
     "meaning": ""
    }
   ]
  },
  "Search": {
   "kind": "component",
   "summary": "Free text over the Query's search fields ($search).",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Tab",
    "Toolbar",
    "Form"
   ],
   "children": [],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "of",
     "type": "ref:Query",
     "required": true,
     "meaning": ""
    }
   ]
  },
  "Control": {
   "kind": "component",
   "summary": "One control for one State; the kind follows the State's type.",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Tab",
    "Toolbar",
    "Form"
   ],
   "children": [],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "state",
     "type": "ref:State",
     "required": true,
     "meaning": ""
    },
    {
     "name": "label",
     "type": "text",
     "required": true,
     "meaning": ""
    }
   ]
  },
  "PeriodNav": {
   "kind": "component",
   "summary": "‹ Today › with the range label; drives every component bound to its State.",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Tab",
    "Toolbar",
    "Form"
   ],
   "children": [],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "state",
     "type": "ref:State",
     "required": true,
     "meaning": ""
    },
    {
     "name": "span",
     "type": "enum",
     "required": true,
     "meaning": "the step: a date State steps by day, a week by week, a month by month, a range by its length (fortnight) or by a week or a month (its length kept; a range of whole months keeps its months)",
     "enum": [
      "day",
      "week",
      "fortnight",
      "month"
     ]
    },
    {
     "name": "counts",
     "type": "ref:Aggregate|list:ref:Aggregate",
     "required": false,
     "meaning": "keyed by date: a day strip with badges in the header's unit; a list is summed (coach-short and driver-short days)"
    },
    {
     "name": "skip",
     "type": "enum",
     "required": false,
     "meaning": "empty: arrows step to the next day with a count",
     "default": "none",
     "enum": [
      "none",
      "empty"
     ]
    }
   ]
  },
  "Files": {
   "kind": "component",
   "summary": "A record's attachments: tiles, lightbox, Add when the reader may attach.",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Grid",
    "Tab",
    "Form"
   ],
   "children": [],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "of",
     "type": "expr",
     "required": true,
     "meaning": ""
    },
    {
     "name": "kinds",
     "type": "list:string",
     "required": false,
     "meaning": "attachment kinds of the type (incl. kinds backed by a child type, PA-14)"
    }
   ]
  },
  "Compare": {
   "kind": "component",
   "summary": "Two versions of a record with aligned lines, signed deltas and totals.",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Tab",
    "Form"
   ],
   "children": [],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "a",
     "type": "expr",
     "required": true,
     "meaning": ""
    },
    {
     "name": "b",
     "type": "expr",
     "required": true,
     "meaning": ""
    },
    {
     "name": "lines",
     "type": "field",
     "required": true,
     "meaning": "a to-many link"
    },
    {
     "name": "key",
     "type": "field",
     "required": true,
     "meaning": "unique per record: a field or a link (the line's item); a duplicate is a render refusal naming it"
    },
    {
     "name": "value",
     "type": "field",
     "required": true,
     "meaning": "the line money field: per-line signed delta, totals per side, difference"
    },
    {
     "name": "fields",
     "type": "list:field",
     "required": false,
     "meaning": "line fields compared and shown; a line is Changed when any differs"
    },
    {
     "name": "facts",
     "type": "list:field",
     "required": false,
     "meaning": "header fields aligned above the lines, each with its change"
    },
    {
     "name": "total",
     "type": "field",
     "required": false,
     "meaning": "the record's own money or number total (e.g. incl. VAT): a/b and the difference"
    }
   ]
  },
  "Action": {
   "kind": "component",
   "summary": "The one verb element: runs an action (generated dialog) or opens a view.",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Tab",
    "Toolbar",
    "Table",
    "List",
    "Group",
    "Empty",
    "Board",
    "Cell",
    "Timeline",
    "DayGrid"
   ],
   "children": [],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "run",
     "type": "name:action",
     "required": false,
     "meaning": "an action"
    },
    {
     "name": "view",
     "type": "name:view",
     "required": false,
     "meaning": "a view to open"
    },
    {
     "name": "params",
     "type": "object|fn",
     "required": false,
     "meaning": "with view: named parameters, or a row function (r => ({customer: r.customer})) so a Form page can be a row's fix verb"
    },
    {
     "name": "label",
     "type": "text",
     "required": false,
     "meaning": "required with view; refused with run (the model's label)"
    },
    {
     "name": "role",
     "type": "enum",
     "required": false,
     "meaning": "may sit on verbs that exclude each other by legality: the first offered one is primary",
     "enum": [
      "primary"
     ]
    },
    {
     "name": "with",
     "type": "object|fn",
     "required": false,
     "meaning": "input presets: {{event_id: evt}} or a row function n => ({position: n.position}); null clears a fill"
    },
    {
     "name": "rest",
     "type": "boolean",
     "required": false,
     "meaning": "false: never the at-rest row verb"
    },
    {
     "name": "when",
     "type": "expr|fn",
     "required": false,
     "meaning": "render expression; false hides the element (UX only, never security). A withheld operand makes it false. On a Table/List/Board row verb, a row function d => d.state == \"on_road\" is its row condition: the verb is offered only on the rows it holds for."
    }
   ]
  },
  "Link": {
   "kind": "component",
   "summary": "Inline navigation to a view or a record.",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Tab",
    "Text",
    "Callout",
    "Empty",
    "Form"
   ],
   "children": [
    "TEXT"
   ],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "view",
     "type": "name:view",
     "required": false,
     "meaning": ""
    },
    {
     "name": "params",
     "type": "object",
     "required": false,
     "meaning": ""
    },
    {
     "name": "record",
     "type": "expr",
     "required": false,
     "meaning": "opens the record's view"
    }
   ]
  },
  "Form": {
   "kind": "component",
   "summary": "An action's form as the screen; a scope: any layout inside; Field/Lines/Step/Submit/Candidates/Preview need a Form ancestor.",
   "parents": [
    "Page",
    "RecordPage",
    "Section",
    "Split",
    "Columns",
    "Tab",
    "Form"
   ],
   "children": [
    "Preview",
    "Section",
    "Split",
    "Columns",
    "Grid",
    "Tabs",
    "Toolbar",
    "Value",
    "Text",
    "Badge",
    "Callout",
    "Stat",
    "Ratio",
    "Meter",
    "Chart",
    "Facts",
    "Breakdown",
    "History",
    "Lifecycle",
    "Table",
    "List",
    "Board",
    "Matrix",
    "Timeline",
    "DayGrid",
    "Filters",
    "Search",
    "Control",
    "PeriodNav",
    "Files",
    "Compare",
    "Link",
    "Form",
    "Field",
    "Lines",
    "Step",
    "Submit",
    "Candidates",
    "Empty"
   ],
   "fnReturns": [],
   "requiresAncestor": [],
   "parentRules": {},
   "props": [
    {
     "name": "run",
     "type": "name:action",
     "required": true,
     "meaning": ""
    },
    {
     "name": "with",
     "type": "object",
     "required": false,
     "meaning": "input presets, e.g. {{proposal_id: param(\"proposal\")}}; a null value leaves the input to its model default"
    },
    {
     "name": "view",
     "type": "name:view",
     "required": false,
     "meaning": "the view a successful submit opens, with `params` (built like a Link: a view the reader may not open, or a param with no value, opens nothing). Without it the Form resets in place, or opens the record the action navigates to (`presentation.refresh: \"navigate\"`)"
    },
    {
     "name": "params",
     "type": "object",
     "required": false,
     "meaning": "with view: its named parameters, from the page's scope ({{event: ev}})"
    }
   ]
  },
  "Field": {
   "kind": "part",
   "summary": "Places one model input; everything else about it is the model's.",
   "parents": [
    "Section",
    "Split",
    "Tab",
    "Form",
    "Lines",
    "Step"
   ],
   "children": [],
   "fnReturns": [],
   "requiresAncestor": [
    "Form"
   ],
   "parentRules": {},
   "props": [
    {
     "name": "name",
     "type": "name:input",
     "required": true,
     "meaning": ""
    }
   ]
  },
  "Lines": {
   "kind": "part",
   "summary": "An array input as a lines grid: a row per line, a column per sub-input; `<Value of={line.<property>} />` shows each line's own value, a property of the row it inserts (the action's `presentation.preview.rows`).",
   "parents": [
    "Section",
    "Split",
    "Tab",
    "Form",
    "Step"
   ],
   "children": [
    "Field",
    "Value"
   ],
   "fnReturns": [],
   "requiresAncestor": [
    "Form"
   ],
   "parentRules": {},
   "props": [
    {
     "name": "field",
     "type": "name:input",
     "required": true,
     "meaning": ""
    }
   ]
  },
  "Step": {
   "kind": "part",
   "summary": "Layout of one model step (pure layout): its Fields must belong to that step.",
   "parents": [
    "Section",
    "Split",
    "Tab",
    "Form"
   ],
   "children": [
    "Field",
    "Lines",
    "Section",
    "Candidates"
   ],
   "fnReturns": [],
   "requiresAncestor": [
    "Form"
   ],
   "parentRules": {},
   "props": [
    {
     "name": "name",
     "type": "name:step",
     "required": true,
     "meaning": ""
    }
   ]
  },
  "Submit": {
   "kind": "part",
   "summary": "A submit button for one of the model's submits.",
   "parents": [
    "Section",
    "Split",
    "Tab",
    "Form"
   ],
   "children": [],
   "fnReturns": [],
   "requiresAncestor": [
    "Form"
   ],
   "parentRules": {},
   "props": [
    {
     "name": "mode",
     "type": "name:submit",
     "required": false,
     "meaning": "the model submit this button runs. Required when the action declares more than one submit: write one `<Submit mode=…>` per submit the screen offers (they render in written order); a `<Submit>` without `mode` is legal only when the action has a single submit (or none), and then runs it. The forward submit (one whose `next` runs a forward transition, e.g. Send) is primary and is the sticky phone bar's button; Save draft is secondary"
    }
   ]
  },
  "Candidates": {
   "kind": "part",
   "summary": "Choose a related record with each option's rule outcome (Form-as-screen; generated dialogs render it by themselves).",
   "parents": [
    "Section",
    "Split",
    "Tab",
    "Form",
    "Step"
   ],
   "children": [],
   "fnReturns": [],
   "requiresAncestor": [
    "Form"
   ],
   "parentRules": {},
   "props": [
    {
     "name": "field",
     "type": "name:input",
     "required": true,
     "meaning": ""
    },
    {
     "name": "facts",
     "type": "list:field",
     "required": false,
     "meaning": "candidate fields shown; may read the subject (model)"
    }
   ]
  }
 },
 "helpers": [
  {
   "call": "today()",
   "returns": "date",
   "meaning": "the org clock's date (demo clock included)"
  },
  {
   "call": "now()",
   "returns": "timestamp",
   "meaning": "the org clock's instant"
  },
  {
   "call": "addDays(date, n)",
   "returns": "date",
   "meaning": ""
  },
  {
   "call": "weekOf(date)",
   "returns": "week",
   "meaning": "`.start`, `.end`: the Monday–Sunday week holding the date; a State's `weekdays` narrow the days it shows"
  },
  {
   "call": "monthOf(date)",
   "returns": "month",
   "meaning": "a month key for @month Aggregates"
  },
  {
   "call": "days(weekOrRange)",
   "returns": "list:date",
   "meaning": "the shown days of a week/range State (its weekdays)"
  },
  {
   "call": "weeks(rangeOrMonth)",
   "returns": "list:week",
   "meaning": "the weeks a range or month State touches, from the org's week start: Matrix columns or an Aggregate's `over` at week grain"
  },
  {
   "call": "months(range)",
   "returns": "list:month",
   "meaning": "the months a range State touches: Matrix columns or an Aggregate's `over` at month grain"
  },
  {
   "call": "hours(day)",
   "returns": "list:timestamp",
   "meaning": "the hours of a date State's day in the org zone (23 or 25 on a DST day): Matrix columns or an Aggregate's `over` at hour grain"
  },
  {
   "call": "param(name)",
   "returns": "string|record",
   "meaning": "a declared view parameter"
  },
  {
   "call": "me()",
   "returns": "record",
   "meaning": "the reader (`.name`, `.id`); in predicates only as `r.link == me()`"
  },
  {
   "call": "greeting()",
   "returns": "text",
   "meaning": "\"Good morning, Lena\" in the org zone"
  },
  {
   "call": "plural(n, one, many)",
   "returns": "text",
   "meaning": "the word only, by the count: `plural(n, \"stop\", \"stops\")` is \"stop\" for 1 and \"stops\" otherwise. Write the number beside it: `<Text><Value of={n} /> <Value of={plural(n, \"stop\", \"stops\")} /></Text>` reads \"1 stop\" / \"12 stops\""
  },
  {
   "call": "percent(part, whole)",
   "returns": "number",
   "meaning": "a computed share written as a percentage: `percent(rewash.value, washed.value)` with 29 of 1,000 is \"2.9%\" (\"2,9 %\" in Danish). One argument is a ratio, a fraction of one: `percent(0.029)` is \"2.9%\"; never multiply by 100 yourself. To 1 place unless the percentage is whole (\"50%\"); a Stat's `scale` sets the places. A whole of 0 or none is no value (\"—\"). A field that holds a ratio declares `scale: {as: \"percent\"}` in the model instead"
  }
 ],
 "handles": [
  {
   "form": "q.total",
   "returns": "number",
   "meaning": "rows the collection shows (all filters)"
  },
  {
   "form": "q.count(id)",
   "returns": "number",
   "meaning": "a Preset's count or a condition's row count"
  },
  {
   "form": "q.amount(condition)",
   "returns": "number",
   "meaning": "Σ of the condition's amount (\"7 open positions\")"
  },
  {
   "form": "q.sum(field[, condition])",
   "returns": "number|money",
   "meaning": "a declared total"
  },
  {
   "form": "q.preset",
   "returns": "string",
   "meaning": "the active preset id"
  },
  {
   "form": "q.current",
   "returns": "record",
   "meaning": "the current (→ Next) record, or null"
  },
  {
   "form": "a.at(k1[, k2])",
   "returns": "number|list",
   "meaning": "an Aggregate cell"
  },
  {
   "form": "a.value",
   "returns": "number",
   "meaning": "an Aggregate without by"
  },
  {
   "form": "a.next(key)",
   "returns": "key",
   "meaning": "the first key ≥ key with a non-zero value"
  },
  {
   "form": "a.peak(k)",
   "returns": "number|money",
   "meaning": "the largest cell along the time key (an over series or a bucketed key), the other key fixed: the busiest day of a range"
  },
  {
   "form": "a.peakAt(k)",
   "returns": "date",
   "meaning": "the period a.peak(k) falls on (the earliest of equal peaks); null when nothing is counted"
  },
  {
   "form": "a.free(k, capacity)",
   "returns": "number|money",
   "meaning": "capacity − a.peak(k), never below 0; past the capacity it reads 0 and is short by the excess on the peak day (\"0 short 1 on Sat 28 Nov\", critical, its row railed)"
  },
  {
   "form": "a.free(k, capacity, extra)",
   "returns": "number|money",
   "meaning": "a capacity that differs by day: on each day capacity + extra.at(k, day) − a.at(k, day), the least of them, never below 0; short by the deficit on the tightest day. extra is a count or sum Aggregate keyed like a (owned stock + what is hired in that day)"
  },
  {
   "form": "s.start / s.end",
   "returns": "date",
   "meaning": "week and range States"
  },
  {
   "form": "pv.<output>",
   "returns": "typed",
   "meaning": "a Preview output"
  },
  {
   "form": "line.<output>",
   "returns": "typed",
   "meaning": "inside Lines: the line's own value (a `preview.rows` property of the row it inserts)"
  },
  {
   "form": "input.<name>",
   "returns": "typed",
   "meaning": "inside a Form: the current input value"
  }
 ],
 "scope": [
  "record (RecordPage)",
  "input (Form)",
  "line (Lines)",
  "child-function parameters",
  "every data element id",
  "every State id"
 ],
 "refusals": [
  {
   "case": "type name case",
   "written": "`type=\"Event\"` on r19",
   "message": "the type is 'event'"
  },
  {
   "case": "_id field",
   "written": "`<Column field=\"client_id\"/>`",
   "message": "use the link 'client'"
  },
  {
   "case": "unknown field",
   "written": "`field=\"pasengers\"`",
   "message": "trip has no field 'pasengers'; did you mean 'passengers'?"
  },
  {
   "case": "hops",
   "written": "`field=\"contract.event.client\"`",
   "message": "2 hops: declare a lookup on instalment or read it through a Record"
  },
  {
   "case": "thin predicate",
   "written": "`where={d => d.trip.is_live}`",
   "message": "comparisons through a link are refused: declare a lookup on trip_day (trip_is_live) or a named condition"
  },
  {
   "case": "or of rows",
   "written": "`where={a => a.status == \"booked\" \\|\\| a.is_late}`",
   "message": "declare a named condition on appointment (e.g. is_open)"
  },
  {
   "case": "repeated literal",
   "written": "the same `status != \"cancelled\"` in two views",
   "message": "advice: declare it on <type> (e.g. is_live)"
  },
  {
   "case": "view attention",
   "written": "`<Ratio short=\"below\">`, `<Badge tone=\"critical\">`",
   "message": "attention comes from a named condition: Flag it, or use a cells Query"
  },
  {
   "case": "Flag shape",
   "written": "`<Flag meaning=\"late\" when={…}>`",
   "message": "Flag takes condition=…; declare the condition on cue (meaning late, on due_at)"
  },
  {
   "case": "constant Flag",
   "written": "`<Query where={i => i.is_overdue}><Flag condition=\"is_overdue\"/>`",
   "message": "every row is overdue; the section title says so (the set is flagged)"
  },
  {
   "case": "Field when",
   "written": "`<Field name=\"bar_hours\" when={…}>`",
   "message": "conditional inputs belong to proposal.build (inputShowWhen)"
  },
  {
   "case": "Step title",
   "written": "`<Step title=\"Pain\">`",
   "message": "Step names a model step: name=\"pain\""
  },
  {
   "case": "submit mode",
   "written": "`<Submit />` in a Form for proposal.build (submits draft, send)",
   "message": "<Submit> without mode: proposal.build has 2 submits — write mode= one of draft, send"
  },
  {
   "case": "Form twice",
   "written": "a Form for an action that is also an Action on the page",
   "message": "pick one: the Form is the screen, or the Action opens the generated dialog"
  },
  {
   "case": "Preview outside",
   "written": "`<Preview>` outside a Form",
   "message": "Preview reads the enclosing Form"
  },
  {
   "case": "template prop",
   "written": "`cell=`, `item=`, `renderItem=`",
   "message": "write the template as the child function"
  },
  {
   "case": "Action parent",
   "written": "an Action in an unknown parent",
   "message": "Action is legal in Page, RecordPage, Section, Tab, Toolbar, Table, List, Board, Group, Empty, Cell, Timeline, DayGrid"
  },
  {
   "case": "with key",
   "written": "`with={{event: …}}`",
   "message": "proposal.send has no input 'event'; inputs: proposal_id, message"
  },
  {
   "case": "fill tie",
   "written": "two Events in scope",
   "message": "two events in scope (ev, evt); write with={{event_id: …}}"
  },
  {
   "case": "no-op fill",
   "written": "a `sets` input filled from a scope value equal to the subject's current value",
   "message": "to_route sets customer.route; filling it from the row's route is a no-op — left empty"
  },
  {
   "case": "subject link fill",
   "written": "an input of the type the subject links to, with no `sets`: `van_id` on run.change_van in a runs Table",
   "message": "run.change_van.van_id would be filled from the row's van — the run's own value: declare sets: \"van\" on the input (the dialog asks it), or fill it with with={{van_id: …}}"
  },
  {
   "case": "id shadowing",
   "written": "`<Query id=\"days\">`",
   "message": "'days' is a helper; rename the Query"
  },
  {
   "case": "aggregate arity",
   "written": "`have.at(p)` on a 2-key Aggregate",
   "message": "have is keyed by (position, date)"
  },
  {
   "case": "period start",
   "written": "a week State without initial",
   "message": "PeriodNav needs a start: initial={weekOf(today())}"
  },
  {
   "case": "collection props",
   "written": "`where=`/`filter=`/`sort=` on a Table",
   "message": "filters and sort belong to the Query"
  },
  {
   "case": "presets",
   "written": "`<Preset>` inside `<Filters>`",
   "message": "Presets are declared in the Query"
  },
  {
   "case": "search in predicate",
   "written": "`t.title.includes(x)`",
   "message": "use the Query's search"
  },
  {
   "case": "library: Line",
   "written": "`<Chart><Line dataKey=…/></Chart>`",
   "message": "Line is a Breakdown money line; a Chart takes <Series of={agg} label=…/>"
  },
  {
   "case": "library: Group",
   "written": "`<Group><Action/><Action/></Group>` outside a collection",
   "message": "Group groups rows of a collection"
  },
  {
   "case": "library: Item",
   "written": "`<Item label=\"Qty\"><Field/></Item>`",
   "message": "Item is a row template; a form field is <Field name=…> in a Form"
  },
  {
   "case": "library: Page",
   "written": "`<Page primaryAction={…}>`",
   "message": "write <Action run=… role=\"primary\"/> as a Page child"
  },
  {
   "case": "library: Table",
   "written": "`<Table columns={[…]} dataSource={…}>`",
   "message": "columns are <Column> children; data is of={query}"
  },
  {
   "case": "library: Tabs",
   "written": "`<Tabs items={…}>`",
   "message": "write <Tab label=…> children"
  },
  {
   "case": "library: tones",
   "written": "`tone=\"success\"`",
   "message": "attention comes from conditions; Callout tone is info | warn"
  },
  {
   "case": "library: Form",
   "written": "`<Form onSubmit=… initialValues=…>`",
   "message": "Form runs an action (run=); defaults are the model's"
  },
  {
   "case": "library: Link",
   "written": "`<Link href=\"/trips/1\">`",
   "message": "Link takes view= or record="
  },
  {
   "case": "library: Grid",
   "written": "`<Grid item xs={6}>`",
   "message": "Grid lays out like items; no spans"
  },
  {
   "case": "library: Check",
   "written": "`<Check checked={c.done}>`",
   "message": "Check runs run/undo transitions"
  },
  {
   "case": "SQL clock",
   "written": "`date('now')` in a condition",
   "message": "use :today / :now (the org clock)"
  },
  {
   "case": "author a11y",
   "written": "`role=`, `tabindex=`, `aria-*`, `onClick=`",
   "message": "the platform owns roles and keys"
  }
 ]
}

This page as Markdown