@lotics/ui 7.15.0 → 7.17.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 CHANGED
@@ -532,7 +532,8 @@ controls — while **status/severity/diffs use functional colour** the way the r
532
532
  - **Confidence** — a 3-tick meter + the full phrase ("High confidence" / "Medium" / "Low"), emerald /
533
533
  amber / zinc by level; `labels` to translate (one phrase per level).
534
534
  - **Finding severity** — a coloured dot `Badge` + metric: red critical, amber warning, blue note,
535
- emerald on-track (+ stacking order, most severe first).
535
+ emerald on-track (+ stacking order, most severe first). The badge words localize through
536
+ `LoticsLocaleProvider` (`locale.finding`, override per-instance via `labels`) — never hardcode them.
536
537
  - **Stepper / AgentRun nodes** — progress dots on a spine: `current` a **pulsing accent ring** (white
537
538
  centre), `done` a filled accent dot + **white check**, `upcoming` a faint **grey** ring, the terminal
538
539
  `complete` a **blackish ring + black check**, `warning` **amber**. Default accent is neutral ink
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lotics/ui",
3
- "version": "7.15.0",
3
+ "version": "7.17.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./tokens": "./src/tokens.ts",
package/src/finding.tsx CHANGED
@@ -4,11 +4,14 @@ import { Text } from "./text";
4
4
  import { Badge } from "./badge";
5
5
  import { Button } from "./button";
6
6
  import { Sources, type SourceRef } from "./sources";
7
+ import { useLoticsLocale } from "./locale";
7
8
 
8
9
  export type FindingSeverity = "critical" | "warning" | "info" | "positive";
9
10
 
