@lotics/ui 7.11.0 → 7.12.1

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
@@ -115,7 +115,7 @@ Pick by capability, not by name. (→ the source file for the API.)
115
115
  `PageHeader` /
116
116
  `PageContent`, `Stack`, `Spacer`, `Divider`, `Accordion`, `Tabs`, `SegmentedControl`, `Stepper`,
117
117
  `DangerZone` (the destructive section — delete/archive — set apart at the bottom of a record/settings surface).
118
- - **Rows & registers** — `PressableRow` (THE register row), `ListItem`, `MenuButton`,
118
+ - **Rows & registers** — `PressableRow` (THE register row; forwards its `ref`, so wrapping it in a `PopoverTrigger` anchors a row-triggered peek Popover — without the ref the trigger is unmeasurable and the popover renders off-screen), `ListItem`, `MenuButton`,
119
119
  `MenuListItem`, `DetailRow` (label+value for drawers/peeks; optional `trailing` slot for a
120
120
  right-side action/badge/unit), `ActionMenu` (⋯), `FloatingActionBar` (bulk-select bar).
121
121
  - **Filters & view controls** — `SearchInput`, `ChipGroup`, `FilterChip` (+ `RangeSlider`,
@@ -867,7 +867,7 @@ inline_text_input · inline_number_input · inline_select · inline_member_selec
867
867
  inline_time_picker (the Inline* family — per-field editors on `inline_edit`'s `useInlineEdit` +
868
868
  `InlineEditView`; `InlineSelect`/`InlineMemberSelect` render the resting value like its option — `renderOptionContent` by default, `renderSelected` to override — a chip/badge at rest, not just text) ·
869
869
  inline_static (InlineStatic — a READ-ONLY value matching the Inline* box metrics EXACTLY (height, padding, 1px transparent border) so a non-editable field — a computed total, a system ID, a synced/locked value — aligns pixel-for-pixel in the same column; non-interactive, NOT a disabled input; `muted`/`tabular`/`align="right"` for a number column, `weight="medium"` to emphasise a total among plain rows) ·
870
- list · list_item · menu_button · menu_list_item · detail_row (DetailRow — label+value row for drawer/peek detail; optional `trailing` slot renders a right-side action/badge/unit after the value) · danger_zone (DangerZone — the destructive section: a soft danger-tinted frame (`tint`/`solid`, never raw hex) + a danger heading + a description + a destructive action slot (children, e.g. a `danger` Button); sits APART at the bottom of a record/settings surface) · pressable_row ·
870
+ list · list_item · menu_button · menu_list_item · detail_row (DetailRow — label+value row for drawer/peek detail; in FORM mode (`labelWidth` set) the value column FILLS the row so a stack of inline editors all span the same width + none jumps wider on edit; optional `trailing` slot renders a right-side action/badge/unit after the value) · danger_zone (DangerZone — the destructive section: a soft danger-tinted frame (`tint`/`solid`, never raw hex) + a danger heading + a description + a destructive action slot (children, e.g. a `danger` Button); sits APART at the bottom of a record/settings surface) · pressable_row ·
871
871
  check_circle (CheckCircle — the completion ring: an empty ring that springs to a filled check when done, distinct from the square checkbox; the task/to-do/checklist toggle. Compose task rows directly, no Task component) · action_menu ·
872
872
  floating_action_bar · filter_chip · column_filter (ColumnFilter — the typed per-column filter pill +
873
873
  columnFilterToConditions; for a register filtering on several columns) · chip_group · search_input ·
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lotics/ui",
3
- "version": "7.11.0",
3
+ "version": "7.12.1",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./tokens": "./src/tokens.ts",
@@ -9,9 +9,8 @@ export interface DetailRowProps {
9
9
  children: ReactNode;
10
10
  /** An optional right-side slot, rendered as the LAST child of the row (after
11
11
  * `children`) — a small action `Button`, a status `Badge`, a unit label, an
12
- * `IconButton`. For it to sit at the right edge, wrap the value/editor in a
13
- * `flex:1` View so the value takes the slack and the trailing pins right (the
14
- * inline-record templates do this). */
12
+ * `IconButton`. In form mode (`labelWidth` set) the value column already fills
13
+ * the row, so the trailing pins to the right edge automatically. */
15
14
  trailing?: ReactNode;
16
15
  /** Fixed label-column width (px) to align labels in a left column — for a peek
17
16
  * or form-like stack. Omit for a spread row: the label takes the slack and the
@@ -26,17 +25,19 @@ export interface DetailRowProps {
26
25
  /**
27
26
  * One label + value line for a drawer / peek detail view — NOT a list row (that's
28
27
  * `PressableRow` / `TableRow`). Spread by default (muted label left, value pushed
29
- * to the right edge); pass `labelWidth` to align labels in a fixed left column
30
- * with the values flowing immediately after instead.
28
+ * to the right edge); pass `labelWidth` to align labels in a fixed left column
29
+ * the value column then FILLS the rest of the row, so a stack of inline editors
30
+ * all span the same width (none jumps wider on edit).
31
31
  */
32
32
  export function DetailRow(props: DetailRowProps) {
33
33
  const { label, children, trailing, labelWidth, labelSize = "sm", minHeight = 28 } = props;
34
+ const form = labelWidth != null;
34
35
  return (
35
36
  <View style={[styles.row, { minHeight }]}>
36
- <Text size={labelSize} color="muted" style={labelWidth != null ? { width: labelWidth } : styles.flexLabel}>
37
+ <Text size={labelSize} color="muted" style={form ? { width: labelWidth } : styles.flexLabel}>
37
38
  {label}
38
39
  </Text>
39
- {children}
40
+ {form ? <View style={styles.value}>{children}</View> : children}
40
41
  {trailing != null ? trailing : null}
41
42
  </View>
42
43
  );
@@ -49,4 +50,10 @@ const styles = StyleSheet.create({
49
50
  gap: 12,
50
51
  },
51
52
  flexLabel: { flex: 1 },
53
+ // Form mode (labelWidth set): the value column FILLS the row so every inline
54
+ // editor spans the SAME width — and none jumps wider when it swaps to the
55
+ // (flex:1) edit control. A stretch column, so an InlineEditView / InlineStatic
56
+ // child fills it edge-to-edge. A status Badge or action is NOT a value — pass
57
+ // it as `trailing` (pins right); one placed here would stretch full-width.
58
+ value: { flex: 1 },
52
59
  });
@@ -1,5 +1,5 @@
1
- import { ReactNode, useState } from "react";
2
- import { Pressable, StyleProp, StyleSheet, ViewStyle } from "react-native";
1
+ import { ReactNode, Ref, useState } from "react";
2
+ import { Pressable, StyleProp, StyleSheet, View, ViewStyle } from "react-native";
3
3
  import { colors } from "./colors";
4
4
 
5
5
  export interface PressableRowProps {
@@ -31,6 +31,11 @@ export interface PressableRowProps {
31
31
  /** Layout only (gap, minHeight overrides). The surface owns its press
32
32
  * states — never pass backgroundColor for hover/selected. */
33
33
  style?: StyleProp<ViewStyle>;
34
+ /** Forwarded to the underlying Pressable's DOM node so a `Popover`/`Tooltip`
35
+ * can anchor to (measure) the row — RN-Web forwards it to the rendered element.
36
+ * Without it, wrapping this row in a `PopoverTrigger` yields an unmeasurable
37
+ * trigger and the popover renders unpositioned. */
38
+ ref?: Ref<View>;
34
39
  }
35
40
 
36
41
  /**
@@ -45,7 +50,7 @@ export interface PressableRowProps {
45
50
  * `variant` picks bleed (registers) or inset (Accordion drill-down rows).
46
51
  */
47
52
  export function PressableRow(props: PressableRowProps) {
48
- const { onPress, selected = false, marked = false, variant = "register", children, style } = props;
53
+ const { onPress, selected = false, marked = false, variant = "register", children, style, ref } = props;
49
54
  const [hovered, setHovered] = useState(false);
50
55
 
51
56
  // RN's types don't declare mouse handlers; react-native-web forwards them
@@ -57,6 +62,7 @@ export function PressableRow(props: PressableRowProps) {
57
62
 
58
63
  return (
59
64
  <Pressable
65
+ ref={ref}
60
66
  onPress={onPress}
61
67
  // Non-focusable surface: tabIndex, NOT focusable — RN-Web's Pressable
62
68
  // ignores `focusable` and writes its own tabIndex (the keyboard target is