@lotics/ui 22.3.0 → 23.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +9 -2
- package/MIGRATION.md +142 -2
- package/docs/ai_patterns.md +22 -22
- package/docs/catalog.md +119 -98
- package/docs/composition.md +134 -42
- package/docs/data_entry.md +67 -31
- package/docs/templates.md +86 -68
- package/examples/tpl_allocate.tsx +5 -5
- package/examples/tpl_attendance.tsx +2 -2
- package/examples/tpl_calendar.tsx +6 -6
- package/examples/tpl_dashboard.tsx +9 -9
- package/examples/tpl_dieline.tsx +2 -2
- package/examples/tpl_item_list.tsx +64 -37
- package/examples/tpl_lookup.tsx +5 -5
- package/examples/tpl_pick.tsx +6 -6
- package/examples/tpl_pivot.tsx +3 -3
- package/examples/tpl_record.tsx +919 -611
- package/examples/tpl_report.tsx +2 -2
- package/examples/tpl_rollup.tsx +5 -5
- package/examples/tpl_shifts.tsx +5 -5
- package/examples/tpl_statements.tsx +7 -7
- package/examples/tpl_stock.tsx +2 -2
- package/examples/tpl_task_board.tsx +42 -26
- package/examples/tpl_tower.tsx +6 -6
- package/package.json +3 -2
- package/src/agent_run.tsx +4 -4
- package/src/breakdown.tsx +1 -1
- package/src/calendar/calendar_view.tsx +1 -1
- package/src/change_review.tsx +9 -8
- package/src/chip_group.tsx +12 -2
- package/src/choice_list.tsx +2 -2
- package/src/confidence.tsx +2 -2
- package/src/data_grid.tsx +1 -1
- package/src/detail_row.tsx +50 -58
- package/src/file_dropzone.tsx +1 -1
- package/src/file_gallery_modal.tsx +3 -3
- package/src/file_rows.tsx +1 -1
- package/src/finding.tsx +4 -4
- package/src/form_field.tsx +1 -1
- package/src/format_date.ts +2 -2
- package/src/heatmap.tsx +1 -1
- package/src/inline_button.tsx +84 -0
- package/src/inline_date_picker.tsx +17 -10
- package/src/inline_edit.tsx +298 -59
- package/src/inline_member_select.tsx +8 -3
- package/src/inline_number_input.tsx +11 -4
- package/src/inline_select.tsx +26 -13
- package/src/inline_text_input.tsx +12 -4
- package/src/inline_time_picker.tsx +10 -4
- package/src/ledger.tsx +2 -2
- package/src/locale.tsx +7 -3
- package/src/matrix.tsx +1 -1
- package/src/number_input.tsx +18 -7
- package/src/pipeline.tsx +1 -1
- package/src/popover.tsx +1 -1
- package/src/press_door.tsx +1 -1
- package/src/pressable_highlight.tsx +1 -1
- package/src/progress_bar.tsx +3 -3
- package/src/record_summary.tsx +2 -2
- package/src/result_header.tsx +2 -2
- package/src/sequence.tsx +170 -0
- package/src/share_or_download.ts +2 -2
- package/src/step_progress.tsx +7 -5
- package/src/stepper.tsx +1 -1
- package/src/task.tsx +6 -6
- package/src/text_input_field.tsx +19 -1
- package/src/text_utils.ts +1 -1
- package/src/linked_record_box.tsx +0 -157
package/AGENTS.md
CHANGED
|
@@ -53,8 +53,15 @@ CURRENT major only — upgrading an app across majors is `MIGRATION.md`.
|
|
|
53
53
|
- **A button never contains a control** — a row that presses open AND carries its own controls
|
|
54
54
|
(a CTA, ⋯, a checkbox, a `Link`) is a role-less `PressableRow` + a **`PressDoor`** sibling
|
|
55
55
|
(the tab stop, name, focus ring), never `PressableHighlight`, which wraps its children in the
|
|
56
|
-
button. `Table`/`TableRow`
|
|
57
|
-
|
|
56
|
+
button. `Table`/`TableRow` already does this. → [composition.md](./docs/composition.md).
|
|
57
|
+
- **A reference to another record is a FIELD** — it wears the inline editor's own resting
|
|
58
|
+
surface, carries an **`InlineButton`** Open inside it, and PEEKS its facts on press (detach
|
|
59
|
+
lives in the peek). Never its own Section, never a card, never the other record's fields as
|
|
60
|
+
rows on this one. → [composition.md](./docs/composition.md).
|
|
61
|
+
- **A verb about a VALUE goes on the value** — an `InlineButton` in the field's `actions`
|
|
62
|
+
(Copy, Open), never the row's `trailing`: a control at the page's right edge has to be paired
|
|
63
|
+
back to the field it belongs to, and one row's action makes EVERY row reserve the column.
|
|
64
|
+
→ [composition.md](./docs/composition.md).
|
|
58
65
|
- **Files land THREE ways on any surface that holds them** — the section's Add CTA
|
|
59
66
|
(`pickFiles`), and a drag OR paste, both from ONE **`<FileDropTarget … paste>`** wrapping the
|
|
60
67
|
region — a Files section, OR a WHOLE surface (a record's section stack, a register page), so a
|
package/MIGRATION.md
CHANGED
|
@@ -4,6 +4,146 @@ Breaking changes, newest first — normally per major, plus the rare minor that
|
|
|
4
4
|
anyway (recorded under its exact version). The current contract lives in `AGENTS.md` + `docs/`;
|
|
5
5
|
this file exists only to move an app from one release to the next.
|
|
6
6
|
|
|
7
|
+
## 23.0.0 — the `Inline*` editors are WHITE, and `variant` is renamed
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
<InlineSelect variant="cell" … /> // BEFORE
|
|
11
|
+
<InlineSelect variant="bare" … /> // AFTER — same axis, named for the LOOK not the use
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
An inline editor now rests on THE pill surface — **white with a 1px border**, the same one `Chip`,
|
|
15
|
+
`ChipGroup` and a secondary `Button` wear — hovering by darkening that border and adding the 2px
|
|
16
|
+
ring when open. The zinc-50 chip is gone.
|
|
17
|
+
|
|
18
|
+
`InlineEditVariant` survives but is renamed for what it IS rather than where it was used:
|
|
19
|
+
**`"framed"`** (was `"form"`, still the default) keeps that frame visible; **`"bare"`** (was
|
|
20
|
+
`"cell"`) shows nothing at rest and fades the SAME border in on hover. `"cell"` named a use — a
|
|
21
|
+
grid cell — which is why nobody reached for it on the other dense surfaces it suits.
|
|
22
|
+
|
|
23
|
+
The tint existed as the editability affordance (a read-only `InlineStatic` stays flat, so you could
|
|
24
|
+
see what was editable without hovering). That still holds, and reads more plainly: a bordered box
|
|
25
|
+
beside bare text is a stronger signal than a tint. What it also fixes is a fork in the vocabulary —
|
|
26
|
+
a `ChipGroup` sitting in a field row was white-and-bordered next to zinc-50 editors, two species of
|
|
27
|
+
control on one line.
|
|
28
|
+
|
|
29
|
+
- **Rename every `variant="cell"` → `variant="bare"`.** The old literal is a type error, not a
|
|
30
|
+
silent no-op.
|
|
31
|
+
- **`bare` hovers with the BORDER now, not a background wash.** One hover language across the
|
|
32
|
+
kit; the ROW under it still washes as a row, so a task/register row is unaffected.
|
|
33
|
+
- **A `cell` used to read VALUE-FIRST** — the date dropped its resting calendar glyph and the
|
|
34
|
+
select its chevron, on the theory that a column header plus a uniformly-editable grid were
|
|
35
|
+
affordance enough. Both now show on every surface: one control, one promise.
|
|
36
|
+
- **`disabled` still rests FLAT and borderless**, so an inert field never makes the promise.
|
|
37
|
+
- **`InlineButton` inverted with it** — it is `Button secondary`'s zinc-100 fill now, not white,
|
|
38
|
+
and has no border. Its affordance was always CONTRAST with the field beneath it, not a colour;
|
|
39
|
+
a white verb on a white field dissolves.
|
|
40
|
+
|
|
41
|
+
Row hover on a dense surface is unaffected: a `TaskItem`/`PressableRow` still washes as the ROW.
|
|
42
|
+
What changed is only what the editor inside it looks like at rest.
|
|
43
|
+
|
|
44
|
+
## 23.0.0 — `DetailRow.trailing` and `DetailTable.trailingWidth` are DELETED
|
|
45
|
+
|
|
46
|
+
A row's third column is gone; a `DetailTable` is label + value, and the value fills what the
|
|
47
|
+
label leaves. `InlineButton` (`@lotics/ui/inline_button`) is the replacement for the case that
|
|
48
|
+
mattered.
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
// BEFORE — the verb in a column the whole table pays for
|
|
52
|
+
<DetailTable labelWidth={150} trailingWidth={88}>
|
|
53
|
+
<DetailRow label="Reference" trailing={<Button title="Copy" color="secondary" onPress={copy} />}>
|
|
54
|
+
<InlineTextInput value={ref} onSave={save} />
|
|
55
|
+
</DetailRow>
|
|
56
|
+
<DetailRow label="Priority"><InlineSelect … /></DetailRow> {/* pays 88px, uses none */}
|
|
57
|
+
</DetailTable>
|
|
58
|
+
|
|
59
|
+
// AFTER — the verb on the field it acts on
|
|
60
|
+
<DetailTable labelWidth={150}>
|
|
61
|
+
<DetailRow label="Reference">
|
|
62
|
+
<InlineTextInput value={ref} onSave={save}
|
|
63
|
+
actions={<InlineButton title="Copy" disabled={!ref} onPress={copy} />} />
|
|
64
|
+
</DetailRow>
|
|
65
|
+
<DetailRow label="Priority"><InlineSelect … /></DetailRow>
|
|
66
|
+
</DetailTable>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`trailingWidth` was declared on the TABLE, so one row's action made EVERY row reserve the
|
|
70
|
+
width — a stack of fields whose values all stopped short of an edge nothing occupied. And the
|
|
71
|
+
control it held was usually about the VALUE, which meant reading a field on the left and
|
|
72
|
+
pairing it with its verb at the page's right edge.
|
|
73
|
+
|
|
74
|
+
Porting, by what the slot held:
|
|
75
|
+
|
|
76
|
+
- **A verb about the value** (Copy, Call, Open) → **`InlineButton`** in the editor's `actions`.
|
|
77
|
+
Pass it UNCONDITIONALLY and `disabled` it when there is nothing to act on: a slot that
|
|
78
|
+
appears once the value is non-empty resizes the field as the user types. `actions` is on
|
|
79
|
+
`InlineTextInput` and on the `InlineEditView` / `InlineEditFrame` engine that custom editors
|
|
80
|
+
build on.
|
|
81
|
+
- **A verb the editor can't host** — the select/date editors pass their ref to a `Popover` as
|
|
82
|
+
its anchor — → compose it into the VALUE cell: a `flexDirection: "row"` with the editor on
|
|
83
|
+
`flex: 1` and the verb beside it. One row deep, no column.
|
|
84
|
+
- **A verb about the FORM, not the value** (a "Fetch" that fills three other fields) → the same
|
|
85
|
+
value-cell composition, or the surface's own footer. It was never a field's verb.
|
|
86
|
+
- **A `Badge` or other qualifier** → beside the value in the value cell. It was never a column.
|
|
87
|
+
- **Units** — already excluded before this release: `InlineNumberInput format`.
|
|
88
|
+
|
|
89
|
+
`DetailRow` keeps `labelWidth`, `labelSize`, `minHeight`, `flat`, and the annotation trio
|
|
90
|
+
(`description` / `warning` / `error`).
|
|
91
|
+
|
|
92
|
+
## 23.0.0 — `LinkedRecordBox` is DELETED; a reference is a field
|
|
93
|
+
|
|
94
|
+
```tsx
|
|
95
|
+
// BEFORE — a bordered card, its own section, three surfaces for one name
|
|
96
|
+
<LinkedRecordBox
|
|
97
|
+
icon="building-2" name={c.name} subtitle={c.code}
|
|
98
|
+
facts={[{ label: "Tax ID", value: c.taxId }, { label: "Contact", value: c.contact }]}
|
|
99
|
+
doorLabel={`${c.name} — details`} onOpen={open}
|
|
100
|
+
actions={<><Button title="Remove" color="danger" onPress={detach} /><View style={{ flex: 1 }} /><Button title="Open record" color="secondary" onPress={open} /></>}
|
|
101
|
+
/>
|
|
102
|
+
|
|
103
|
+
// AFTER — a value in a row, in whatever section the reference belongs to.
|
|
104
|
+
// It wears the field surface, carries its go-to verb INSIDE, and peeks its
|
|
105
|
+
// facts on press; detach lives in the peek. `tpl_record`'s `ReferenceValue`
|
|
106
|
+
// is the worked composition.
|
|
107
|
+
<DetailRow label="Customer">
|
|
108
|
+
<ReferenceValue name={c.name} code={c.code} facts={…} onOpen={open} onRemove={detach} />
|
|
109
|
+
</DetailRow>
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
There is no replacement component, because the kit already had the answer and this was the
|
|
113
|
+
exception to it: a person renders as a `MemberChip`, a file as a `FileBadge`, a select option
|
|
114
|
+
as an `OptionBadge`, and a picked value in a field as a `<Chip onDismiss>` (the tags pattern).
|
|
115
|
+
A record was the one reference drawn as a card — an icon tile, a facts grid and an action
|
|
116
|
+
footer for a single name — which made a pointer to another row outweigh the fields it sat
|
|
117
|
+
among and pushed hosts into giving it a whole Section.
|
|
118
|
+
|
|
119
|
+
Porting, piece by piece:
|
|
120
|
+
|
|
121
|
+
- **`icon`** — drop it. The label already names what the reference is; a glyph at value
|
|
122
|
+
altitude is decoration. (Keep one only where the *kind* varies row to row.)
|
|
123
|
+
- **`name` + `subtitle`** — both go INSIDE the pill, name in default ink, subtitle muted. A
|
|
124
|
+
code sitting outside the chip reads as an orphan next to a link.
|
|
125
|
+
- **`facts`** — they were the other record's fields, which never belonged on this one. A fact
|
|
126
|
+
THIS record actually uses (a tax id that gates invoicing) becomes this record's own
|
|
127
|
+
`DetailRow`, or the reference row's `warning` when it is a problem; the rest lives on the
|
|
128
|
+
record `Open` goes to.
|
|
129
|
+
- **`onOpen` / `doorLabel`** — an **`InlineButton`** ("Open") INSIDE the value's surface. The
|
|
130
|
+
whole-box door is gone, but the a11y contract it owned is not: a container with its own
|
|
131
|
+
controls is still a role-less surface + a `PressDoor` sibling, which is what makes pressing
|
|
132
|
+
the value (to peek) and pressing Open two separate acts.
|
|
133
|
+
- **`actions`** — the destructive verb moves into the PEEK's footer (destructive left, go-to
|
|
134
|
+
right), where it answers the question the peek asks. A detach link repeated down a column of
|
|
135
|
+
references is noise for an act most readers never perform.
|
|
136
|
+
- **The STATIC variant** (no `onOpen`, fact values as nodes with inline editors) has no
|
|
137
|
+
successor by design. A record with no surface of its own has no identity to reference — its
|
|
138
|
+
values simply ARE this record's fields, so render them as a `Subsection` of `DetailRow`s with
|
|
139
|
+
no box around them.
|
|
140
|
+
- **A whole Section built around one reference** collapses into the row. Its find-or-create
|
|
141
|
+
`Combobox` is the field's EMPTY state (same value slot), its create `Dialog` stays a dialog,
|
|
142
|
+
and its validity `Callout` becomes `DetailRow warning`. Remove the section's outline-rail
|
|
143
|
+
entry with it.
|
|
144
|
+
|
|
145
|
+
`tpl_record`'s Customer and Handoff sections are the worked examples.
|
|
146
|
+
|
|
7
147
|
## 22.0.0 — `RangeSlider` is `Slider`, and single-value is a mode on it
|
|
8
148
|
|
|
9
149
|
```ts
|
|
@@ -53,7 +193,7 @@ values it was missing.
|
|
|
53
193
|
|
|
54
194
|
## v21 from 20.x
|
|
55
195
|
|
|
56
|
-
**`FilesEditor` is a COMPOUND.** It rendered a fixed toolbar — Upload
|
|
196
|
+
**`FilesEditor` is a COMPOUND.** It rendered a fixed toolbar — Upload, Select, Download all,
|
|
57
197
|
swapping into a select-mode row whose actions hid behind a generic "Menu" — and that shape cost
|
|
58
198
|
two things in real screens. A HOST verb had nowhere to go, so a surface that needed one (an AI
|
|
59
199
|
read over the picked papers, "send these to the broker") hand-rolled the whole grid and lost the
|
|
@@ -90,7 +230,7 @@ the files is now composed below it.
|
|
|
90
230
|
| `onDownloadZipSelected` | the same |
|
|
91
231
|
| `readOnly` | withhold `onAdd`/`onRemove`; the pieces render nothing without a handler, so the composition IS the read-only shape and there is no second mode to keep in sync |
|
|
92
232
|
| the "Menu" popover | the bar. Actions are visible controls, in the order the surface wants them |
|
|
93
|
-
| `labels.menu
|
|
233
|
+
| `labels.menu`, `labels.share`, `labels.downloadZip` | deleted with the acts they named |
|
|
94
234
|
|
|
95
235
|
**No children means no bar** — a grid that previews and nothing else. That is the one rendering
|
|
96
236
|
path; there is no default toolbar to fall back to.
|
package/docs/ai_patterns.md
CHANGED
|
@@ -21,15 +21,15 @@ the human stays in charge follows the stakes — split by whether a before-state
|
|
|
21
21
|
is nothing to diff → **apply directly, then end on the RECEIPT**
|
|
22
22
|
(`@lotics/ui/result_header`) — the receipt states the outcome and ROUTES; it is never a
|
|
23
23
|
record editor. Run DETERMINISTIC checks over what the save STORED (a checksum, a count
|
|
24
|
-
reconciliation — binary math, never a fabricated score). ONE record: `ResultHeader` (tone
|
|
25
|
-
outcome title) → the RECEIPT LINES — a `DetailTable` of spread `DetailRow`s (who
|
|
26
|
-
much
|
|
24
|
+
reconciliation — binary math, never a fabricated score). ONE record: `ResultHeader` (tone,
|
|
25
|
+
outcome title) → the RECEIPT LINES — a `DetailTable` of spread `DetailRow`s (who, how
|
|
26
|
+
much, how many, the schedule) — → **`Confidence`**: the level WITH its basis as
|
|
27
27
|
one block, always (the happy path says what was checked; the flagged path NAMES the exact
|
|
28
28
|
failing values — the user knows what to verify BEFORE opening). Confidence never floats
|
|
29
29
|
alone as a bare meter on a result surface. NOTHING in the receipt edits: the RECORD is the edit surface (its
|
|
30
30
|
flagged cells carry the same amber marks), one press away — correction uses the record's
|
|
31
31
|
ordinary verbs. SEVERAL records: a compact attention-first RESULT REGISTER (`ListItem` per
|
|
32
|
-
record — tone mark
|
|
32
|
+
record — tone mark, outcome title, key figures, the needs-checking count) whose rows
|
|
33
33
|
press STRAIGHT THROUGH to the record — no intermediate screen. Never tabs (they cap out),
|
|
34
34
|
never stacked collapsed cards, never a field wall duplicating the record page. A
|
|
35
35
|
flagged value names its exact verdict in amber (a reason line under the value, or a check
|
|
@@ -69,7 +69,7 @@ Three shapes:
|
|
|
69
69
|
the thread, version chains, branching, session memory. An in-app "edit chat" would
|
|
70
70
|
re-implement all of that inside every app.
|
|
71
71
|
|
|
72
|
-
The Document desk's Use-AI fork IS this table as UI: Extract data (1)
|
|
72
|
+
The Document desk's Use-AI fork IS this table as UI: Extract data (1), Cross-check (2),
|
|
73
73
|
Edit with AI (3) — one entry point, three outcome shapes
|
|
74
74
|
([`tpl_record`](../examples/tpl_record.tsx)'s Documents section).
|
|
75
75
|
|
|
@@ -151,7 +151,7 @@ Output panel; `undefined` keeps it. Input + error rendering are untouched.
|
|
|
151
151
|
**Activity grouping.** Consecutive tool parts fold into ONE group. While the agent is mid-tools
|
|
152
152
|
the tail group is a SINGLE pulsing row whose label swaps in place as each call fires (no growing
|
|
153
153
|
stack of dots); once prose resumes the group settles: a single call becomes one done row, and a
|
|
154
|
-
multi-call group becomes a persistent "{final action}
|
|
154
|
+
multi-call group becomes a persistent "{final action} ({n} steps)" HEADER (a `complete` terminal
|
|
155
155
|
dot — distinct from the filled `done` step dots; amber `warning` if any call errored) that STAYS
|
|
156
156
|
PUT and rolls the calls out BELOW it on press. The run ALWAYS ends on the agent's text — there is
|
|
157
157
|
no global terminal node.
|
|
@@ -292,22 +292,22 @@ composes from twelve pieces in three groups (all in `@lotics/ui/change_review`;
|
|
|
292
292
|
- **`ChangeFields` + `ChangeField`** — THE field unit. `ChangeFields` is the OPEN form (the
|
|
293
293
|
section IS the record — an extract dialog's one order: no card chrome), stacking `ChangeField`s
|
|
294
294
|
with hairline rules. A diff-form `ChangeField` renders, top to bottom: the label (sm medium,
|
|
295
|
-
**full colour** — it names the subject of a decision, never `DetailRow`'s muted ink)
|
|
296
|
-
field's `reasoning` directly under the label
|
|
295
|
+
**full colour** — it names the subject of a decision, never `DetailRow`'s muted ink), the
|
|
296
|
+
field's `reasoning` directly under the label, the `−` band when replacing (`before`), the
|
|
297
297
|
value — `ChangeValueInput` when `onChangeText` is given (the green `+` band; pressing it edits
|
|
298
298
|
IN THE BAND — a borderless input with identical type metrics, so nothing shifts), the read-only
|
|
299
299
|
`+` band when `valueReadOnly` or no `onChangeText` (muted `placeholder` while empty), or any
|
|
300
300
|
input via `children` — compose `<ChangeValueInput unit="pcs" …>` there yourself for a unit
|
|
301
301
|
suffix (`unit` fixes the suffix outside the editable core — type the number, never the unit;
|
|
302
|
-
the built-in default doesn't take it)
|
|
302
|
+
the built-in default doesn't take it), conflict `candidates` as full-width decision rows
|
|
303
303
|
(picked via `onPickCandidate`) + the localized "Type another value" third option
|
|
304
304
|
(`customValue`/`customSelected`/`onCustomValue`/`onCustomSelect`; the outcome band is read-only
|
|
305
305
|
via `valueReadOnly` — the decision comes from picking, never from editing the band; gate with
|
|
306
|
-
`keepDisabled`)
|
|
306
|
+
`keepDisabled`), per-field **Keep/Drop** bottom-right
|
|
307
307
|
(`status: "pending" | "kept" | "dropped"`, `onKeep`/`onDrop`/`onUndo`). A pure REMOVAL is
|
|
308
308
|
`before` with no value — the `−` band alone. A decided field collapses to the compact one-row
|
|
309
|
-
card (mark
|
|
310
|
-
inline label
|
|
309
|
+
card (mark, label → `summary`, Undo). A field with no diff and no decision is the plain
|
|
310
|
+
inline label, value row — this form borrows `DetailRow`'s *metrics* (130px label column /
|
|
311
311
|
40px row) — press-to-edit when `onChangeText` is given.
|
|
312
312
|
|
|
313
313
|
**Limitation:** `ChangeFieldCandidate.source` and `.description` are accepted by the type but
|
|
@@ -432,8 +432,8 @@ meter + level phrase head the block, and the REQUIRED `children` carry the basis
|
|
|
432
432
|
checked and what came of it ("all 7 references pass their checksum" / "2 of 7 fail (X, Y) —
|
|
433
433
|
verify against the source"). The box stays white with a hairline border at EVERY level — the
|
|
434
434
|
meter is the only colored element (the level already lives in the meter and the phrase; a
|
|
435
|
-
tinted fill would say it a third time). Pass `level` or a 0–1 `score` (≥0.8 high
|
|
436
|
-
≥0.5 medium
|
|
435
|
+
tinted fill would say it a third time). Pass `level` or a 0–1 `score` (≥0.8 high,
|
|
436
|
+
≥0.5 medium, else low; `levelFromScore` exported). There is NO standalone meter: a level
|
|
437
437
|
without its reasons cannot be acted on, so it cannot be rendered — and where a compact meter
|
|
438
438
|
used to decorate a ranked row or a proposal card, remove it (rank, badges, and severity
|
|
439
439
|
already convey standing). Derive levels HONESTLY (deterministic checks: all pass → high, any
|
|
@@ -442,16 +442,16 @@ fail → low) — never render a fabricated score.
|
|
|
442
442
|
## Findings — evidence, not writes
|
|
443
443
|
|
|
444
444
|
`Finding` (`@lotics/ui/finding`) is one ranked insight from an AI check — a cross-check
|
|
445
|
-
discrepancy, an audit observation, a briefing item: severity dot-badge + localized word
|
|
446
|
-
`title
|
|
445
|
+
discrepancy, an audit observation, a briefing item: severity dot-badge + localized word,
|
|
446
|
+
`title`, `detail`, the PROMINENT `metric` (lg semibold, never a side note) + `metricCaption`,
|
|
447
447
|
`Sources` chips at the bottom (`sources`/`onOpenSource`), with a `children` slot between body and
|
|
448
|
-
sources. Severity → colour: `critical` red
|
|
448
|
+
sources. Severity → colour: `critical` red, `warning` amber, `info` zinc ("Note"), `positive`
|
|
449
449
|
emerald ("On track"); words come from the `finding` locale slice. **Display-only**: a finding
|
|
450
450
|
informs the action the human takes in the app; it decides nothing itself — no phantom "record
|
|
451
451
|
verdict" write (a persisted check-status goes stale on the next edit). Stack several most-severe
|
|
452
452
|
first — inside a `ChangeReview` wrap each in a display-only `Change` (the family's dividers
|
|
453
453
|
apply). `FindingComparison` is the expected-vs-actual body: each disagreeing side a labeled row
|
|
454
|
-
(source
|
|
454
|
+
(source, value), a hairline, then the DELTA emphasized — compose it as the finding's children
|
|
455
455
|
for any one-value-disagrees insight (quantities, totals, dates).
|
|
456
456
|
|
|
457
457
|
## Session, not chat
|
|
@@ -496,10 +496,10 @@ ranked set, don't cram it into chat prose:
|
|
|
496
496
|
document-driven records) — the record's files block feeds ONE "Use AI" entry that FORKS into
|
|
497
497
|
the two document tasks, each a specialized run with a task-pure result: **Extract** (files
|
|
498
498
|
read → fields already matching fold into one quiet line → every add / update / conflict a
|
|
499
|
-
`ChangeField` (the `−` band
|
|
499
|
+
`ChangeField` (the `−` band, the editable value, candidate rows), the record's current value
|
|
500
500
|
a first-class choice — plus proposed new lines as record-body `Change`s → one outcome-named
|
|
501
501
|
`ChangeReviewActions` commit) and **Cross-check** (documents compared against the record and
|
|
502
|
-
each other → ranked `Finding`s — severity
|
|
502
|
+
each other → ranked `Finding`s — severity, title, the prominent metric, sources — separated
|
|
503
503
|
by hairlines; the findings ARE the outcome the human acts on). The fork carries an OPTIONAL
|
|
504
504
|
instructions field — the user steers what the agent checks or extracts, so `Finding` serves ANY
|
|
505
505
|
file-based AI request, not just the stock cross-check. Every file list in the flow opens the
|
|
@@ -530,7 +530,7 @@ ranked set, don't cram it into chat prose:
|
|
|
530
530
|
The AI vocabulary has **no purple accent and no gimmick glyphs** (no sparkles) — but it is NOT
|
|
531
531
|
monochrome: **colour is used where it carries meaning, not for decoration.** What the violet
|
|
532
532
|
sparkle used to carry now reads structurally — **provenance** is a quiet sentence-case microlabel
|
|
533
|
-
naming the artifact ("Proposed"
|
|
533
|
+
naming the artifact ("Proposed", "Match", "Mismatch", "Suggested edit", "Question" — xs,
|
|
534
534
|
muted, medium; all-caps is banned kit-wide), and the agent's **reasoning** is a left-ruled margin
|
|
535
535
|
note (a hairline rule + muted text — `ChangeReasoning`), quoted apart from the facts and the
|
|
536
536
|
human's controls — while **status/severity/diffs use functional colour** the way the rest of the
|
|
@@ -546,7 +546,7 @@ kit does:
|
|
|
546
546
|
- **ChangeBand** — the removed value on the light **red** band with the `−` marker, the incoming
|
|
547
547
|
value on the light **emerald** band with `+` (the GitHub-diff idiom, markers in one aligned
|
|
548
548
|
column); everything else in a review stays neutral — a decided row reads a single emerald
|
|
549
|
-
check, an add/remove record card wears the quiet tone wash (50 body
|
|
549
|
+
check, an add/remove record card wears the quiet tone wash (50 body, 100 header, 200 border).
|
|
550
550
|
Colour marks the change, never the chrome.
|
|
551
551
|
- **Finding severity** — the coloured dot badge (red / amber / zinc / emerald), most severe
|
|
552
552
|
first.
|