@dloizides/ui-forms 1.23.0 → 1.24.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/CHANGELOG.md +6 -0
- package/dist/index.d.mts +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +42 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +42 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.24.0
|
|
4
|
+
|
|
5
|
+
BEAD-3 "Report form: searchable pattern field": review fix.
|
|
6
|
+
|
|
7
|
+
- New `useKeepInView(trigger)`, moved from Jinx: scrolls the returned view into sight each time `trigger` takes a new value, as far as needed and no further. Web only; a no-op on native.
|
|
8
|
+
|
|
3
9
|
## 1.23.0
|
|
4
10
|
|
|
5
11
|
BEAD-3 "Report form: searchable pattern field and shared form feedback".
|
package/dist/index.d.mts
CHANGED
|
@@ -1146,6 +1146,9 @@ type FocusableRefs<Field extends string> = Readonly<Record<Field, RefObject<Focu
|
|
|
1146
1146
|
/** Returns a stable function that focuses the first listed field that is on screen. */
|
|
1147
1147
|
declare function useFocusFirstInvalid<Field extends string>(refs: FocusableRefs<Field>): (invalid: readonly Field[]) => void;
|
|
1148
1148
|
|
|
1149
|
+
/** Scrolls the returned view fully into sight each time `trigger` takes a new value. */
|
|
1150
|
+
declare function useKeepInView(trigger: unknown): RefObject<View | null>;
|
|
1151
|
+
|
|
1149
1152
|
/** Every string the field shows; all pre-localized. */
|
|
1150
1153
|
interface UploadWithLinkLabels {
|
|
1151
1154
|
title: string;
|
|
@@ -1170,4 +1173,4 @@ interface UploadWithLinkFieldProps {
|
|
|
1170
1173
|
/** An image field: preview, an upload control, and a link input revealed on request. */
|
|
1171
1174
|
declare const UploadWithLinkField: ({ value, onChange, labels, uploadControl, testID, disabled, previewSize, }: UploadWithLinkFieldProps) => React.ReactElement;
|
|
1172
1175
|
|
|
1173
|
-
export { AlignToControl, type AlignToControlProps, AnchoredMenu, type AnchoredMenuColors, type AnchoredMenuListbox, type AnchoredMenuProps, type ChipOption, ChipSelector, type ChipSelectorProps, type ChipSingleSelectRole, type ChipVariant, type ControlOption, DEFAULT_MAX_RECENTS, DEFAULT_OPTIONAL_LABEL, DEFAULT_TYPEAHEAD_MAX_SUGGESTIONS, DEFAULT_TYPEAHEAD_MIN_CHARS, DateRangeControl, type DateRangeControlProps, type DateRangeValue, Field, type FieldChildContext, type FieldChildren, type FieldLabelVariant, type FieldMarker, type FieldProps, type FieldSpacing, type Focusable, type FocusableRefs, FormActions, type FormActionsProps, FormCell, type FormCellProps, FormCheckbox, type FormCheckboxProps, FormField, type FormFieldProps, FormGrid, type FormGridProps, FormSection, type FormSectionProps, FormStatusLine, type FormStatusLineProps, FormSwitch, type FormSwitchProps, type GroupSelection, INLINE_FIELD_ROW_MIN_WIDTH, InlineFieldRow, type InlineFieldRowLayout, type InlineFieldRowProps, type RecentValues, SelectControl, type SelectControlProps, type StepNeighbours, StepperNav, type StepperNavLabels, type StepperNavProps, type StepperStep, StepperTabs, type StepperTabsProps, type ThemedInput, ThemedTextInput, type ThemedTextInputProps, TypeaheadControl, type TypeaheadControlProps, type TypeaheadSearch, type TypeaheadSearchProps, UploadWithLinkField, type UploadWithLinkFieldProps, type UploadWithLinkLabels, type UseThemedInputOptions, controlStyles, groupAriaChecked, inlineFieldRowLayout, isUnmatched, resolveGroupSelection, resolveStepNeighbours, suggestOptions, toggleGroupSelection, useFocusFirstInvalid, useRecentValues, useThemedInput };
|
|
1176
|
+
export { AlignToControl, type AlignToControlProps, AnchoredMenu, type AnchoredMenuColors, type AnchoredMenuListbox, type AnchoredMenuProps, type ChipOption, ChipSelector, type ChipSelectorProps, type ChipSingleSelectRole, type ChipVariant, type ControlOption, DEFAULT_MAX_RECENTS, DEFAULT_OPTIONAL_LABEL, DEFAULT_TYPEAHEAD_MAX_SUGGESTIONS, DEFAULT_TYPEAHEAD_MIN_CHARS, DateRangeControl, type DateRangeControlProps, type DateRangeValue, Field, type FieldChildContext, type FieldChildren, type FieldLabelVariant, type FieldMarker, type FieldProps, type FieldSpacing, type Focusable, type FocusableRefs, FormActions, type FormActionsProps, FormCell, type FormCellProps, FormCheckbox, type FormCheckboxProps, FormField, type FormFieldProps, FormGrid, type FormGridProps, FormSection, type FormSectionProps, FormStatusLine, type FormStatusLineProps, FormSwitch, type FormSwitchProps, type GroupSelection, INLINE_FIELD_ROW_MIN_WIDTH, InlineFieldRow, type InlineFieldRowLayout, type InlineFieldRowProps, type RecentValues, SelectControl, type SelectControlProps, type StepNeighbours, StepperNav, type StepperNavLabels, type StepperNavProps, type StepperStep, StepperTabs, type StepperTabsProps, type ThemedInput, ThemedTextInput, type ThemedTextInputProps, TypeaheadControl, type TypeaheadControlProps, type TypeaheadSearch, type TypeaheadSearchProps, UploadWithLinkField, type UploadWithLinkFieldProps, type UploadWithLinkLabels, type UseThemedInputOptions, controlStyles, groupAriaChecked, inlineFieldRowLayout, isUnmatched, resolveGroupSelection, resolveStepNeighbours, suggestOptions, toggleGroupSelection, useFocusFirstInvalid, useKeepInView, useRecentValues, useThemedInput };
|
package/dist/index.d.ts
CHANGED
|
@@ -1146,6 +1146,9 @@ type FocusableRefs<Field extends string> = Readonly<Record<Field, RefObject<Focu
|
|
|
1146
1146
|
/** Returns a stable function that focuses the first listed field that is on screen. */
|
|
1147
1147
|
declare function useFocusFirstInvalid<Field extends string>(refs: FocusableRefs<Field>): (invalid: readonly Field[]) => void;
|
|
1148
1148
|
|
|
1149
|
+
/** Scrolls the returned view fully into sight each time `trigger` takes a new value. */
|
|
1150
|
+
declare function useKeepInView(trigger: unknown): RefObject<View | null>;
|
|
1151
|
+
|
|
1149
1152
|
/** Every string the field shows; all pre-localized. */
|
|
1150
1153
|
interface UploadWithLinkLabels {
|
|
1151
1154
|
title: string;
|
|
@@ -1170,4 +1173,4 @@ interface UploadWithLinkFieldProps {
|
|
|
1170
1173
|
/** An image field: preview, an upload control, and a link input revealed on request. */
|
|
1171
1174
|
declare const UploadWithLinkField: ({ value, onChange, labels, uploadControl, testID, disabled, previewSize, }: UploadWithLinkFieldProps) => React.ReactElement;
|
|
1172
1175
|
|
|
1173
|
-
export { AlignToControl, type AlignToControlProps, AnchoredMenu, type AnchoredMenuColors, type AnchoredMenuListbox, type AnchoredMenuProps, type ChipOption, ChipSelector, type ChipSelectorProps, type ChipSingleSelectRole, type ChipVariant, type ControlOption, DEFAULT_MAX_RECENTS, DEFAULT_OPTIONAL_LABEL, DEFAULT_TYPEAHEAD_MAX_SUGGESTIONS, DEFAULT_TYPEAHEAD_MIN_CHARS, DateRangeControl, type DateRangeControlProps, type DateRangeValue, Field, type FieldChildContext, type FieldChildren, type FieldLabelVariant, type FieldMarker, type FieldProps, type FieldSpacing, type Focusable, type FocusableRefs, FormActions, type FormActionsProps, FormCell, type FormCellProps, FormCheckbox, type FormCheckboxProps, FormField, type FormFieldProps, FormGrid, type FormGridProps, FormSection, type FormSectionProps, FormStatusLine, type FormStatusLineProps, FormSwitch, type FormSwitchProps, type GroupSelection, INLINE_FIELD_ROW_MIN_WIDTH, InlineFieldRow, type InlineFieldRowLayout, type InlineFieldRowProps, type RecentValues, SelectControl, type SelectControlProps, type StepNeighbours, StepperNav, type StepperNavLabels, type StepperNavProps, type StepperStep, StepperTabs, type StepperTabsProps, type ThemedInput, ThemedTextInput, type ThemedTextInputProps, TypeaheadControl, type TypeaheadControlProps, type TypeaheadSearch, type TypeaheadSearchProps, UploadWithLinkField, type UploadWithLinkFieldProps, type UploadWithLinkLabels, type UseThemedInputOptions, controlStyles, groupAriaChecked, inlineFieldRowLayout, isUnmatched, resolveGroupSelection, resolveStepNeighbours, suggestOptions, toggleGroupSelection, useFocusFirstInvalid, useRecentValues, useThemedInput };
|
|
1176
|
+
export { AlignToControl, type AlignToControlProps, AnchoredMenu, type AnchoredMenuColors, type AnchoredMenuListbox, type AnchoredMenuProps, type ChipOption, ChipSelector, type ChipSelectorProps, type ChipSingleSelectRole, type ChipVariant, type ControlOption, DEFAULT_MAX_RECENTS, DEFAULT_OPTIONAL_LABEL, DEFAULT_TYPEAHEAD_MAX_SUGGESTIONS, DEFAULT_TYPEAHEAD_MIN_CHARS, DateRangeControl, type DateRangeControlProps, type DateRangeValue, Field, type FieldChildContext, type FieldChildren, type FieldLabelVariant, type FieldMarker, type FieldProps, type FieldSpacing, type Focusable, type FocusableRefs, FormActions, type FormActionsProps, FormCell, type FormCellProps, FormCheckbox, type FormCheckboxProps, FormField, type FormFieldProps, FormGrid, type FormGridProps, FormSection, type FormSectionProps, FormStatusLine, type FormStatusLineProps, FormSwitch, type FormSwitchProps, type GroupSelection, INLINE_FIELD_ROW_MIN_WIDTH, InlineFieldRow, type InlineFieldRowLayout, type InlineFieldRowProps, type RecentValues, SelectControl, type SelectControlProps, type StepNeighbours, StepperNav, type StepperNavLabels, type StepperNavProps, type StepperStep, StepperTabs, type StepperTabsProps, type ThemedInput, ThemedTextInput, type ThemedTextInputProps, TypeaheadControl, type TypeaheadControlProps, type TypeaheadSearch, type TypeaheadSearchProps, UploadWithLinkField, type UploadWithLinkFieldProps, type UploadWithLinkLabels, type UseThemedInputOptions, controlStyles, groupAriaChecked, inlineFieldRowLayout, isUnmatched, resolveGroupSelection, resolveStepNeighbours, suggestOptions, toggleGroupSelection, useFocusFirstInvalid, useKeepInView, useRecentValues, useThemedInput };
|
package/dist/index.js
CHANGED
|
@@ -571,12 +571,16 @@ function listboxDomId(testID) {
|
|
|
571
571
|
function isDetailBesideTitle(menuWidth) {
|
|
572
572
|
return menuWidth >= DETAIL_BESIDE_MIN_MENU_WIDTH;
|
|
573
573
|
}
|
|
574
|
+
function rowInk(colors, isActive, isHighlighted) {
|
|
575
|
+
if (isHighlighted) return { title: colors.surface, detail: colors.surface };
|
|
576
|
+
return { title: isActive ? colors.brand : colors.text, detail: colors.textSecondary ?? colors.text };
|
|
577
|
+
}
|
|
574
578
|
function OptionRow({ option, isActive, isHighlighted, isListboxRow, menuWidth, hint, colors, testID, onSelect }) {
|
|
575
579
|
const hasDetail = option.detail !== void 0 && option.detail !== "";
|
|
576
580
|
const label = hasDetail ? `${option.label}, ${option.detail}` : option.label;
|
|
577
581
|
const roleProps = isListboxRow ? { role: "option", tabIndex: -1, id: optionDomId(testID, option.value), "aria-selected": isHighlighted } : { accessibilityRole: "menuitem", "aria-selected": isActive };
|
|
578
582
|
const isBold = isActive || isHighlighted;
|
|
579
|
-
const
|
|
583
|
+
const ink = rowInk(colors, isActive, isHighlighted);
|
|
580
584
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
581
585
|
reactNative.Pressable,
|
|
582
586
|
{
|
|
@@ -585,11 +589,11 @@ function OptionRow({ option, isActive, isHighlighted, isListboxRow, menuWidth, h
|
|
|
585
589
|
accessibilityHint: hint,
|
|
586
590
|
accessibilityState: { selected: isActive },
|
|
587
591
|
onPress: () => onSelect(option.value),
|
|
588
|
-
style: [controlStyles.option, isHighlighted ? { backgroundColor: colors.
|
|
592
|
+
style: [controlStyles.option, isHighlighted ? { backgroundColor: colors.text } : null],
|
|
589
593
|
testID: `${testID}-option-${option.value}`,
|
|
590
594
|
children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: isDetailBesideTitle(menuWidth) ? styles7.beside : styles7.stacked, children: [
|
|
591
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [controlStyles.optionText, styles7.shrink, { color:
|
|
592
|
-
hasDetail ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles7.detail, { color:
|
|
595
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [controlStyles.optionText, styles7.shrink, { color: ink.title, fontWeight: isBold ? ACTIVE_WEIGHT : IDLE_WEIGHT }], children: option.label }),
|
|
596
|
+
hasDetail ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles7.detail, { color: ink.detail }], children: option.detail }) : null
|
|
593
597
|
] })
|
|
594
598
|
}
|
|
595
599
|
);
|
|
@@ -1761,6 +1765,24 @@ function SelectControl({
|
|
|
1761
1765
|
) : null
|
|
1762
1766
|
] });
|
|
1763
1767
|
}
|
|
1768
|
+
var CLOSE_DELAY_MS2 = 140;
|
|
1769
|
+
function useDelayedBlurClose(open, close) {
|
|
1770
|
+
const timerRef = React2.useRef(null);
|
|
1771
|
+
const cancelClose = React2.useCallback(() => {
|
|
1772
|
+
if (timerRef.current !== null) clearTimeout(timerRef.current);
|
|
1773
|
+
timerRef.current = null;
|
|
1774
|
+
}, []);
|
|
1775
|
+
React2.useEffect(() => cancelClose, [cancelClose]);
|
|
1776
|
+
const handleFocus = React2.useCallback(() => {
|
|
1777
|
+
cancelClose();
|
|
1778
|
+
open();
|
|
1779
|
+
}, [cancelClose, open]);
|
|
1780
|
+
const handleBlur = React2.useCallback(() => {
|
|
1781
|
+
cancelClose();
|
|
1782
|
+
timerRef.current = setTimeout(close, CLOSE_DELAY_MS2);
|
|
1783
|
+
}, [cancelClose, close]);
|
|
1784
|
+
return { handleFocus, handleBlur };
|
|
1785
|
+
}
|
|
1764
1786
|
|
|
1765
1787
|
// src/controls/suggestOptions.ts
|
|
1766
1788
|
var RANK_VALUE_EXACT = 0;
|
|
@@ -1926,7 +1948,6 @@ function useTypeaheadKeys(input) {
|
|
|
1926
1948
|
[rowCount, isOpen, highlighted, setIsOpen, setHighlightIndex, close, pick]
|
|
1927
1949
|
);
|
|
1928
1950
|
}
|
|
1929
|
-
var CLOSE_DELAY_MS2 = 140;
|
|
1930
1951
|
var DEFAULT_TYPEAHEAD_MIN_CHARS = 1;
|
|
1931
1952
|
var DEFAULT_TYPEAHEAD_MAX_SUGGESTIONS = 8;
|
|
1932
1953
|
function comboboxAria(testID, isExpanded, highlighted) {
|
|
@@ -1948,6 +1969,7 @@ function TypeaheadControlImpl(props, ref) {
|
|
|
1948
1969
|
const { colors, palette } = theme;
|
|
1949
1970
|
const anchorRef = React2.useRef(null);
|
|
1950
1971
|
const state = useTypeaheadState({ options, search, value, minChars, maxSuggestions, onChange, onSubmit });
|
|
1972
|
+
const { handleFocus, handleBlur } = useDelayedBlurClose(state.open, state.close);
|
|
1951
1973
|
const showMenu = state.isOpen && (state.rows.length > 0 || state.statusText !== void 0);
|
|
1952
1974
|
const isExpanded = state.isOpen && state.rows.length > 0;
|
|
1953
1975
|
const hasError = error !== void 0 && error !== "";
|
|
@@ -1971,8 +1993,8 @@ function TypeaheadControlImpl(props, ref) {
|
|
|
1971
1993
|
spellCheck: false,
|
|
1972
1994
|
value,
|
|
1973
1995
|
onChangeText: state.handleChange,
|
|
1974
|
-
onFocus:
|
|
1975
|
-
onBlur:
|
|
1996
|
+
onFocus: handleFocus,
|
|
1997
|
+
onBlur: handleBlur,
|
|
1976
1998
|
onKeyPress: state.handleKeyPress,
|
|
1977
1999
|
onSubmitEditing: state.handleSubmit,
|
|
1978
2000
|
style: [controlStyles.input, { borderColor: hasError ? fieldErrorInk(theme) : colors.border, backgroundColor: colors.surface, color: colors.text }],
|
|
@@ -2234,6 +2256,18 @@ function useFocusFirstInvalid(refs) {
|
|
|
2234
2256
|
first?.focus();
|
|
2235
2257
|
}, []);
|
|
2236
2258
|
}
|
|
2259
|
+
function isScrollable(node) {
|
|
2260
|
+
return "scrollIntoView" in Object(node);
|
|
2261
|
+
}
|
|
2262
|
+
function useKeepInView(trigger) {
|
|
2263
|
+
const ref = React2.useRef(null);
|
|
2264
|
+
React2.useEffect(() => {
|
|
2265
|
+
const node = ref.current;
|
|
2266
|
+
const hasTrigger = trigger !== void 0 && trigger !== null;
|
|
2267
|
+
if (hasTrigger && isScrollable(node)) node.scrollIntoView({ block: "nearest" });
|
|
2268
|
+
}, [trigger]);
|
|
2269
|
+
return ref;
|
|
2270
|
+
}
|
|
2237
2271
|
var DEFAULT_PREVIEW_PX = 48;
|
|
2238
2272
|
var PREVIEW_RADIUS = 8;
|
|
2239
2273
|
var GAP = 8;
|
|
@@ -2333,6 +2367,7 @@ exports.resolveStepNeighbours = resolveStepNeighbours;
|
|
|
2333
2367
|
exports.suggestOptions = suggestOptions;
|
|
2334
2368
|
exports.toggleGroupSelection = toggleGroupSelection;
|
|
2335
2369
|
exports.useFocusFirstInvalid = useFocusFirstInvalid;
|
|
2370
|
+
exports.useKeepInView = useKeepInView;
|
|
2336
2371
|
exports.useRecentValues = useRecentValues;
|
|
2337
2372
|
exports.useThemedInput = useThemedInput;
|
|
2338
2373
|
//# sourceMappingURL=index.js.map
|