@lotics/ui 12.1.0 → 12.1.2

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/docs/catalog.md CHANGED
@@ -934,9 +934,11 @@ source (`src/<module>.tsx`/`.ts`) is the API reference.
934
934
  `ChangeRecord` (THE item card: registers like a Change; tone wash + localized op word;
935
935
  verb level follows the decision level) · `ChangeBand` (the raw ± band) ·
936
936
  `ChangeValueInput` (the diff-at-rest editor); the `changeReview` locale slice.
937
- - **`clarify`** — `Clarify`: the agent asks back, via `ChoiceList`.
938
- - **`choice_list`** — `ChoiceList` + `ChoiceOption`: selectable answer options, the agent's
939
- quick-reply surface.
937
+ - **`clarify`** — `Clarify`: the agent asks back a borderless block (question + a
938
+ `ChoiceList`), no card wrapper.
939
+ - **`choice_list`** — `ChoiceList` + `ChoiceOption`: selectable answer options as
940
+ divider-separated rows (no bordered cards) with a per-row focus ring + hover wash; the
941
+ agent's quick-reply surface.
940
942
  - **`sources`** — `Sources` + `SourceRef`/`SourceKind` (record | document | table | web |
941
943
  knowledge): provenance chips, per-kind glyphs.
942
944
  - **`finding`** — `Finding` + `FindingComparison` + `FindingSeverity`/`FindingLabels`: one
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lotics/ui",
3
- "version": "12.1.0",
3
+ "version": "12.1.2",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./vite": {
@@ -1,8 +1,10 @@
1
- import { StyleSheet, View } from "react-native";
1
+ import { Pressable, View } from "react-native";
2
2
  import { colors } from "./colors";
3
3
  import { Text } from "./text";
4
4
  import { Icon } from "./icon";
5
- import { CardSelectItem } from "./card_select_item";
5
+ import { Divider } from "./divider";
6
+ import { useFocusRing } from "./use_focus_ring";
7
+ import { FOCUS_RING } from "./control_surface";
6
8
 
