@lotics/ui 6.2.0 → 6.3.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 +4 -0
- package/package.json +1 -1
- package/src/combobox.tsx +23 -0
package/AGENTS.md
CHANGED
|
@@ -205,6 +205,10 @@ builds the new record and attaches it; existing matches attach directly. The cre
|
|
|
205
205
|
BELOW matches by default (the keyboard highlight lands on the first MATCH, so Enter on a partial
|
|
206
206
|
picks it, never a duplicate); pass `customOptionPlacement="top"` to pin it above. Use
|
|
207
207
|
`reflectSelection={false}` and render the attached record below as a card with a Change action.
|
|
208
|
+
For input-level status that must stay visible while results scroll (validity feedback on the typed
|
|
209
|
+
value, a result count, a secondary "create" affordance), pass `footer={({ close }) => …}` — a pinned
|
|
210
|
+
row below the listbox, OUTSIDE keyboard option-nav; call `close()` from a footer action that hands
|
|
211
|
+
off elsewhere (so the popover dismisses cleanly instead of floating over what you navigated to).
|
|
208
212
|
|
|
209
213
|
### Line items — create → preview → edit (a composition, not a primitive)
|
|
210
214
|
For a list of records you build then revise (invoice rows, repair lines, config entries), each
|
package/package.json
CHANGED
package/src/combobox.tsx
CHANGED
|
@@ -67,6 +67,13 @@ export interface ComboboxProps<T extends string = string, D = unknown> {
|
|
|
67
67
|
placeholder?: string;
|
|
68
68
|
recentsLabel?: string;
|
|
69
69
|
emptyText?: string;
|
|
70
|
+
/** A pinned row rendered at the bottom of the popover (below the results, outside
|
|
71
|
+
* the scroll area) whenever the popover is open. For input-level status that must
|
|
72
|
+
* stay visible while results scroll — validity feedback, a result count, a "create"
|
|
73
|
+
* affordance. It sits OUTSIDE the listbox, so its content is auxiliary (not an
|
|
74
|
+
* option) and never enters keyboard option-nav. Receives `close` to dismiss the
|
|
75
|
+
* popover — call it from an action that navigates elsewhere. */
|
|
76
|
+
footer?: (api: { close: () => void }) => ReactNode;
|
|
70
77
|
accessibilityLabel?: string;
|
|
71
78
|
disabled?: boolean;
|
|
72
79
|
/** Show an in-input clear ✕ whenever the input has text (a reflected selection
|
|
@@ -111,6 +118,7 @@ export function Combobox<T extends string = string, D = unknown>(props: Combobox
|
|
|
111
118
|
searchDebounceMs = 200,
|
|
112
119
|
icon,
|
|
113
120
|
placeholder,
|
|
121
|
+
footer,
|
|
114
122
|
accessibilityLabel = "Results",
|
|
115
123
|
disabled = false,
|
|
116
124
|
clearable = false,
|
|
@@ -169,6 +177,14 @@ export function Combobox<T extends string = string, D = unknown>(props: Combobox
|
|
|
169
177
|
[onValueChange, isServer, debouncedSearch, onSearchChange, reflectSelection],
|
|
170
178
|
);
|
|
171
179
|
|
|
180
|
+
// Dismiss the popover from the footer — drop focus too, mirroring the popover's
|
|
181
|
+
// own self-close (so the input's keyboard focus ring doesn't linger after a
|
|
182
|
+
// footer action hands off elsewhere).
|
|
183
|
+
const close = useCallback(() => {
|
|
184
|
+
setOpen(false);
|
|
185
|
+
inputRef.current?.blur();
|
|
186
|
+
}, []);
|
|
187
|
+
|
|
172
188
|
const list = useOptionList<T, false, D>({
|
|
173
189
|
options,
|
|
174
190
|
value: single?.value ?? null,
|
|
@@ -347,6 +363,7 @@ export function Combobox<T extends string = string, D = unknown>(props: Combobox
|
|
|
347
363
|
})
|
|
348
364
|
)}
|
|
349
365
|
</ScrollView>
|
|
366
|
+
{footer ? <View style={styles.footer}>{footer({ close })}</View> : null}
|
|
350
367
|
</View>
|
|
351
368
|
</PopoverContent>
|
|
352
369
|
</Popover>
|
|
@@ -386,4 +403,10 @@ const styles = StyleSheet.create({
|
|
|
386
403
|
justifyContent: "center",
|
|
387
404
|
paddingVertical: 16,
|
|
388
405
|
},
|
|
406
|
+
footer: {
|
|
407
|
+
borderTopWidth: 1,
|
|
408
|
+
borderTopColor: colors.border,
|
|
409
|
+
paddingHorizontal: 8,
|
|
410
|
+
paddingVertical: 6,
|
|
411
|
+
},
|
|
389
412
|
});
|