Records cards
Reach for this to browse records as cards — five postures from dense scan rows to media browse tiles, with onOpen: as the card's single primary action. cardFor binds each row to posture-free slots and the grid picks the posture itself, so the record-to-media swap is the grid's decision rather than the screen's. A verb on this screen has three homes and none of them is the bar: the primary one is the Fab (fab), view verbs like Export are the view-options surface's header affordance, and a record's own actions belong to the pushed record surface — see Detail's hosting knob.
Spec of record: design-system/components/data/Card.d.ts
Live
Real widgets, built from the real kit. Turn a knob and it rebuilds; the theme bar above applies the design system's own tokens — including anything you changed under Customize — and the device selector uses the same sizes the golden baselines gate on, so what you see here is what CI holds the widget to.
Press Focus on any preview to take it to the full window — at a desktop width that renders most devices at 1:1, which is when the widget's own controls become clickable. The bar always states the device and the scale, so a shrunk preview says it is shrunk. Esc leaves.
Set to 0 for the empty state.
Shows when you tap a card — selection paints on the ones you pick, and starts empty — press Focus to make the preview interactive.
Which nav the compact posture mounts — the drawer behind the hamburger, or a bottom bar.
The primary tier, and on a records destination the ONLY loud action the bar's neighborhood has. The scaffold renders it in the thumb zone at every window class; a screen never places it itself.
Actions in the drawer's own footer. The drawer carries them at EVERY window class — at 960 and wider it exists only because they do, since the expanded shell otherwise mounts a standing inline rail instead.
Shows when you open the drawer — the hamburger below 960, an edge swipe at 960 and wider, where the rail head's menu button toggles the rail instead. The actions sit in the drawer's own footer; the resting frame is identical either way. — press Focus to make the preview interactive.
The app's identity mark, and nothing else — it never opens a picker. At 960 and wider it sits beside the menu button in the rail's head at the same place in both postures, overhanging the collapsed rail so the bar beside it steps in. Below 960 the drawer's header band states it.
The scope — one value of the app's own kind (here an Area) — as the FIRST item of the bar's subtitle, ahead of the meta. With a picker it is a quiet text button with a chevron; on a phone the whole title block opens the picker as a bottom sheet. A pushed record's bar shows it read-only.
Global commands with no page ("Send feedback", "Help") pinned in the rail's footer under the footer destinations — the same row as a destination, but never lit and never counted in the destination index.
An organization's or partner's logo at the very bottom of the rail and the drawer — identity, never a control. Collapsed it shows its compact square, or nothing when the host gives none.
The Group and Columns panels beside the built-in Filter. `RecordsChrome.panels` is host-contributed and view-agnostic — the same cluster a table gets. OFF leaves Filter standing alone, which is a real posture: the tab row is absent at a single available control, because one control needs no tabs.
Shows when you open the view-options pane (tap Filter's control) — panels are TABS of that one pane, so the resting bar looks identical either way and only the pane's content differs — press Focus to make the preview interactive.
Dart for these values
screen_records_cards() What you can do in it
Capability the preview already carries that no knob can express — you reach it by using the widget. Worth knowing before concluding something is missing: most of this is only clickable once the preview is at Focus size.
- **Search** — type in the field; the table narrows live. Collapsing search never clears the query, which survives as a removable
search:…chip. - **Filter** — the funnel opens the view-options pane. Facets are type-appropriate: enums and text offer distinct values, numbers a min/max, dates a From/To.
- **Chips** — every applied filter renders as a removable chip, and Clear all removes the lot.
- **Narrowed to zero** states the narrowing and offers Clear, rather than the author-a-record empty state.
What it is made of
The widgets this screen assembles, with their full API below. They used to live on a second entry of their own; one thing you choose gets one page.
AppCard widget
The design-system Card — one outlined-card archetype, five postures (AppCardPosture). The whole card is ONE button (onOpen, min DesignTokens.touch target); secondary actions render as the always-visible corner `⋯` menu and footerActions as the media footer's ghost row — both outside the tap target,…
Full dartdoc
The design-system Card — one outlined-card archetype, five postures (AppCardPosture). The whole card is ONE button (onOpen, min DesignTokens.touch target); secondary actions render as the always-visible corner `⋯` menu and footerActions as the media footer's ghost row — both outside the tap target, never an accent slab in a grid. State contract: enabled · hover (DesignTokens.rowHover wash — pointer enhancement only, suppressed while selected) · focus-visible (1px accent, inset) · pressed (1px translateY on the content) · selected (DesignTokens.rowSel wash + border swap to DesignTokens.accent — deliberately NO start-edge bar at card scale) · blocked (DesignTokens.dangerEdge border + danger-weight status word; selected wins) · disabled (DesignTokens.ink40 text, DesignTokens.hair border, no affordance) · loading (structural skeleton mirroring the posture, no shimmer). Empty slots collapse: a dense(AppCard.dense) card with only a title and meta renders them on one row (the ladder's "minimal" rung). ```dart AppCard.record( id: 'SR-1042', title: 'Recoat east span guardrail', supporting: 'Pump house access road', meta: 'upd 09:41', status: 'Blocked', danger: true, onOpen: () => openRecord('SR-1042'), actions: [ AppCardAction(label: 'Edit', glyph: KitGlyph.edit, onSelected: edit), ], ) AppCard.stat( title: 'Open work', value: '6', delta: const ChartDelta( direction: DeltaDirection.up, magnitudeText: '2', sentiment: DeltaSentiment.worse, ), deltaCaption: 'vs prior 7 days', ) ```
AppCard.category
| Knob | Type | Default | What it does |
|---|---|---|---|
| enabled | bool | true | False renders the disabled state: DesignTokens.ink40 text, DesignTokens.hair border, no tap/hover/press, `⋯` hidden. |
| glyph | KitIconRef? | null | The category plate's design-system glyph. Wins over icon. |
| glyphColor | String? | null | THE PLATE TAKES A PALETTE COLOR (`Card.d.ts`, steady-core #1928): a palette NAME (`tokens/palette/Palette.d.ts`) the category plate paints in place of the accent — its tint under the glyph in its ink. Null, or a name DesignTokens.palette does not hold, is the accent-tint plate. An image plate… |
| icon | IconData? | null | The category plate's Material glyph, for consumers not yet on glyph. |
| image | String? | null | Image src for the media block / record thumb / category plate, resolved through AppImage's ladder. Null renders the posture's fallback mark — the Photo glyph on the DesignTokens.ink4 void (media/record), or the category plate's own glyph/icon on the accent tint. |
| imageSemanticLabel | String? | null | Content description for image (media identity, never decorative). |
| loading | bool | false | Renders the structural loading skeleton for this posture — gray DesignTokens.ink4 blocks mirroring the anatomy, excluded from semantics, no shimmer. |
| meta | String? | null | Quiet data-font identity text — a timestamp, a count. Never a sentence. |
| navigates | bool | false | THE ACTION THAT ONLY OPENS A PAGE (`Card.d.ts` `navigates`, `ActionStrip.d.ts`; #1734): opening the card pushes another screen and writes nothing, so the card's one button reports a link to assistive technology (`Semantics(link: true)`). A navigation-hub card (AppCard.category) is the usual one.… |
| onOpen | VoidCallback? | null | The card's ONE primary action — the whole card is this button. Null renders a non-interactive card (no hover/focus/press paint). |
| selected | bool? | null | Card-scale selection: DesignTokens.rowSel wash + border swap to DesignTokens.accent, surfaced as `Semantics.selected` — deliberately NO start-edge bar. Null = not a selection target (no semantics flag). |
| state | AppCardState? | null | THE CATEGORY STATE (`Card.d.ts`, steady-core #1920): one live state about the place the card opens, drawn as an AppStatusPill under the supporting line; null draws nothing and pays no height. The card's name stays its title; the pill's word is read after it. Category posture only. |
| supporting | String? | null | One supporting body line, DesignTokens.ink60, ellipsized. The media posture may raise supportingMaxLines for the ladder's rich rung; the category posture wraps it to two lines (THE CATEGORY LINE WRAPS TO TWO, #1891). |
| title * | String | — | The record's primary label — DesignTokens.title, 2-line clamp (one line in the category/dense postures). In the stat posture: the KPI's label line above the value. |
AppCard.dense
| Knob | Type | Default | What it does |
|---|---|---|---|
| danger | bool | false | Blocked/error grammar: DesignTokens.dangerEdge border + danger-weight status word (media / record / dense). Never set by the stat posture (#895: a KPI's only semantic color is its delta). Loses the border to selected. |
| enabled | bool | true | False renders the disabled state: DesignTokens.ink40 text, DesignTokens.hair border, no tap/hover/press, `⋯` hidden. |
| loading | bool | false | Renders the structural loading skeleton for this posture — gray DesignTokens.ink4 blocks mirroring the anatomy, excluded from semantics, no shimmer. |
| meta | String? | null | Quiet data-font identity text — a timestamp, a count. Never a sentence. |
| metaFormat | FormatRule<Object?>? | null | The resolved rule the meta line wears, every paint, the data font kept — the record posture's `id · meta` row, the media footer's meta, the dense meta line. Null: the plain line. |
| navigates | bool | false | THE ACTION THAT ONLY OPENS A PAGE (`Card.d.ts` `navigates`, `ActionStrip.d.ts`; #1734): opening the card pushes another screen and writes nothing, so the card's one button reports a link to assistive technology (`Semantics(link: true)`). A navigation-hub card (AppCard.category) is the usual one.… |
| onOpen | VoidCallback? | null | The card's ONE primary action — the whole card is this button. Null renders a non-interactive card (no hover/focus/press paint). |
| selected | bool? | null | Card-scale selection: DesignTokens.rowSel wash + border swap to DesignTokens.accent, surfaced as `Semantics.selected` — deliberately NO start-edge bar. Null = not a selection target (no semantics flag). |
| title * | String | — | The record's primary label — DesignTokens.title, 2-line clamp (one line in the category/dense postures). In the stat posture: the KPI's label line above the value. |
| titleFormat | FormatRule<Object?>? | null | A CARD'S LINES WEAR THEIR FORMAT RULE (`Card.d.ts`, #1006): the RESOLVED rule (the resolver's output, resolveFormat) the title line wears, exactly as a list row's title does (`List.d.ts` FORMAT RULES ON A ROW'S LINES): the mark before the first word, 'tag' read as 'ink'. The media, record and dense… |
AppCard.media
| Knob | Type | Default | What it does |
|---|---|---|---|
| actions | List<AppCardAction> | const [] | Secondary actions — the always-visible corner `⋯` menu, OUTSIDE the tap target. Never hover-revealed. The category posture renders none. |
| danger | bool | false | Blocked/error grammar: DesignTokens.dangerEdge border + danger-weight status word (media / record / dense). Never set by the stat posture (#895: a KPI's only semantic color is its delta). Loses the border to selected. |
| enabled | bool | true | False renders the disabled state: DesignTokens.ink40 text, DesignTokens.hair border, no tap/hover/press, `⋯` hidden. |
| footerActions | List<AppCardAction> | const [] | Media-posture footer ghost buttons (label-only), trailing meta on the footer's end. Outside the tap target, behind a top hairline. |
| id | String? | null | Record id — the media posture renders it as the IdChip-grammar corner chip; the record posture leads the data-font meta row with it. |
| image | String? | null | Image src for the media block / record thumb / category plate, resolved through AppImage's ladder. Null renders the posture's fallback mark — the Photo glyph on the DesignTokens.ink4 void (media/record), or the category plate's own glyph/icon on the accent tint. |
| imageSemanticLabel | String? | null | Content description for image (media identity, never decorative). |
| loading | bool | false | Renders the structural loading skeleton for this posture — gray DesignTokens.ink4 blocks mirroring the anatomy, excluded from semantics, no shimmer. |
| mediaAspect | AppCardMediaAspect wide · square · portrait | AppCardMediaAspect.wide | The media block's shape (`Card.d.ts` THE MEDIA BLOCK TAKES A SHAPE AND A FIT, #1378): AppCardMediaAspect.wide 16:9 by default. Media posture only — always AppCardMediaAspect.wide on the others. |
| mediaFit | AppCardMediaFit cover · contain | AppCardMediaFit.cover | How image inscribes the media block or the record thumb: AppCardMediaFit.cover by default, AppCardMediaFit.contain showing the whole image on the ink4 void. Always cover on the category, stat and dense postures, which draw no such frame. |
| meta | String? | null | Quiet data-font identity text — a timestamp, a count. Never a sentence. |
| metaFormat | FormatRule<Object?>? | null | The resolved rule the meta line wears, every paint, the data font kept — the record posture's `id · meta` row, the media footer's meta, the dense meta line. Null: the plain line. |
| navigates | bool | false | THE ACTION THAT ONLY OPENS A PAGE (`Card.d.ts` `navigates`, `ActionStrip.d.ts`; #1734): opening the card pushes another screen and writes nothing, so the card's one button reports a link to assistive technology (`Semantics(link: true)`). A navigation-hub card (AppCard.category) is the usual one.… |
| onOpen | VoidCallback? | null | The card's ONE primary action — the whole card is this button. Null renders a non-interactive card (no hover/focus/press paint). |
| selected | bool? | null | Card-scale selection: DesignTokens.rowSel wash + border swap to DesignTokens.accent, surfaced as `Semantics.selected` — deliberately NO start-edge bar. Null = not a selection target (no semantics flag). |
| status | String? | null | The status WORD — DesignTokens.ink60, no pill, no dot ("encode once"); danger adds the one color-coded treatment. On the stat posture it is THE STATUS, drawn on the label line as an AppStatusMark in statusTone. |
| supporting | String? | null | One supporting body line, DesignTokens.ink60, ellipsized. The media posture may raise supportingMaxLines for the ladder's rich rung; the category posture wraps it to two lines (THE CATEGORY LINE WRAPS TO TWO, #1891). |
| supportingFormat | FormatRule<Object?>? | null | The resolved rule the supporting line wears, every paint. Media and record only. Null: the plain line. |
| supportingMaxLines | int | 1 | Line cap for supporting in the media posture (default 1; the rich ladder rung uses 2). Other postures always clamp to one line. |
| title * | String | — | The record's primary label — DesignTokens.title, 2-line clamp (one line in the category/dense postures). In the stat posture: the KPI's label line above the value. |
| titleFormat | FormatRule<Object?>? | null | A CARD'S LINES WEAR THEIR FORMAT RULE (`Card.d.ts`, #1006): the RESOLVED rule (the resolver's output, resolveFormat) the title line wears, exactly as a list row's title does (`List.d.ts` FORMAT RULES ON A ROW'S LINES): the mark before the first word, 'tag' read as 'ink'. The media, record and dense… |
| titleMaxLines | int | 2 | Line cap for title in the media posture (default 2 — the spec's clamp). AppCardGrid.rail pins 1 so the band's height is deterministic. Other postures keep their own fixed clamps. |
AppCard.record
| Knob | Type | Default | What it does |
|---|---|---|---|
| actionBar | AppCardActionBar? | null | Record posture only: the ACTION BAR below the body, outside the tap target (`Card.d.ts` A RECORD CARD MAY CARRY AN ACTION BAR, #451). Set, the thumb draws only for a real image and the title and supporting lines wrap unclamped. Null renders today's record card. |
| actions | List<AppCardAction> | const [] | Secondary actions — the always-visible corner `⋯` menu, OUTSIDE the tap target. Never hover-revealed. The category posture renders none. |
| danger | bool | false | Blocked/error grammar: DesignTokens.dangerEdge border + danger-weight status word (media / record / dense). Never set by the stat posture (#895: a KPI's only semantic color is its delta). Loses the border to selected. |
| enabled | bool | true | False renders the disabled state: DesignTokens.ink40 text, DesignTokens.hair border, no tap/hover/press, `⋯` hidden. |
| id | String? | null | Record id — the media posture renders it as the IdChip-grammar corner chip; the record posture leads the data-font meta row with it. |
| image | String? | null | Image src for the media block / record thumb / category plate, resolved through AppImage's ladder. Null renders the posture's fallback mark — the Photo glyph on the DesignTokens.ink4 void (media/record), or the category plate's own glyph/icon on the accent tint. |
| imageSemanticLabel | String? | null | Content description for image (media identity, never decorative). |
| loading | bool | false | Renders the structural loading skeleton for this posture — gray DesignTokens.ink4 blocks mirroring the anatomy, excluded from semantics, no shimmer. |
| mediaFit | AppCardMediaFit cover · contain | AppCardMediaFit.cover | How image inscribes the media block or the record thumb: AppCardMediaFit.cover by default, AppCardMediaFit.contain showing the whole image on the ink4 void. Always cover on the category, stat and dense postures, which draw no such frame. |
| meta | String? | null | Quiet data-font identity text — a timestamp, a count. Never a sentence. |
| metaFormat | FormatRule<Object?>? | null | The resolved rule the meta line wears, every paint, the data font kept — the record posture's `id · meta` row, the media footer's meta, the dense meta line. Null: the plain line. |
| navigates | bool | false | THE ACTION THAT ONLY OPENS A PAGE (`Card.d.ts` `navigates`, `ActionStrip.d.ts`; #1734): opening the card pushes another screen and writes nothing, so the card's one button reports a link to assistive technology (`Semantics(link: true)`). A navigation-hub card (AppCard.category) is the usual one.… |
| onOpen | VoidCallback? | null | The card's ONE primary action — the whole card is this button. Null renders a non-interactive card (no hover/focus/press paint). |
| selected | bool? | null | Card-scale selection: DesignTokens.rowSel wash + border swap to DesignTokens.accent, surfaced as `Semantics.selected` — deliberately NO start-edge bar. Null = not a selection target (no semantics flag). |
| status | String? | null | The status WORD — DesignTokens.ink60, no pill, no dot ("encode once"); danger adds the one color-coded treatment. On the stat posture it is THE STATUS, drawn on the label line as an AppStatusMark in statusTone. |
| supporting | String? | null | One supporting body line, DesignTokens.ink60, ellipsized. The media posture may raise supportingMaxLines for the ladder's rich rung; the category posture wraps it to two lines (THE CATEGORY LINE WRAPS TO TWO, #1891). |
| supportingFormat | FormatRule<Object?>? | null | The resolved rule the supporting line wears, every paint. Media and record only. Null: the plain line. |
| title * | String | — | The record's primary label — DesignTokens.title, 2-line clamp (one line in the category/dense postures). In the stat posture: the KPI's label line above the value. |
| titleFormat | FormatRule<Object?>? | null | A CARD'S LINES WEAR THEIR FORMAT RULE (`Card.d.ts`, #1006): the RESOLVED rule (the resolver's output, resolveFormat) the title line wears, exactly as a list row's title does (`List.d.ts` FORMAT RULES ON A ROW'S LINES): the mark before the first word, 'tag' read as 'ink'. The media, record and dense… |
AppCard.stat
| Knob | Type | Default | What it does |
|---|---|---|---|
| compact | bool | false | Renders the stat value at the kpi-c rung (DesignTokens.kpiC). |
| delta | ChartDelta? | null | The stat posture's delta (THE DELTA IS A FIGURE). |
| deltaCaption | String? | null | The stat posture's delta caption ("vs prior 30 days"). |
| loading | bool | false | Renders the structural loading skeleton for this posture — gray DesignTokens.ink4 blocks mirroring the anatomy, excluded from semantics, no shimmer. |
| status | String? | null | The status WORD — DesignTokens.ink60, no pill, no dot ("encode once"); danger adds the one color-coded treatment. On the stat posture it is THE STATUS, drawn on the label line as an AppStatusMark in statusTone. |
| statusTone | AppStatusMarkTone? pending · active · done · blocked | null | The stat posture's status tone (`Card.d.ts` `statusTone`, #948): AppStatusMarkTone.blocked is the KPI's needs-action tag; null draws status as the plain word. Always null on the other postures, whose status stays a word. |
| title * | String | — | The record's primary label — DesignTokens.title, 2-line clamp (one line in the category/dense postures). In the stat posture: the KPI's label line above the value. |
| trend | List<(DateTime, double)>? | null | The stat posture's trend — the window's points, the lead-series sparkline (THE KPI). |
| value * | String? | — | The stat posture's scalar, rendered in the KPI role. |
AppCardGrid widget
The design-system CardGrid — the record-browse collection over AppCard. Adaptation: **swap**, resolved from the grid's OWN measured width (so a pane-hosted grid classifies by its pane, not the window): single-column record posture `< 600` (media collapses to the 56px thumb, 8px gaps) · 2-up media…
Full dartdoc
The design-system CardGrid — the record-browse collection over AppCard. Adaptation: **swap**, resolved from the grid's OWN measured width (so a pane-hosted grid classifies by its pane, not the window): single-column record posture `< 600` (media collapses to the 56px thumb, 8px gaps) · 2-up media posture at medium · 3-up at expanded · **4-up at large (≥1200)**, 16px gutters throughout. Rows equalize card heights so a grid row reads as one band. Selection (the card-scale border swap + wash) stays live across the swap — same record, same selected read, both renders. Stat and dense cards do not swap — the host lays those out itself (a dashboard row). Category cards have their own layout, AppCardGrid.category. ```dart AppCardGrid<WorkOrder>( items: workOrders, keyFor: (wo) => wo.id, selectedKeys: {openId}, onOpen: (wo) => openRecord(wo.id), cardFor: (wo) => AppCardGridItem( id: wo.id, title: wo.title, supporting: wo.site, meta: wo.updatedLabel, status: wo.status, danger: wo.status == 'Blocked', image: wo.coverPhoto, ), ) ```
AppCardGriddefault constructor
| Knob | Type | Default | What it does |
|---|---|---|---|
| cardExtent | double? | null | The card extent, per layout. Rail: each card's EXACT width, default 300. Category: the TRACK FLOOR, default 220 — as many columns as fit at that width or wider. |
| cardFor * | AppCardGridItem Function(T item) | — | Binds one row to its posture-free card slots. Pure `T -> slots`. |
| emptyActionLabel | String? | null | Empty-state single action label (renders with onEmptyAction). |
| emptyActionNavigates | bool | false | THE ACTION THAT ONLY OPENS A PAGE (`ActionStrip.d.ts`, #1749): the empty face's action pushes another screen and writes nothing, so it reports a link to assistive technology. Declared, never inferred from onEmptyAction. Default false. |
| emptyLabel | String | 'No records.' | Empty-state title — what the grid would show. |
| items * | List<T> | — | The row data, in display order. |
| keyFor | Object Function(T item)? | null | Extracts a row's stable identity for selectedKeys matching. Null uses the item itself (value equality) — the old deck's `Set<T>` idiom. |
| onEmptyAction | VoidCallback? | null | Empty-state single action callback (renders with emptyActionLabel). |
| onOpen | ValueChanged<T>? | null | Row tap — the card's primary action, unless the item's own AppCardGridItem.onOpen overrides it. |
| selectedKeys | Set<Object> | const {} | Keys rendered selected (the card-scale border swap + wash) — typically the one open record. Selection survives the posture swap by identity. |
| windowClassOverride | AppWindowClass? compact · medium · expanded · large | null | Pins the window class instead of measuring the container — for specimens and goldens that show both postures side by side. |
AppCardGrid.category
| Knob | Type | Default | What it does |
|---|---|---|---|
| cardExtent | double? | 220 | The card extent, per layout. Rail: each card's EXACT width, default 300. Category: the TRACK FLOOR, default 220 — as many columns as fit at that width or wider. |
| cardFor * | AppCardGridItem Function(T item) | — | Binds one row to its posture-free card slots. Pure `T -> slots`. |
| emptyActionLabel | String? | null | Empty-state single action label (renders with onEmptyAction). |
| emptyActionNavigates | bool | false | THE ACTION THAT ONLY OPENS A PAGE (`ActionStrip.d.ts`, #1749): the empty face's action pushes another screen and writes nothing, so it reports a link to assistive technology. Declared, never inferred from onEmptyAction. Default false. |
| emptyLabel | String | 'No records.' | Empty-state title — what the grid would show. |
| items * | List<T> | — | The row data, in display order. |
| keyFor | Object Function(T item)? | null | Extracts a row's stable identity for selectedKeys matching. Null uses the item itself (value equality) — the old deck's `Set<T>` idiom. |
| onEmptyAction | VoidCallback? | null | Empty-state single action callback (renders with emptyActionLabel). |
| onOpen | ValueChanged<T>? | null | Row tap — the card's primary action, unless the item's own AppCardGridItem.onOpen overrides it. |
| selectedKeys | Set<Object> | const {} | Keys rendered selected (the card-scale border swap + wash) — typically the one open record. Selection survives the posture swap by identity. |
AppCardGrid.rail
| Knob | Type | Default | What it does |
|---|---|---|---|
| cardExtent | double? | 300 | The card extent, per layout. Rail: each card's EXACT width, default 300. Category: the TRACK FLOOR, default 220 — as many columns as fit at that width or wider. |
| cardFor * | AppCardGridItem Function(T item) | — | Binds one row to its posture-free card slots. Pure `T -> slots`. |
| emptyActionLabel | String? | null | Empty-state single action label (renders with onEmptyAction). |
| emptyActionNavigates | bool | false | THE ACTION THAT ONLY OPENS A PAGE (`ActionStrip.d.ts`, #1749): the empty face's action pushes another screen and writes nothing, so it reports a link to assistive technology. Declared, never inferred from onEmptyAction. Default false. |
| emptyLabel | String | 'No records.' | Empty-state title — what the grid would show. |
| items * | List<T> | — | The row data, in display order. |
| keyFor | Object Function(T item)? | null | Extracts a row's stable identity for selectedKeys matching. Null uses the item itself (value equality) — the old deck's `Set<T>` idiom. |
| onEmptyAction | VoidCallback? | null | Empty-state single action callback (renders with emptyActionLabel). |
| onOpen | ValueChanged<T>? | null | Row tap — the card's primary action, unless the item's own AppCardGridItem.onOpen overrides it. |
| selectedKeys | Set<Object> | const {} | Keys rendered selected (the card-scale border swap + wash) — typically the one open record. Selection survives the posture swap by identity. |
Types its knobs take
These are not things you choose — they are the shapes the knobs above expect. They live under this entry rather than in the navigation for exactly that reason.
AppCardAction support
One secondary action on an AppCard — a row in the card's always-visible trailing `⋯` menu, or (via AppCard.footerActions) a ghost button in the media footer. Secondary actions live OUTSIDE the card's tap target.
| Field | Type | Default | What it does |
|---|---|---|---|
| danger | bool | false | Paints the action in DesignTokens.danger (menu-row form) — ink only, never a red slab. |
| enabled | bool | true | Disables the action (DesignTokens.ink40, not tappable) when false. |
| glyph | KitIconRef? | null | The design-system glyph for the menu-row mark. Wins over icon. |
| icon | IconData? | null | A Material glyph, for a consumer that has not moved to glyph yet. |
| label * | String | — | The action's accessible name / menu-row label / footer-button label. |
| onSelected * | VoidCallback? | — | Fires when the action is chosen (menu-row select, footer-button press). |
AppCardActionBar support
A record card's ACTION BAR (`Card.d.ts` A RECORD CARD MAY CARRY AN ACTION BAR, #451): kit buttons INSIDE the card, below the body and OUTSIDE its tap target — for a card that is answered or acted on in place (a checklist item's answer pair, a task's verbs) rather than opened. actions is the LEADING…
| Field | Type | Default | What it does |
|---|---|---|---|
| actions * | List<AppCardBarAction> | — | The leading set — an answer set, or the card's verbs. |
| label | String? | null | The group's accessible name (typically the item the bar answers). |
| trailing | List<AppCardBarAction> | const [] | The trailing set at the inline end. |
AppCardGridItem support
One record's posture-free slot bindings for AppCardGrid — the grid chooses the posture per window class and builds the AppCard itself.
| Field | Type | Default | What it does |
|---|---|---|---|
| actions | List<AppCardAction> | const [] | See AppCard.actions. |
| danger | bool | false | See AppCard.danger. |
| enabled | bool | true | See AppCard.enabled. False renders the card disabled: no tap, the quiet ink and border. |
| footerActions | List<AppCardAction> | const [] | See AppCard.footerActions — rendered in the media posture only. |
| glyph | KitIconRef? | null | The category plate's glyph (AppCard.glyph) — required by AppCardGrid.category, whose plate falls back to it when image is absent or fails. The browse and rail postures do not render it. |
| glyphColor | String? | null | The category plate's palette color (AppCard.glyphColor): its tint under the glyph in its ink. Null, or a name the palette does not hold, is the accent plate. The browse and rail postures do not render it. |
| id | String? | null | See AppCard.id. |
| image | String? | null | See AppCard.image. Collapses to the 56px thumb in the compact swap. |
| imageSemanticLabel | String? | null | See AppCard.imageSemanticLabel. |
| mediaAspect | AppCardMediaAspect | AppCardMediaAspect.wide | See AppCard.mediaAspect — the browse grid's media posture reads it; the rail pins AppCardMediaAspect.wide, and the record and category postures have no media block to shape. |
| mediaFit | AppCardMediaFit | AppCardMediaFit.cover | See AppCard.mediaFit — the media block and the record thumb, at both sides of the swap and on the rail; the category plate ignores it. |
| meta | String? | null | See AppCard.meta. |
| metaFormat | FormatRule<Object?>? | null | See AppCard.metaFormat. The browse and rail postures read it; the category posture ignores it. |
| navigates | bool? | null | See AppCard.navigates. Null leaves the card undeclared, which a host that states a default (`RecordsCardsSlot.navigates`) may fill; a card that states its own, true or false, stands. |
| onOpen | VoidCallback? | null | Per-item open handler. Wins over AppCardGrid.onOpen when both are set. |
| state | AppCardState? | null | THE CATEGORY STATE (AppCard.state, `Card.d.ts`, #1920): one live state about the place the card opens, under its content. Read by AppCardGrid.category only. |
| status | String? | null | See AppCard.status. |
| supporting | String? | null | See AppCard.supporting. |
| supportingFormat | FormatRule<Object?>? | null | See AppCard.supportingFormat. The browse posture reads it; the rail draws no supporting line and the category posture ignores it. |
| title * | String | — | See AppCard.title. |
| titleFormat | FormatRule<Object?>? | null | See AppCard.titleFormat (`Card.d.ts` A CARD'S LINES WEAR THEIR FORMAT RULE, #1006). The browse and rail postures read it; the category posture ignores it. |
AppCardState support
THE CATEGORY STATE's value (`Card.d.ts`, steady-core #1920): one LIVE state about the place a category card opens, drawn as an AppStatusPill under its supporting line — a short word, its tone and an optional 12px glyph. Derived state only, never a stored value (the encode-once rule and the…
| Field | Type | Default | What it does |
|---|---|---|---|
| glyph | KitIconRef? | null | The leading glyph, or null for none. |
| label * | String | — | The short word or phrase — never a sentence. |
| tone | StatusTone | StatusTone.neutral | The pill's tone. |
ChartDelta support
The resolved delta (`Charts.d.ts` `ChartDelta`): direction, display magnitude and the app's sentiment — given, or derived from goodDirection. Rendering is `ChartDeltaFigure`'s (THE DELTA IS A FIGURE); the semantics live here so the visual figure and the Δ9 spoken trend word read the identical…
| Field | Type | Default | What it does |
|---|---|---|---|
| direction * | DeltaDirection | — | Direction, read off the display-rounded delta — never the raw float. |
| goodDirection | ChartGoodDirection? | null | THE GOOD DIRECTION (`Charts.d.ts`, #1425): which way is good for this measure. With no sentiment given, a direction matching it derives DeltaSentiment.better and the opposite DeltaSentiment.worse; flat and noBaseline derive none. |
| magnitudeText | String? | null | The rounded magnitude at the metric's DecimalDigits, T16-grouped ("3", "12%"; a pre-signed "+12%" or "−2" is kept as given); `null` in the no-baseline state (no figure). |
| sentiment | DeltaSentiment? | null |
FormatRule support
One FORMAT RULE (`FormatRules.d.ts` THE FORMAT RULE): a match and its effects. A rule list is ORDERED and the FIRST holding rule formats the value; a rule with no match always holds, so written last it is the column's default.
| Field | Type | Default | What it does |
|---|---|---|---|
| color | KitColor? | null | A palette name or a color parsed from data — on a map pin, its FILL. |
| em | bool | false | The word at the em weight. |
| glyph | KitIconRef? | null | A glyph — on a map pin, the head's glyph. |
| italic | bool | false | The word italic. |
| label | String? | null | What the rule means, in the host's words — read by a legend, a chip and the accessible name. |
| match | FormatMatch<T>? | null | The predicate, or null for "always holds" (the default rule). |
| muted | bool | false | The word at ink40 (ignored under FormatPaint.ink and FormatPaint.tag). |
| paint | FormatPaint | FormatPaint.mark | How color lands on a value (FormatPaint.mark by default). |
| strike | bool | false | The word struck through, in its own ink. |
KitIconRef support
A glyph, by NAME — what every glyph-bearing kit API takes (a pin, a legend key, a nav item, an action, an empty face, a category card). Two shapes implement it: - a KitGlyph — a glyph in the kit's own name table, checked by the compiler (`KitGlyph.syringe`); - KitIconRef.named — any name as a…
| Field | Type | Default | What it does |
|---|---|---|---|
| name * | String | — |
Where it lives
| Class | File |
|---|---|
| AppCard | packages/app_widgets/lib/src/kit/data/card.dart |
| AppCardGrid | packages/app_widgets/lib/src/kit/data/card.dart |