7
9
  export interface ChoiceOption {
8
10
  label: string;
@@ -18,46 +20,55 @@ export interface ChoiceListProps {
18
20
  onSelect: (value: string) => void;
19
21
  }
20
22
 
23
+ /** One selectable option — a role-less-free `Pressable` (its own accessible name
24
+ * + selected state), hover wash + focus ring, no border. */
25
+ function ChoiceRow({ option, selected, onSelect }: { option: ChoiceOption; selected: boolean; onSelect: (value: string) => void }) {
26
+ const { focusVisible, focusProps } = useFocusRing();
27
+ return (
28
+ <Pressable
29
+ accessibilityRole="button"
30
+ accessibilityLabel={option.label}
31
+ accessibilityState={{ selected }}
32
+ onPress={() => onSelect(option.value)}
33
+ {...focusProps}
34
+ style={({ hovered, pressed }) => [
35
+ { flexDirection: "row", alignItems: "center", gap: 12, paddingVertical: 14, paddingHorizontal: 6, borderRadius: 8 },
36
+ hovered || pressed ? { backgroundColor: colors.zinc[50] } : null,
37
+ focusVisible ? { boxShadow: FOCUS_RING } : null,
38
+ ]}
39
+ >
40
+ <View style={{ flex: 1, gap: 3, minWidth: 0 }}>
41
+ <Text size="sm" weight={selected ? "semibold" : "medium"}>
42
+ {option.label}
43
+ </Text>
44
+ {option.description ? (
45
+ <Text size="xs" color="muted">
46
+ {option.description}
47
+ </Text>
48
+ ) : null}
49
+ </View>
50
+ {selected ? <Icon name="check" size={17} color={colors.zinc[900]} /> : null}
51
+ </Pressable>
52
+ );
53
+ }
54
+
21
55
  /**
22
- * A vertical set of selectable answer options — bordered cards with the global
23
- * focus/hover/selected ring (`CardSelectItem`), single-select and freely
24
- * switchable (pick a different option any time). The chosen card shows a check.
25
- * The agent's quick-reply surface (`Clarify` uses it) and any "pick one"
56
+ * A vertical set of selectable answer options — divider-separated rows (no
57
+ * bordered cards), each with its own focus ring + hover wash, single-select and
58
+ * freely switchable (pick a different option any time). The chosen row shows a
59
+ * check. The agent's quick-reply surface (`Clarify` uses it) and any "pick one"
26
60
  * question.
27
61
  */
28
62
  export function ChoiceList(props: ChoiceListProps) {
29
63
  const { options, value, onSelect } = props;
30
64
  return (
31
- <View style={{ gap: 8 }}>
32
- {options.map((o) => {
33
- const selected = value === o.value;
34
- return (
35
- <CardSelectItem
36
- key={o.value}
37
- selected={selected}
38
- onPress={() => onSelect(o.value)}
39
- accessibilityLabel={o.label}
40
- style={styles.item}
41
- >
42
- <View style={styles.text}>
43
- <Text size="sm" weight="medium">
44
- {o.label}
45
- </Text>
46
- {o.description ? (
47
- <Text size="xs" color="muted">
48
- {o.description}
49
- </Text>
50
- ) : null}
51
- </View>
52
- {selected ? <Icon name="check" size={16} color={colors.zinc[900]} /> : null}
53
- </CardSelectItem>
54
- );
55
- })}
65
+ <View>
66
+ {options.map((o, i) => (
67
+ <View key={o.value}>
68
+ {i > 0 ? <Divider /> : null}
69
+ <ChoiceRow option={o} selected={value === o.value} onSelect={onSelect} />
70
+ </View>
71
+ ))}
56
72
  </View>
57
73
  );
58
74
  }
59
-
60
- const styles = StyleSheet.create({
61
- item: { flexDirection: "row", alignItems: "center", gap: 10, paddingVertical: 11, paddingHorizontal: 14 },
62
- text: { flex: 1, gap: 2 },
63
- });
package/src/clarify.tsx CHANGED
@@ -1,5 +1,4 @@
1
- import { StyleSheet, View } from "react-native";
2
- import { colors } from "./colors";
1
+ import { View } from "react-native";
3
2
  import { Text } from "./text";
4
3
  import { ChoiceList, type ChoiceOption } from "./choice_list";
5
4
 
@@ -16,33 +15,24 @@ export interface ClarifyProps {
16
15
  }
17
16
 
18
17
  /**
19
- * The agent asks BACK — a question with selectable answer options (`ChoiceList`)
20
- * the human picks before the run continues, freely switchable until committed.
18
+ * The agent asks BACK — a question with selectable answer options the human picks
19
+ * before the run continues, freely switchable until committed. A borderless block
20
+ * (no card): the question, then divider-separated option rows (`ChoiceList`).
21
21
  * Human-in-the-loop input: when the agent is unsure, it clarifies instead of
22
- * guessing wrong. The run pauses on this and `onAnswer` resumes it. Pair with
23
- * `AgentRun` / `AgentProgress`.
22
+ * guessing wrong. Pair with `AgentRun` / `AgentProgress`.
24
23
  */
25
24
  export function Clarify(props: ClarifyProps) {
26
25
  return (
27
- <View style={styles.card}>
28
- <Text size="xs" color="muted" weight="medium">
29
- Question
30
- </Text>
31
- <Text size="sm" weight="medium">
32
- {props.question}
33
- </Text>
26
+ <View style={{ gap: 14 }}>
27
+ <View style={{ gap: 4 }}>
28
+ <Text size="xs" color="muted" weight="medium">
29
+ Question
30
+ </Text>
31
+ <Text size="sm" weight="medium">
32
+ {props.question}
33
+ </Text>
34
+ </View>
34
35
  <ChoiceList options={props.options} value={props.answer} onSelect={props.onAnswer} />
35
36
  </View>
36
37
  );
37
38
  }
38
-
39
- const styles = StyleSheet.create({
40
- card: {
41
- borderWidth: 1,
42
- borderColor: colors.border,
43
- backgroundColor: colors.white,
44
- borderRadius: 12,
45
- padding: 16,
46
- gap: 12,
47
- },
48
- });
@@ -6,6 +6,29 @@ import { gfmTaskListItemFromMarkdown } from "mdast-util-gfm-task-list-item";
6
6
  import { gfm } from "micromark-extension-gfm";
7
7
  import type { Plugin } from "unified";
8
8
 
9
+ // A micromark syntax extension is exactly what `gfm()` produces; deriving the type
10
+ // from the imported value keeps this dependency-free (`micromark-util-types` is
11
+ // only a transitive dep) while staying the true type the registry holds.
12
+ type MicromarkExtension = ReturnType<typeof gfm>;
13
+
14
+ // `unified`'s `Data` interface ships bare (`{ settings? }`). `remark-parse` is what
15
+ // normally augments it with the two extension registries a `fromMarkdown` plugin
16
+ // writes into via `this.data()` — but this module composes GFM from its parts
17
+ // precisely so it never imports the `remark-gfm`/autolink-literal graph, and it
18
+ // doesn't import `remark-parse` either, so nothing else in a consumer's compile
19
+ // graph declares them. We restate the ecosystem's canonical augmentation here so
20
+ // the writes below type-check for every app that pulls this file in through
21
+ // `<Markdown>` (without it, `tsc` throws TS2339 on the whole app). Types mirror
22
+ // the consumers: `micromarkExtensions` holds micromark `Extension`s;
23
+ // `fromMarkdownExtensions` mirrors `mdast-util-from-markdown`'s `mdastExtensions`
24
+ // shape (`Extension | Extension[]`), which is what we push a nested list into below.
25
+ declare module "unified" {
26
+ interface Data {
27
+ micromarkExtensions?: MicromarkExtension[];
28
+ fromMarkdownExtensions?: Array<Extension | Extension[]>;
29
+ }
30
+ }
31
+
9
32
  /**
10
33
  * `remark-gfm`, rebuilt so no regex lookbehind reaches the bundle.
11
34
  *