@lotics/ui 5.7.0 → 5.9.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 +102 -42
- package/examples/tpl_approvals.tsx +10 -10
- package/examples/tpl_convert.tsx +11 -23
- package/examples/tpl_crm_desk.tsx +3 -3
- package/examples/tpl_dieline.tsx +7 -6
- package/examples/tpl_directory.tsx +3 -3
- package/examples/tpl_dossier.tsx +7 -7
- package/examples/tpl_draft.tsx +4 -4
- package/examples/tpl_extract.tsx +7 -7
- package/examples/tpl_inventory.tsx +3 -3
- package/examples/tpl_lookup.tsx +4 -3
- package/examples/tpl_match.tsx +1 -1
- package/examples/tpl_order.tsx +1 -1
- package/examples/tpl_ratedesk.tsx +12 -12
- package/examples/tpl_record.tsx +1 -1
- package/examples/tpl_report.tsx +3 -3
- package/examples/tpl_stock.tsx +3 -3
- package/examples/tpl_triage.tsx +1 -1
- package/package.json +12 -4
- package/src/agent_progress.tsx +14 -12
- package/src/agent_run.tsx +253 -66
- package/src/back_button.tsx +3 -2
- package/src/badge.tsx +2 -1
- package/src/button.tsx +11 -32
- package/src/button_colors.ts +23 -0
- package/src/calendar/calendar_view.tsx +2 -2
- package/src/card_select_item.tsx +2 -1
- package/src/change_review.tsx +5 -6
- package/src/{pill_button.tsx → chip.tsx} +7 -7
- package/src/chip_group.tsx +2 -2
- package/src/column_filter.tsx +4 -4
- package/src/combobox.tsx +2 -9
- package/src/composer.tsx +4 -3
- package/src/control_surface.ts +15 -15
- package/src/date_field.tsx +2 -1
- package/src/date_filter.tsx +2 -1
- package/src/date_range_filter_field.tsx +2 -1
- package/src/dialog.tsx +2 -2
- package/src/discrepancy.tsx +1 -1
- package/src/drawer.tsx +1 -2
- package/src/file_gallery_modal.tsx +220 -133
- package/src/file_grid.tsx +184 -0
- package/src/file_preview.web.tsx +329 -6
- package/src/file_preview_types.ts +40 -0
- package/src/file_row.tsx +114 -0
- package/src/file_rows.tsx +105 -0
- package/src/file_thumbnail.tsx +121 -79
- package/src/file_thumbnail_grid.tsx +130 -55
- package/src/{filter_pill.tsx → filter_chip.tsx} +8 -8
- package/src/finding.tsx +1 -1
- package/src/gantt/gantt_view.tsx +2 -2
- package/src/icon_button.tsx +49 -14
- package/src/image_gallery.tsx +0 -4
- package/src/inline_edit.tsx +2 -2
- package/src/link_button.tsx +2 -1
- package/src/menu_button.tsx +2 -1
- package/src/menu_list_item.tsx +2 -1
- package/src/number_input.tsx +2 -1
- package/src/pdfjs_worker.d.ts +5 -0
- package/src/picker.tsx +3 -3
- package/src/popover_header.tsx +2 -2
- package/src/radio_picker.tsx +2 -1
- package/src/range_slider.tsx +1 -1
- package/src/review_card.tsx +2 -2
- package/src/scan_field.tsx +2 -1
- package/src/scored_option.tsx +0 -1
- package/src/search_input.tsx +3 -2
- package/src/segmented_control.tsx +2 -1
- package/src/status_badge.tsx +2 -1
- package/src/stepper.tsx +3 -2
- package/src/switch_button.tsx +2 -1
- package/src/switcher.tsx +3 -2
- package/src/tabs.tsx +2 -1
- package/src/tag_input.tsx +2 -1
- package/src/text_input_field.tsx +2 -1
- package/src/time_field.tsx +2 -1
- package/src/time_picker.tsx +2 -1
- package/src/triage_row.tsx +3 -3
- package/src/uploading_thumbnail.tsx +212 -0
- package/src/hover_action.tsx +0 -54
package/src/column_filter.tsx
CHANGED
|
@@ -3,7 +3,7 @@ import { Text } from "./text";
|
|
|
3
3
|
import { TextInputField } from "./text_input_field";
|
|
4
4
|
import { NumberInput } from "./number_input";
|
|
5
5
|
import { PickerMenu } from "./picker_menu";
|
|
6
|
-
import {
|
|
6
|
+
import { FilterChip } from "./filter_chip";
|
|
7
7
|
import type { PickerOption } from "./picker";
|
|
8
8
|
|
|
9
9
|
/** A column the picker can filter on. `type` selects the control + operators. */
|
|
@@ -97,7 +97,7 @@ export interface ColumnFilterProps {
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
/**
|
|
100
|
-
* A toolbar-style filter pill: the same `
|
|
100
|
+
* A toolbar-style filter pill: the same `Chip` the table toolbar uses, so
|
|
101
101
|
* a picker's filters read identically. Inactive → "Label ⌄"; active →
|
|
102
102
|
* "Label: summary" with an X to clear. Pressing the pill opens a type-aware
|
|
103
103
|
* editor (text contains / number range / multi-select). Controlled — the
|
|
@@ -109,7 +109,7 @@ export function ColumnFilter(props: ColumnFilterProps) {
|
|
|
109
109
|
const active = isColumnFilterActive(value);
|
|
110
110
|
|
|
111
111
|
return (
|
|
112
|
-
<
|
|
112
|
+
<FilterChip
|
|
113
113
|
label={column.label}
|
|
114
114
|
summary={active ? columnFilterSummary(column, value) : undefined}
|
|
115
115
|
onClear={() => onChange(undefined)}
|
|
@@ -150,7 +150,7 @@ export function ColumnFilter(props: ColumnFilterProps) {
|
|
|
150
150
|
onValueChange={(selected) => onChange({ kind: "select", selected })}
|
|
151
151
|
/>
|
|
152
152
|
)}
|
|
153
|
-
</
|
|
153
|
+
</FilterChip>
|
|
154
154
|
);
|
|
155
155
|
}
|
|
156
156
|
|
package/src/combobox.tsx
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
} from "react-native";
|
|
10
10
|
import { useCallback, useEffect, useId, useMemo, useRef, useState, type ReactNode } from "react";
|
|
11
11
|
import { colors } from "./colors";
|
|
12
|
-
import { ACTIVE_RING,
|
|
12
|
+
import { ACTIVE_RING, CONTROL_RADIUS } from "./control_surface";
|
|
13
13
|
import { Text } from "./text";
|
|
14
14
|
import { Icon, type IconName } from "./icon";
|
|
15
15
|
import { TextInputField } from "./text_input_field";
|
|
@@ -70,11 +70,6 @@ export interface ComboboxProps<T extends string = string, D = unknown> {
|
|
|
70
70
|
* picker, not a free-text search box. Opt IN to the search-box look explicitly
|
|
71
71
|
* with `icon="search"` (leading glyph, no chevron). Multi-select shows neither. */
|
|
72
72
|
icon?: IconName;
|
|
73
|
-
/** Render the input on the white toolbar-pill surface (rounded-full, white
|
|
74
|
-
* fill, zinc-300 border) — the same surface SearchInput/ChipGroup/FilterPill
|
|
75
|
-
* wear — so a combobox used as a toolbar filter reads as a view-control on the
|
|
76
|
-
* zinc-50 canvas, not a form field. Single-select only. */
|
|
77
|
-
pill?: boolean;
|
|
78
73
|
placeholder?: string;
|
|
79
74
|
recentsLabel?: string;
|
|
80
75
|
emptyText?: string;
|
|
@@ -128,7 +123,6 @@ export function Combobox<T extends string = string, D = unknown>(props: Combobox
|
|
|
128
123
|
loading = false,
|
|
129
124
|
searchDebounceMs = 200,
|
|
130
125
|
icon,
|
|
131
|
-
pill = false,
|
|
132
126
|
placeholder,
|
|
133
127
|
recentsLabel = "Recent",
|
|
134
128
|
emptyText = "No results",
|
|
@@ -346,7 +340,6 @@ export function Combobox<T extends string = string, D = unknown>(props: Combobox
|
|
|
346
340
|
autoCorrect={false}
|
|
347
341
|
style={[
|
|
348
342
|
multi ? styles.multiInput : showChevron ? styles.selectInput : undefined,
|
|
349
|
-
!multi && pill ? inputPillStyle : undefined,
|
|
350
343
|
// Single-select wears the open ring on the input (which holds the
|
|
351
344
|
// border); multi wears it on the wrapper above (the input is borderless).
|
|
352
345
|
// Gate on `showList`, not `open`: an empty query with no options has
|
|
@@ -471,7 +464,7 @@ const styles = StyleSheet.create({
|
|
|
471
464
|
minHeight: 40,
|
|
472
465
|
borderWidth: 1,
|
|
473
466
|
borderColor: colors.border,
|
|
474
|
-
borderRadius:
|
|
467
|
+
borderRadius: CONTROL_RADIUS,
|
|
475
468
|
},
|
|
476
469
|
multiInput: {
|
|
477
470
|
flexGrow: 1,
|
package/src/composer.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { type ReactNode, type Ref, useCallback, useEffect, useState } from "react";
|
|
2
2
|
import { View, TextInput as RNTextInput, ScrollView, StyleSheet, type TextInputProps } from "react-native";
|
|
3
|
-
import {
|
|
3
|
+
import { IconButton } from "./icon_button";
|
|
4
4
|
import { colors } from "./colors";
|
|
5
5
|
import { fontFamilyRegular, getInputTextStyle } from "./text_utils";
|
|
6
6
|
import { useAutoGrowHeight } from "./use_auto_grow_height";
|
|
@@ -156,10 +156,11 @@ export function Composer(props: ComposerProps) {
|
|
|
156
156
|
|
|
157
157
|
const sendButton =
|
|
158
158
|
disabled && onStop ? (
|
|
159
|
-
<
|
|
159
|
+
<IconButton onPress={onStop} size="lg" color="primary" icon="square" tooltip={stopLabel} accessibilityLabel={stopLabel} />
|
|
160
160
|
) : (
|
|
161
|
-
<
|
|
161
|
+
<IconButton
|
|
162
162
|
onPress={handleSend}
|
|
163
|
+
size="lg"
|
|
163
164
|
color="primary"
|
|
164
165
|
disabled={disabled || effectiveSendDisabled}
|
|
165
166
|
icon="arrow-up"
|
package/src/control_surface.ts
CHANGED
|
@@ -1,10 +1,21 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type ViewStyle } from "react-native";
|
|
2
2
|
import { colors } from "./colors";
|
|
3
3
|
|
|
4
4
|
/** The system control height — every band control (chips, pills, search,
|
|
5
5
|
* buttons) aligns to it so a toolbar row reads as one band. */
|
|
6
6
|
export const CONTROL_HEIGHT = 40;
|
|
7
7
|
|
|
8
|
+
/** The system control radius — every interactive control surface (Button, the
|
|
9
|
+
* inputs/selects/pickers, SearchInput, MenuButton, Tabs, the SegmentedControl
|
|
10
|
+
* track, and ChipGroup/FilterChip/Chip via the surfaces below) wears it,
|
|
11
|
+
* so the whole control vocabulary reads as one family. Containers are
|
|
12
|
+
* deliberately larger (Card 16, the review card 12); a nested element inside a
|
|
13
|
+
* padded control (a segmented thumb, a combobox chip) takes `CONTROL_RADIUS −
|
|
14
|
+
* padding` so its corner stays CONCENTRIC with the parent's — set it equal and
|
|
15
|
+
* the inner corner bulges past the outer curve. Round-by-function controls
|
|
16
|
+
* (avatars, dots, switches, sliders, progress, icon buttons) stay full. */
|
|
17
|
+
export const CONTROL_RADIUS = 10;
|
|
18
|
+
|
|
8
19
|
/** The active/open edge for an interactive control — a 2px zinc-900 ring flush
|
|
9
20
|
* against the box (offset 0), MIRRORING the keyboard `:focus-visible` outline
|
|
10
21
|
* (index.css). A mouse-opened popover trigger (Picker / Combobox / InlineSelect /
|
|
@@ -13,17 +24,6 @@ export const CONTROL_HEIGHT = 40;
|
|
|
13
24
|
* beside the kit's focus outline and selected-pill ring. */
|
|
14
25
|
export const ACTIVE_RING = `0 0 0 2px ${colors.zinc[900]}`;
|
|
15
26
|
|
|
16
|
-
/** THE white toolbar-input surface — a rounded-full white pill with a one-step-up
|
|
17
|
-
* zinc-300 border. A search/select control (SearchInput, and Combobox via `pill`)
|
|
18
|
-
* wears it so it reads as a view-control beside ChipGroup/FilterPill on the
|
|
19
|
-
* zinc-50 canvas (where the fill pops), not as a form field that vanishes into a
|
|
20
|
-
* white card. One definition so the two controls never drift. */
|
|
21
|
-
export const inputPillStyle: TextStyle = {
|
|
22
|
-
borderRadius: 999,
|
|
23
|
-
backgroundColor: colors.white,
|
|
24
|
-
borderColor: colors.zinc[300],
|
|
25
|
-
};
|
|
26
|
-
|
|
27
27
|
/** THE review-card surface — the bordered white card every "AI proposes, you
|
|
28
28
|
* decide" surface wears (`ReviewCard`, and the whole-set `ChangeReview`), so the
|
|
29
29
|
* review family reads as ONE contract instead of look-alikes drifting apart. One
|
|
@@ -41,7 +41,7 @@ export const reviewResolvedStyle: ViewStyle = { backgroundColor: colors.zinc[50]
|
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
43
|
* THE pill-surface contract — the single definition of the bordered, white,
|
|
44
|
-
* rounded interactive surface shared by `ChipGroup` chips and `
|
|
44
|
+
* rounded interactive surface shared by `ChipGroup` chips and `Chip` (and
|
|
45
45
|
* anything composed on them). Returns the style for the CURRENT pressable state,
|
|
46
46
|
* so the hover (white → zinc-100) and press (zinc-200) washes live in ONE place
|
|
47
47
|
* instead of drifting per control — and any control built on it hovers without
|
|
@@ -49,7 +49,7 @@ export const reviewResolvedStyle: ViewStyle = { backgroundColor: colors.zinc[50]
|
|
|
49
49
|
* crisp 2px dark edge, no layout shift). Each control adds its own padding/layout
|
|
50
50
|
* on top.
|
|
51
51
|
*/
|
|
52
|
-
export function
|
|
52
|
+
export function chipSurfaceStyle(
|
|
53
53
|
state: { hovered?: boolean; pressed?: boolean },
|
|
54
54
|
opts?: { selected?: boolean },
|
|
55
55
|
): ViewStyle {
|
|
@@ -57,7 +57,7 @@ export function pillSurfaceStyle(
|
|
|
57
57
|
return {
|
|
58
58
|
height: CONTROL_HEIGHT,
|
|
59
59
|
justifyContent: "center",
|
|
60
|
-
borderRadius:
|
|
60
|
+
borderRadius: CONTROL_RADIUS,
|
|
61
61
|
borderWidth: 1,
|
|
62
62
|
borderColor: selected ? colors.zinc[900] : colors.border,
|
|
63
63
|
backgroundColor: state.pressed ? colors.zinc[200] : state.hovered ? colors.zinc[100] : colors.white,
|
package/src/date_field.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
2
|
import { StyleProp, StyleSheet, View, ViewStyle } from "react-native";
|
|
3
3
|
import { colors } from "./colors";
|
|
4
|
+
import { CONTROL_RADIUS } from "./control_surface";
|
|
4
5
|
import { Text } from "./text";
|
|
5
6
|
import { DateSegments } from "./date_segments_field";
|
|
6
7
|
import { SegmentLabels, dateSegmentsConfig } from "./date_segments";
|
|
@@ -144,7 +145,7 @@ const styles = StyleSheet.create({
|
|
|
144
145
|
height: 40,
|
|
145
146
|
paddingHorizontal: 8,
|
|
146
147
|
gap: 4,
|
|
147
|
-
borderRadius:
|
|
148
|
+
borderRadius: CONTROL_RADIUS,
|
|
148
149
|
borderWidth: 1,
|
|
149
150
|
borderColor: colors.border,
|
|
150
151
|
backgroundColor: colors.background,
|
package/src/date_filter.tsx
CHANGED
|
@@ -2,6 +2,7 @@ import React, { useCallback, useMemo, useRef, useState } from "react";
|
|
|
2
2
|
import { ScrollView, StyleSheet, View } from "react-native";
|
|
3
3
|
import { Text } from "./text";
|
|
4
4
|
import { colors } from "./colors";
|
|
5
|
+
import { CONTROL_RADIUS } from "./control_surface";
|
|
5
6
|
import { MenuButton } from "./menu_button";
|
|
6
7
|
import { Calendar, CalendarRangeValue, CalendarRef } from "./date_calendar";
|
|
7
8
|
import { TimeField } from "./time_field";
|
|
@@ -336,7 +337,7 @@ export function DateFilter(props: DateFilterProps) {
|
|
|
336
337
|
const styles = StyleSheet.create({
|
|
337
338
|
container: {
|
|
338
339
|
backgroundColor: colors.white,
|
|
339
|
-
borderRadius:
|
|
340
|
+
borderRadius: CONTROL_RADIUS,
|
|
340
341
|
gap: 16,
|
|
341
342
|
},
|
|
342
343
|
presetsSidebar: {
|
|
@@ -2,6 +2,7 @@ import React, { useMemo, useState } from "react";
|
|
|
2
2
|
import { View } from "react-native";
|
|
3
3
|
import { Text } from "./text";
|
|
4
4
|
import { colors } from "./colors";
|
|
5
|
+
import { CONTROL_RADIUS } from "./control_surface";
|
|
5
6
|
import { Icon } from "./icon";
|
|
6
7
|
import { Button } from "./button";
|
|
7
8
|
import { PressableHighlight } from "./pressable_highlight";
|
|
@@ -130,7 +131,7 @@ export function DateRangeFilterField(props: DateRangeFilterFieldProps) {
|
|
|
130
131
|
paddingHorizontal: 12,
|
|
131
132
|
borderWidth: 1,
|
|
132
133
|
borderColor: colors.zinc[300],
|
|
133
|
-
borderRadius:
|
|
134
|
+
borderRadius: CONTROL_RADIUS,
|
|
134
135
|
backgroundColor: colors.white,
|
|
135
136
|
}}
|
|
136
137
|
>
|
package/src/dialog.tsx
CHANGED
|
@@ -3,7 +3,7 @@ import { Animated, Modal, StyleSheet, View, ScrollView } from "react-native";
|
|
|
3
3
|
import { useScreenSize } from "@lotics/ui/use_screen_size";
|
|
4
4
|
import { PortalHost } from "@lotics/ui/portal";
|
|
5
5
|
import { colors } from "@lotics/ui/colors";
|
|
6
|
-
import {
|
|
6
|
+
import { IconButton } from "@lotics/ui/icon_button";
|
|
7
7
|
import { Text } from "@lotics/ui/text";
|
|
8
8
|
import { BackButton } from "@lotics/ui/back_button";
|
|
9
9
|
import { useOverlayScope } from "@lotics/ui/overlay_scope";
|
|
@@ -163,7 +163,7 @@ export function Dialog(props: DialogProps) {
|
|
|
163
163
|
<PortalHost>
|
|
164
164
|
<View testID={testID} style={[styles.dialogContainer, { borderRadius }]}>
|
|
165
165
|
<View style={[styles.closeButtonContainer, { paddingHorizontal: screenSize.small ? 16 : 24 }]}>
|
|
166
|
-
<
|
|
166
|
+
<IconButton icon="x" size="lg" accessibilityLabel="Close" onPress={handleClose} />
|
|
167
167
|
</View>
|
|
168
168
|
<View style={styles.container}>{children}</View>
|
|
169
169
|
</View>
|
package/src/discrepancy.tsx
CHANGED
|
@@ -88,7 +88,7 @@ export function Discrepancy(props: DiscrepancyProps) {
|
|
|
88
88
|
|
|
89
89
|
{onFlag ? (
|
|
90
90
|
<View style={styles.footer}>
|
|
91
|
-
<Button title="Flag for review" color="muted"
|
|
91
|
+
<Button title="Flag for review" color="muted" onPress={onFlag} />
|
|
92
92
|
</View>
|
|
93
93
|
) : null}
|
|
94
94
|
</>
|
package/src/drawer.tsx
CHANGED
|
@@ -3,7 +3,6 @@ import { Modal, Pressable, StyleSheet, View } from "react-native";
|
|
|
3
3
|
import { useScreenSize } from "@lotics/ui/use_screen_size";
|
|
4
4
|
import { PortalHost } from "@lotics/ui/portal";
|
|
5
5
|
import { colors } from "@lotics/ui/colors";
|
|
6
|
-
import { Button } from "@lotics/ui/button";
|
|
7
6
|
import { IconButton } from "@lotics/ui/icon_button";
|
|
8
7
|
import { Text } from "@lotics/ui/text";
|
|
9
8
|
import { useOverlayScope } from "@lotics/ui/overlay_scope";
|
|
@@ -112,7 +111,7 @@ export function Drawer(props: DrawerProps) {
|
|
|
112
111
|
/>
|
|
113
112
|
</View>
|
|
114
113
|
) : null}
|
|
115
|
-
<
|
|
114
|
+
<IconButton icon="x" size="lg" accessibilityLabel="Close" onPress={handleClose} />
|
|
116
115
|
</View>
|
|
117
116
|
<View testID={testID} style={styles.body}>
|
|
118
117
|
{children}
|