10
11
  export interface FindingProps {
11
12
  severity?: FindingSeverity;
13
+ /** Translated severity words. Defaults resolve through the locale ("Critical" …). */
14
+ labels?: Partial<FindingLabels>;
12
15
  /** The headline — what the agent found. */
13
16
  title: string;
14
17
  /** One or two lines explaining it. */
@@ -28,12 +31,13 @@ export interface FindingProps {
28
31
 
29
32
  // Severity reads through a coloured dot badge + the order it's stacked in (most
30
33
  // severe first): red critical, amber warning, blue note, emerald on-track. The
31
- // metric takes the same colour.
32
- const SEV: Record<FindingSeverity, { word: string; color: ColorName }> = {
33
- critical: { word: "Critical", color: "red" },
34
- warning: { word: "Warning", color: "amber" },
35
- info: { word: "Note", color: "blue" },
36
- positive: { word: "On track", color: "emerald" },
34
+ // metric takes the same colour. Words resolve prop → locale → English default.
35
+ export type FindingLabels = Record<FindingSeverity, string>;
36
+ const SEV_COLOR: Record<FindingSeverity, ColorName> = {
37
+ critical: "red",
38
+ warning: "amber",
39
+ info: "blue",
40
+ positive: "emerald",
37
41
  };
38
42
 
39
43
  /**
@@ -45,7 +49,9 @@ const SEV: Record<FindingSeverity, { word: string; color: ColorName }> = {
45
49
  * carries its own next action.
46
50
  */
47
51
  export function Finding(props: FindingProps) {
48
- const sev = SEV[props.severity ?? "info"];
52
+ const severity = props.severity ?? "info";
53
+ const words = { ...useLoticsLocale().finding, ...props.labels };
54
+ const sev = { word: words[severity], color: SEV_COLOR[severity] };
49
55
  return (
50
56
  <View style={styles.card}>
51
57
  <View style={styles.header}>
package/src/locale.tsx CHANGED
@@ -2,6 +2,7 @@ import { createContext, useContext, type ReactNode } from "react";
2
2
  import { type PaginationLabels } from "./pagination";
3
3
  import { type SortHeaderLabels } from "./sort_header";
4
4
  import { type ConfidenceLabels } from "./confidence";
5
+ import { type FindingLabels } from "./finding";
5
6
  import { type RemainderMeterLabels } from "./remainder_meter";
6
7
  import { type DateRangeFilterFieldLabels } from "./date_range_filter_field";
7
8
 
@@ -36,6 +37,8 @@ export interface LoticsLocale {
36
37
  drawer: { previous: string; next: string; close: string };
37
38
  /** `Confidence`: the full level phrase ("High confidence" …). */
38
39
  confidence: ConfidenceLabels;
40
+ /** `Finding`: the severity badge word ("Critical" …). */
41
+ finding: FindingLabels;
39
42
  /** `RemainderMeter`: the applied / remaining / over / exact captions. */
40
43
  remainderMeter: Required<RemainderMeterLabels>;
41
44
  /** `ChangeReview` (+ `ChangeReviewActions`): the review-card chrome — the
@@ -81,6 +84,7 @@ export const en: LoticsLocale = {
81
84
  formField: { optional: "Optional" },
82
85
  drawer: { previous: "Previous record", next: "Next record", close: "Close" },
83
86
  confidence: { high: "High confidence", medium: "Medium confidence", low: "Low confidence" },
87
+ finding: { critical: "Critical", warning: "Warning", info: "Note", positive: "On track" },
84
88
  remainderMeter: {
85
89
  applied: (allocated, total) => `${allocated} of ${total} applied`,
86
90
  remaining: (remainder) => `${remainder} unapplied`,
@@ -131,6 +135,7 @@ export const vi: LoticsLocale = {
131
135
  formField: { optional: "Tùy chọn" },
132
136
  drawer: { previous: "Bản ghi trước", next: "Bản ghi sau", close: "Đóng" },
133
137
  confidence: { high: "Độ tin cậy cao", medium: "Độ tin cậy trung bình", low: "Độ tin cậy thấp" },
138
+ finding: { critical: "Nghiêm trọng", warning: "Cảnh báo", info: "Ghi chú", positive: "Đúng tiến độ" },
134
139
  remainderMeter: {
135
140
  applied: (allocated, total) => `Đã phân bổ ${allocated}/${total}`,
136
141
  remaining: (remainder) => `Còn ${remainder}`,
package/src/table.tsx CHANGED
@@ -80,30 +80,35 @@ export function Table(props: TableProps) {
80
80
 
81
81
  return (
82
82
  <TableContext.Provider value={{ columns, leading, trailing }}>
83
- <View style={styles.headerBand}>
84
- {leading > 0 ? <View style={{ width: leading }}>{selectAll}</View> : null}
85
- {columns.map((col) => (
86
- <View key={col.key} style={colStyle(col)}>
87
- {col.label ? (
88
- col.sortable && onSort ? (
89
- <SortHeader label={col.label} sortKey={col.key} sort={sort ?? null} onSort={onSort} align={col.align} labels={sortLabels} />
90
- ) : (
91
- <Text size="xs" color="muted" transform="uppercase" numberOfLines={1}>
92
- {col.label}
93
- </Text>
94
- )
95
- ) : null}
96
- </View>
97
- ))}
98
- {trailing > 0 ? <View style={{ width: trailing }} /> : null}
99
- </View>
100
- <View style={styles.body}>
101
- {rows.map((row, i) => (
102
- <View key={i}>
103
- {i > 0 ? <Divider /> : null}
104
- {row}
105
- </View>
106
- ))}
83
+ {/* ONE layout node: without this wrapper the header band + body land as two
84
+ direct flex children of the app's container, and a parent column `gap`
85
+ (the standard section spacing) opens a hole between the header and rows. */}
86
+ <View>
87
+ <View style={styles.headerBand}>
88
+ {leading > 0 ? <View style={{ width: leading }}>{selectAll}</View> : null}
89
+ {columns.map((col) => (
90
+ <View key={col.key} style={colStyle(col)}>
91
+ {col.label ? (
92
+ col.sortable && onSort ? (
93
+ <SortHeader label={col.label} sortKey={col.key} sort={sort ?? null} onSort={onSort} align={col.align} labels={sortLabels} />
94
+ ) : (
95
+ <Text size="xs" color="muted" transform="uppercase" numberOfLines={1}>
96
+ {col.label}
97
+ </Text>
98
+ )
99
+ ) : null}
100
+ </View>
101
+ ))}
102
+ {trailing > 0 ? <View style={{ width: trailing }} /> : null}
103
+ </View>
104
+ <View style={styles.body}>
105
+ {rows.map((row, i) => (
106
+ <View key={i}>
107
+ {i > 0 ? <Divider /> : null}
108
+ {row}
109
+ </View>
110
+ ))}
111
+ </View>
107
112
  </View>
108
113
  </TableContext.Provider>
109
114
  );