@lotics/ui 7.19.3 → 9.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.
Files changed (75) hide show
  1. package/AGENTS.md +298 -159
  2. package/examples/tpl_allocate.tsx +2 -2
  3. package/examples/tpl_attendance.tsx +2 -2
  4. package/examples/tpl_calendar.tsx +1 -1
  5. package/examples/tpl_dashboard.tsx +1 -1
  6. package/examples/tpl_dieline.tsx +3 -3
  7. package/examples/tpl_documents.tsx +790 -0
  8. package/examples/tpl_item_list.tsx +1015 -124
  9. package/examples/tpl_lookup.tsx +37 -10
  10. package/examples/tpl_pick.tsx +3 -3
  11. package/examples/tpl_pivot.tsx +1 -1
  12. package/examples/tpl_record.tsx +1354 -0
  13. package/examples/tpl_report.tsx +7 -7
  14. package/examples/tpl_rollup.tsx +6 -6
  15. package/examples/tpl_shifts.tsx +2 -2
  16. package/examples/tpl_statements.tsx +221 -0
  17. package/examples/tpl_stock.tsx +7 -7
  18. package/examples/tpl_task_board.tsx +48 -32
  19. package/examples/tpl_tasks.tsx +47 -47
  20. package/examples/tpl_tower.tsx +2 -2
  21. package/package.json +9 -9
  22. package/src/agent_run.tsx +1 -1
  23. package/src/capture_row.tsx +59 -0
  24. package/src/change_review.tsx +732 -236
  25. package/src/checklist.tsx +104 -0
  26. package/src/chip.tsx +12 -3
  27. package/src/composer.tsx +22 -1
  28. package/src/confidence.tsx +1 -1
  29. package/src/control_surface.ts +0 -14
  30. package/src/detail_row.tsx +137 -10
  31. package/src/finding.tsx +112 -80
  32. package/src/floating_action_bar.tsx +1 -1
  33. package/src/inline_date_picker.tsx +8 -3
  34. package/src/inline_edit.tsx +40 -10
  35. package/src/inline_member_select.tsx +3 -0
  36. package/src/inline_number_input.tsx +5 -2
  37. package/src/inline_select.tsx +8 -3
  38. package/src/inline_tag_select.tsx +140 -0
  39. package/src/inline_text_input.tsx +5 -2
  40. package/src/inline_time_picker.tsx +5 -2
  41. package/src/ledger.tsx +220 -0
  42. package/src/locale.tsx +43 -16
  43. package/src/progress_bar.tsx +32 -1
  44. package/src/record_summary.tsx +101 -0
  45. package/src/section_heading.tsx +16 -8
  46. package/src/sources.tsx +8 -5
  47. package/src/suggestion_chip.tsx +47 -0
  48. package/src/use_section_nav.test.ts +69 -0
  49. package/src/use_section_nav.ts +59 -0
  50. package/examples/tpl_assistant.tsx +0 -174
  51. package/examples/tpl_billing.tsx +0 -344
  52. package/examples/tpl_briefing.tsx +0 -121
  53. package/examples/tpl_compare.tsx +0 -133
  54. package/examples/tpl_crosscheck.tsx +0 -120
  55. package/examples/tpl_detail.tsx +0 -232
  56. package/examples/tpl_directory.tsx +0 -260
  57. package/examples/tpl_draft.tsx +0 -163
  58. package/examples/tpl_extract.tsx +0 -193
  59. package/examples/tpl_intake.tsx +0 -206
  60. package/examples/tpl_match.tsx +0 -134
  61. package/examples/tpl_order.tsx +0 -482
  62. package/examples/tpl_quick.tsx +0 -211
  63. package/examples/tpl_ratedesk.tsx +0 -386
  64. package/examples/tpl_record_plain.tsx +0 -259
  65. package/examples/tpl_settings.tsx +0 -178
  66. package/examples/tpl_timeline.tsx +0 -244
  67. package/examples/tpl_triage.tsx +0 -112
  68. package/examples/tpl_wizard.tsx +0 -223
  69. package/src/discrepancy.tsx +0 -114
  70. package/src/match_sides.tsx +0 -79
  71. package/src/record_fields.tsx +0 -68
  72. package/src/review_card.tsx +0 -172
  73. package/src/scored_option.tsx +0 -138
  74. package/src/spec_list.tsx +0 -81
  75. package/src/triage_row.tsx +0 -99
@@ -7,7 +7,6 @@ import { Callout, CalloutText, CalloutTitle } from "@lotics/ui/callout";
7
7
  import { PressableHighlight } from "@lotics/ui/pressable_highlight";
8
8
  import { Composer } from "@lotics/ui/composer";
9
9
  import { AgentRun, type AgentRunStep, type AgentRunItem } from "@lotics/ui/agent_run";
10
- import { SpecList, type SpecRow } from "@lotics/ui/spec_list";
11
10
  import { Confidence, type ConfidenceLevel } from "@lotics/ui/confidence";
12
11
  import { Badge } from "@lotics/ui/badge";
13
12
  import { Sources, type SourceRef } from "@lotics/ui/sources";
@@ -19,7 +18,7 @@ import { Sources, type SourceRef } from "@lotics/ui/sources";
19
18
  // single confident verdict: classification is ambiguous, so the alternatives are
20
19
  // first-class (the prep/pack push the goods to a different code with a different
21
20
  // duty). The answer is a panel of scannable components — the code, the exact duty
22
- // breakdown (SpecList), the policies, the sources. Refine the description ("what
21
+ // breakdown (hand-composed spec rows), the policies, the sources. Refine the description ("what
23
22
  // if it's pre-cooked?") and the ranking updates. Same shape for any
24
23
  // look-up-and-explain: tariff/HS, fee lookup, policy Q&A, a spec/compliance desk.
25
24
  // ─────────────────────────────────────────────────────────────────────────────
@@ -46,7 +45,6 @@ interface Candidate {
46
45
  // One query, several plausible HS codes — the agent RANKS them; the declarant
47
46
  // picks. The prep and the pack push the goods to a different code with a
48
47
  // different duty, which is exactly why a single confident verdict is wrong.
49
- const QUERY = "Black tiger shrimp, headless shell-on, IQF frozen, 1 kg retail packs";
50
48
 
51
49
  const CANDIDATES: Candidate[] = [
52
50
  {
@@ -204,9 +202,11 @@ export function TplLookup() {
204
202
  {/* current run */}
205
203
  <AgentRun items={items} state={streaming ? "streaming" : "done"} />
206
204
 
205
+ {/* Matches surface only once the run settles — the agent's output,
206
+ never a pre-filled list; they sit at the bottom, under the run. */}
207
+ {phase === "ready" ? (
207
208
  <View style={{ gap: 8 }}>
208
209
  <Text size="xs" color="muted" weight="medium">Nearest matches</Text>
209
- <Text size="xs" color="muted" numberOfLines={2}>{QUERY}</Text>
210
210
  {CANDIDATES.map((c) => (
211
211
  <PressableHighlight
212
212
  key={c.id}
@@ -231,6 +231,7 @@ export function TplLookup() {
231
231
  </PressableHighlight>
232
232
  ))}
233
233
  </View>
234
+ ) : null}
234
235
  </ScrollView>
235
236
 
236
237
  <View style={{ padding: 12, borderTopWidth: 1, borderTopColor: colors.zinc[200] }}>
@@ -247,9 +248,9 @@ export function TplLookup() {
247
248
  {/* ── RIGHT · the pinned structured answer ───────────────────── */}
248
249
  <ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 28, paddingBottom: 48 }}>
249
250
  <View style={{ width: "100%", maxWidth: 720, alignSelf: "center", gap: 16 }}>
250
- <View style={{ borderWidth: 1, borderColor: colors.zinc[200], borderRadius: 16, backgroundColor: colors.white, overflow: "hidden" }}>
251
- {/* verdict header */}
252
- <View style={{ padding: 22, gap: 10, backgroundColor: colors.white, borderBottomWidth: 1, borderBottomColor: colors.zinc[200] }}>
251
+ <View style={{ gap: 4 }}>
252
+ {/* verdict header — open, no card box: the panel IS the answer */}
253
+ <View style={{ paddingVertical: 6, gap: 10 }}>
253
254
  <View style={{ flexDirection: "row", alignItems: "center", gap: 8 }}>
254
255
  <Text size="xs" color="muted" weight="medium" style={{ flex: 1 }}>Suggested HS code</Text>
255
256
  <Confidence level={active.confidence} />
@@ -258,21 +259,22 @@ export function TplLookup() {
258
259
  <Text size="sm" color="muted">{active.heading}</Text>
259
260
  </View>
260
261
 
261
- <View style={{ padding: 22, gap: 18 }}>
262
+ <Divider />
263
+ <View style={{ paddingVertical: 16, gap: 18 }}>
262
264
  <View style={{ borderLeftWidth: 2, borderLeftColor: colors.zinc[300], paddingLeft: 12 }}>
263
265
  <Text size="sm" color="muted">{active.basis}</Text>
264
266
  </View>
265
267
 
266
268
  <View style={{ gap: 8 }}>
267
269
  <Text size="sm" weight="semibold">Duty & tax</Text>
268
- <SpecList rows={active.duty} total={active.dutyTotal} />
270
+ <SpecRows rows={active.duty} total={active.dutyTotal} />
269
271
  </View>
270
272
 
271
273
  <Divider />
272
274
 
273
275
  <View style={{ gap: 8 }}>
274
276
  <Text size="sm" weight="semibold">Classification basis</Text>
275
- <SpecList rows={active.specs} dense />
277
+ <SpecRows rows={active.specs} dense />
276
278
  </View>
277
279
 
278
280
  {active.policies.length > 0 ? (
@@ -300,3 +302,28 @@ export function TplLookup() {
300
302
  </View>
301
303
  );
302
304
  }
305
+
306
+ // The structured label → value breakdown behind the answer — the duty table,
307
+ // the classification basis. Hand-composed two-column rows: hierarchy from
308
+ // weight and tabular figures; the total pins under a divider.
309
+ interface SpecRow { label: string; value: string }
310
+
311
+ function SpecRows({ rows, total, dense }: { rows: SpecRow[]; total?: SpecRow; dense?: boolean }) {
312
+ const line = (row: SpecRow, isTotal?: boolean) => (
313
+ <View key={row.label} style={{ flexDirection: "row", alignItems: "baseline", justifyContent: "space-between", gap: 16, minHeight: dense ? 26 : 32 }}>
314
+ <Text size={dense ? "xs" : "sm"} color={isTotal ? "default" : "muted"} weight={isTotal ? "semibold" : "regular"} numberOfLines={1} style={{ flexShrink: 1 }}>{row.label}</Text>
315
+ <Text size={dense && !isTotal ? "sm" : "md"} weight={isTotal ? "semibold" : "medium"} tabular>{row.value}</Text>
316
+ </View>
317
+ );
318
+ return (
319
+ <View>
320
+ {rows.map((r) => line(r))}
321
+ {total ? (
322
+ <>
323
+ <Divider paddingVertical={dense ? 5 : 7} />
324
+ {line(total, true)}
325
+ </>
326
+ ) : null}
327
+ </View>
328
+ );
329
+ }
@@ -15,7 +15,7 @@ import { Stepper, Step, type StepStatus } from "@lotics/ui/stepper";
15
15
  import { CompletionState } from "@lotics/ui/completion_state";
16
16
 
17
17
  // ─────────────────────────────────────────────────────────────────────────────
18
- // Template · Guided execution — a warehouse PICK RUN. The work is a SEQUENCE of
18
+ // Template · Guided queue — a warehouse PICK RUN. The work is a SEQUENCE of
19
19
  // physical tasks, not a list to browse: the run hands the operator the next bin,
20
20
  // they scan to verify they're at the right shelf, confirm the count, and the
21
21
  // next task takes its place. A single focus column — the CURRENT task is the only
@@ -100,7 +100,7 @@ function CurrentTask({ line, index, total, onConfirm, onShort }: {
100
100
  </View>
101
101
  {/* the bin is the biggest thing on screen — it's where you walk */}
102
102
  <View style={{ gap: 2 }}>
103
- <Text size="xs" color="muted" transform="uppercase">Go to bin</Text>
103
+ <Text size="xs" color="muted" weight="medium">Go to bin</Text>
104
104
  <Text size="xxl" weight="semibold" tabular>{line.bin}</Text>
105
105
  </View>
106
106
  <View style={{ flexDirection: "row", alignItems: "flex-end", gap: 16, flexWrap: "wrap" }}>
@@ -199,7 +199,7 @@ export function TplPick() {
199
199
  {/* header — the wave + the cart it's filling */}
200
200
  <View style={{ flexDirection: "row", alignItems: "flex-end", gap: 12, flexWrap: "wrap" }}>
201
201
  <View style={{ gap: 2, flex: 1 }}>
202
- <Text size="xl" weight="semibold">Pick wave W-0142</Text>
202
+ <Text size="xl" weight="semibold">Queue W-0142</Text>
203
203
  <Text size="sm" color="muted">7 lines for 3 outbound orders · Cart C-07</Text>
204
204
  </View>
205
205
  <Button title="Pause wave" color="muted" onPress={() => {}} />
@@ -14,7 +14,7 @@ import { type MatrixCellRef } from "@lotics/ui/matrix_totals";
14
14
  import { PressableRow } from "@lotics/ui/pressable_row";
15
15
 
16
16
  // ─────────────────────────────────────────────────────────────────────────────
17
- // Template · Pivot desk — one dimension crossed against another, then drill.
17
+ // Template · Pivot — one dimension crossed against another, then drill.
18
18
  // The Matrix is the hero: warehouse × category, the number IN each cell and a
19
19
  // heat wash behind it so the concentration reads at a glance, row/column/grand
20
20
  // totals down the edges. Pressing a cell is a door — the register below filters