@dloizides/ui-forms 1.7.0 → 1.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/CHANGELOG.md +280 -166
- package/README.md +42 -0
- package/dist/index.d.mts +450 -5
- package/dist/index.d.ts +450 -5
- package/dist/index.js +600 -49
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +590 -51
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -42,6 +42,40 @@ function resolveFieldMarker(required, optional) {
|
|
|
42
42
|
if (optional) return "optional";
|
|
43
43
|
return "none";
|
|
44
44
|
}
|
|
45
|
+
var FIELD_STACK_MARGIN_BOTTOM = 16;
|
|
46
|
+
var FIELD_STACK_LABEL_MARGIN_BOTTOM = 4;
|
|
47
|
+
var FIELD_STACK_CHILD_MARGIN_TOP = 4;
|
|
48
|
+
var FIELD_CONTRACT_GAP = 6;
|
|
49
|
+
var fieldSpacingStyles = reactNative.StyleSheet.create({
|
|
50
|
+
stackContainer: { marginBottom: FIELD_STACK_MARGIN_BOTTOM },
|
|
51
|
+
stackLabel: { marginBottom: FIELD_STACK_LABEL_MARGIN_BOTTOM },
|
|
52
|
+
stackChild: { marginTop: FIELD_STACK_CHILD_MARGIN_TOP },
|
|
53
|
+
/**
|
|
54
|
+
* The gap model sets NO margins — not even zeroed ones. An explicit `marginBottom: 0` here would
|
|
55
|
+
* defeat a caller who legitimately wants to push one field down via `containerStyle`, because
|
|
56
|
+
* `containerStyle` composes AFTER this and a zero is indistinguishable from "unset" to a reader.
|
|
57
|
+
*/
|
|
58
|
+
gapContainer: { gap: FIELD_CONTRACT_GAP },
|
|
59
|
+
none: {}
|
|
60
|
+
});
|
|
61
|
+
function resolveFieldSpacing(explicit, insideGrid) {
|
|
62
|
+
if (explicit !== void 0) return explicit;
|
|
63
|
+
return insideGrid ? "gap" : "stack";
|
|
64
|
+
}
|
|
65
|
+
function fieldSpacingStyleSet(spacing) {
|
|
66
|
+
if (spacing === "gap") {
|
|
67
|
+
return {
|
|
68
|
+
container: fieldSpacingStyles.gapContainer,
|
|
69
|
+
label: fieldSpacingStyles.none,
|
|
70
|
+
child: fieldSpacingStyles.none
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
container: fieldSpacingStyles.stackContainer,
|
|
75
|
+
label: fieldSpacingStyles.stackLabel,
|
|
76
|
+
child: fieldSpacingStyles.stackChild
|
|
77
|
+
};
|
|
78
|
+
}
|
|
45
79
|
var FIELD_FONT_SIZE = 13;
|
|
46
80
|
var FIELD_FONT_WEIGHT = "600";
|
|
47
81
|
var CONTROL_FONT_SIZE = 11;
|
|
@@ -62,27 +96,25 @@ var labelVariantStyles = reactNative.StyleSheet.create({
|
|
|
62
96
|
function resolveLabelVariantStyle(variant) {
|
|
63
97
|
return variant === "control" ? labelVariantStyles.control : labelVariantStyles.field;
|
|
64
98
|
}
|
|
65
|
-
var
|
|
66
|
-
var
|
|
99
|
+
var FormGridContext = React__default.default.createContext(null);
|
|
100
|
+
var GapOwnedContext = React__default.default.createContext(false);
|
|
101
|
+
var FormGridProvider = FormGridContext.Provider;
|
|
102
|
+
var GapOwnedProvider = GapOwnedContext.Provider;
|
|
103
|
+
function useFormGridMetrics() {
|
|
104
|
+
return React__default.default.useContext(FormGridContext);
|
|
105
|
+
}
|
|
106
|
+
function useIsGapOwned() {
|
|
107
|
+
return React__default.default.useContext(GapOwnedContext);
|
|
108
|
+
}
|
|
67
109
|
var ERROR_FONT_SIZE = 12;
|
|
68
|
-
var ERROR_MARGIN_TOP = 4;
|
|
69
110
|
var HINT_FONT_SIZE = 12;
|
|
70
|
-
var HINT_MARGIN_TOP = 4;
|
|
71
111
|
var OPTIONAL_MARK_FONT_WEIGHT = "400";
|
|
72
112
|
var styles = reactNative.StyleSheet.create({
|
|
73
|
-
container: {
|
|
74
|
-
marginBottom: CONTAINER_MARGIN_BOTTOM
|
|
75
|
-
},
|
|
76
|
-
label: {
|
|
77
|
-
marginBottom: LABEL_MARGIN_BOTTOM
|
|
78
|
-
},
|
|
79
113
|
hintText: {
|
|
80
|
-
fontSize: HINT_FONT_SIZE
|
|
81
|
-
marginTop: HINT_MARGIN_TOP
|
|
114
|
+
fontSize: HINT_FONT_SIZE
|
|
82
115
|
},
|
|
83
116
|
errorText: {
|
|
84
|
-
fontSize: ERROR_FONT_SIZE
|
|
85
|
-
marginTop: ERROR_MARGIN_TOP
|
|
117
|
+
fontSize: ERROR_FONT_SIZE
|
|
86
118
|
},
|
|
87
119
|
optionalMark: {
|
|
88
120
|
fontWeight: OPTIONAL_MARK_FONT_WEIGHT
|
|
@@ -118,9 +150,12 @@ var Field = ({
|
|
|
118
150
|
labelVariant,
|
|
119
151
|
labelStyle,
|
|
120
152
|
containerStyle,
|
|
153
|
+
spacing,
|
|
121
154
|
testID
|
|
122
155
|
}) => {
|
|
123
156
|
const { theme } = uiFeedback.useUi();
|
|
157
|
+
const gapOwned = useIsGapOwned();
|
|
158
|
+
const spacingStyles = fieldSpacingStyleSet(resolveFieldSpacing(spacing, gapOwned));
|
|
124
159
|
const { colors, semantic } = theme;
|
|
125
160
|
const errorColor = semantic.error["500"];
|
|
126
161
|
const hasError = hasFieldError(error);
|
|
@@ -142,7 +177,7 @@ var Field = ({
|
|
|
142
177
|
);
|
|
143
178
|
const describedById = joinDescribedBy(hasHint ? hintId : void 0, hasError ? errorId : void 0);
|
|
144
179
|
const control = typeof children === "function" ? children({ describedById, hasError }) : children;
|
|
145
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [
|
|
180
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [spacingStyles.container, containerStyle], testID, children: [
|
|
146
181
|
hasLabel ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
147
182
|
FieldLabel,
|
|
148
183
|
{
|
|
@@ -151,16 +186,107 @@ var Field = ({
|
|
|
151
186
|
optionalLabel,
|
|
152
187
|
optionalMarkStyle: [styles.optionalMark, themeStyles.optionalMark],
|
|
153
188
|
requiredMarkStyle: themeStyles.requiredMark,
|
|
154
|
-
style: [
|
|
189
|
+
style: [spacingStyles.label, resolveLabelVariantStyle(labelVariant), themeStyles.label, labelStyle]
|
|
155
190
|
}
|
|
156
191
|
) : null,
|
|
157
192
|
control,
|
|
158
|
-
hasHint ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { nativeID: hintId, style: [styles.hintText, themeStyles.hintText], children: hint }) : null,
|
|
159
|
-
hasError ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { nativeID: errorId, role: "alert", style: [styles.errorText, themeStyles.errorText], children: error }) : null
|
|
193
|
+
hasHint ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { nativeID: hintId, style: [styles.hintText, spacingStyles.child, themeStyles.hintText], children: hint }) : null,
|
|
194
|
+
hasError ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { nativeID: errorId, role: "alert", style: [styles.errorText, spacingStyles.child, themeStyles.errorText], children: error }) : null
|
|
160
195
|
] });
|
|
161
196
|
};
|
|
162
|
-
var
|
|
197
|
+
var FORM_GRID_DEFAULT_GAP = 12;
|
|
198
|
+
var FORM_GRID_DEFAULT_MIN_WIDTH = 220;
|
|
199
|
+
var FORM_GRID_DEFAULT_BASIS = 260;
|
|
163
200
|
var styles2 = reactNative.StyleSheet.create({
|
|
201
|
+
grid: {
|
|
202
|
+
flexDirection: "row",
|
|
203
|
+
flexWrap: "wrap"
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
var FormGrid = ({
|
|
207
|
+
children,
|
|
208
|
+
gap = FORM_GRID_DEFAULT_GAP,
|
|
209
|
+
minWidth = FORM_GRID_DEFAULT_MIN_WIDTH,
|
|
210
|
+
basis = FORM_GRID_DEFAULT_BASIS,
|
|
211
|
+
style,
|
|
212
|
+
testID
|
|
213
|
+
}) => {
|
|
214
|
+
const metrics = React__default.default.useMemo(() => ({ minWidth, basis }), [minWidth, basis]);
|
|
215
|
+
return /* @__PURE__ */ jsxRuntime.jsx(FormGridProvider, { value: metrics, children: /* @__PURE__ */ jsxRuntime.jsx(GapOwnedProvider, { value: true, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles2.grid, { gap }, style], testID, children }) }) });
|
|
216
|
+
};
|
|
217
|
+
var GROW = 1;
|
|
218
|
+
var NO_GROW = 0;
|
|
219
|
+
var FormCell = ({
|
|
220
|
+
children,
|
|
221
|
+
minWidth,
|
|
222
|
+
basis,
|
|
223
|
+
grow = true,
|
|
224
|
+
style,
|
|
225
|
+
testID
|
|
226
|
+
}) => {
|
|
227
|
+
const metrics = useFormGridMetrics();
|
|
228
|
+
const resolvedMinWidth = minWidth ?? metrics?.minWidth ?? FORM_GRID_DEFAULT_MIN_WIDTH;
|
|
229
|
+
const resolvedBasis = basis ?? metrics?.basis ?? FORM_GRID_DEFAULT_BASIS;
|
|
230
|
+
const cellStyle = {
|
|
231
|
+
minWidth: resolvedMinWidth,
|
|
232
|
+
flexBasis: resolvedBasis,
|
|
233
|
+
flexGrow: grow ? GROW : NO_GROW
|
|
234
|
+
};
|
|
235
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [cellStyle, style], testID, children });
|
|
236
|
+
};
|
|
237
|
+
var SECTION_GAP = 10;
|
|
238
|
+
var DESCRIPTION_FONT_SIZE = 12;
|
|
239
|
+
var styles3 = reactNative.StyleSheet.create({
|
|
240
|
+
section: {
|
|
241
|
+
gap: SECTION_GAP
|
|
242
|
+
},
|
|
243
|
+
description: {
|
|
244
|
+
fontSize: DESCRIPTION_FONT_SIZE
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
var sectionSeq = 0;
|
|
248
|
+
function useSectionLegendId() {
|
|
249
|
+
const [id] = React__default.default.useState(() => {
|
|
250
|
+
sectionSeq += 1;
|
|
251
|
+
return `form-section-legend-${String(sectionSeq)}`;
|
|
252
|
+
});
|
|
253
|
+
return id;
|
|
254
|
+
}
|
|
255
|
+
var FormSection = ({
|
|
256
|
+
title,
|
|
257
|
+
description,
|
|
258
|
+
children,
|
|
259
|
+
labelVariant,
|
|
260
|
+
titleStyle,
|
|
261
|
+
style,
|
|
262
|
+
testID
|
|
263
|
+
}) => {
|
|
264
|
+
const { theme } = uiFeedback.useUi();
|
|
265
|
+
const { colors } = theme;
|
|
266
|
+
const legendId = useSectionLegendId();
|
|
267
|
+
const hasTitle = typeof title === "string" && title !== "";
|
|
268
|
+
const hasDescription = typeof description === "string" && description !== "";
|
|
269
|
+
const a11y = { "aria-labelledby": hasTitle ? legendId : void 0 };
|
|
270
|
+
return (
|
|
271
|
+
// The section spaces its children with `gap`, so it owns their vertical rhythm exactly as a
|
|
272
|
+
// `FormGrid` owns a row's — without this a `Field` placed directly in a section would stack its
|
|
273
|
+
// 16px margin on the section's gap and recreate the F3 bug one level up.
|
|
274
|
+
/* @__PURE__ */ jsxRuntime.jsx(GapOwnedProvider, { value: true, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { role: "group", style: [styles3.section, style], testID, ...a11y, children: [
|
|
275
|
+
hasTitle ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
276
|
+
reactNative.Text,
|
|
277
|
+
{
|
|
278
|
+
nativeID: legendId,
|
|
279
|
+
style: [resolveLabelVariantStyle(labelVariant), { color: colors.text }, titleStyle],
|
|
280
|
+
children: title
|
|
281
|
+
}
|
|
282
|
+
) : null,
|
|
283
|
+
hasDescription ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles3.description, { color: colors.textSecondary }], children: description }) : null,
|
|
284
|
+
children
|
|
285
|
+
] }) })
|
|
286
|
+
);
|
|
287
|
+
};
|
|
288
|
+
var ACTIONS_GAP = 12;
|
|
289
|
+
var styles4 = reactNative.StyleSheet.create({
|
|
164
290
|
container: {
|
|
165
291
|
flexDirection: "row",
|
|
166
292
|
justifyContent: "flex-end",
|
|
@@ -180,7 +306,7 @@ var FormActions = ({
|
|
|
180
306
|
saveTestID = "save-button",
|
|
181
307
|
cancelTestID = "cancel-button",
|
|
182
308
|
testID
|
|
183
|
-
}) => /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [
|
|
309
|
+
}) => /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles4.container, containerStyle], testID, children: [
|
|
184
310
|
typeof onCancel === "function" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
185
311
|
uiButtons.Button,
|
|
186
312
|
{
|
|
@@ -333,7 +459,7 @@ var INPUT_PADDING_V = 10;
|
|
|
333
459
|
var INPUT_PADDING_H = 12;
|
|
334
460
|
var INPUT_BORDER_RADIUS = 8;
|
|
335
461
|
var INPUT_BORDER_WIDTH = 1;
|
|
336
|
-
var
|
|
462
|
+
var styles5 = reactNative.StyleSheet.create({
|
|
337
463
|
input: {
|
|
338
464
|
paddingVertical: INPUT_PADDING_V,
|
|
339
465
|
paddingHorizontal: INPUT_PADDING_H,
|
|
@@ -355,7 +481,7 @@ var FormField = ({
|
|
|
355
481
|
describedById,
|
|
356
482
|
hasError,
|
|
357
483
|
requiredField: required,
|
|
358
|
-
style:
|
|
484
|
+
style: styles5.input,
|
|
359
485
|
testID: "form-field-input",
|
|
360
486
|
...textInputProps
|
|
361
487
|
}
|
|
@@ -393,18 +519,22 @@ function withAlpha2(hex, alpha) {
|
|
|
393
519
|
const isValid = !Number.isNaN(r) && !Number.isNaN(g) && !Number.isNaN(b);
|
|
394
520
|
return isValid ? `rgba(${r}, ${g}, ${b}, ${alpha})` : hex;
|
|
395
521
|
}
|
|
396
|
-
var
|
|
522
|
+
var styles6 = reactNative.StyleSheet.create({
|
|
397
523
|
chipContainer: {
|
|
398
524
|
flexDirection: "row",
|
|
399
525
|
flexWrap: "wrap",
|
|
400
|
-
//
|
|
401
|
-
//
|
|
402
|
-
//
|
|
403
|
-
marginBottom: -
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
526
|
+
// `gap`, NOT per-chip margins plus a compensating negative container margin.
|
|
527
|
+
//
|
|
528
|
+
// The old form was `chipWrapper { marginRight: 8, marginBottom: 8 }` with
|
|
529
|
+
// `chipContainer { marginBottom: -8 }`. Its comment blamed `Field`'s 16px container margin —
|
|
530
|
+
// that was WRONG, and worth recording: F3 was briefed on the belief that the -8 compensated for
|
|
531
|
+
// `Field` and had to move in lockstep with it. It did not. -8 cancelled the CHIP's own gutter
|
|
532
|
+
// hanging off the last row, identically whether `Field` contributed 16, 0, or anything else.
|
|
533
|
+
//
|
|
534
|
+
// The pair is still the wrong tool: it holds only while the two constants agree, and it leaves
|
|
535
|
+
// a real negative margin any measuring parent inherits. `gap` produces the byte-identical box
|
|
536
|
+
// and is correct under BOTH of `Field`'s spacing models, not just the one it was tuned against.
|
|
537
|
+
gap: CHIP_GUTTER
|
|
408
538
|
},
|
|
409
539
|
chip: {
|
|
410
540
|
paddingHorizontal: 12,
|
|
@@ -456,12 +586,11 @@ function OutlineChip({
|
|
|
456
586
|
"aria-pressed": ariaPressed,
|
|
457
587
|
disabled,
|
|
458
588
|
hitSlop: CHIP_HIT_SLOP,
|
|
459
|
-
style: styles4.chipWrapper,
|
|
460
589
|
testID,
|
|
461
590
|
onHoverIn: () => setHovered(true),
|
|
462
591
|
onHoverOut: () => setHovered(false),
|
|
463
592
|
onPress,
|
|
464
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [
|
|
593
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles6.chipOutline, { borderColor, backgroundColor }], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles6.chipText, styles6.chipTextOutline, { color: textColor }], children: option.label }) })
|
|
465
594
|
}
|
|
466
595
|
);
|
|
467
596
|
}
|
|
@@ -487,10 +616,9 @@ function SolidChip({
|
|
|
487
616
|
"aria-pressed": ariaPressed,
|
|
488
617
|
disabled,
|
|
489
618
|
hitSlop: CHIP_HIT_SLOP,
|
|
490
|
-
style: styles4.chipWrapper,
|
|
491
619
|
testID,
|
|
492
620
|
onPress,
|
|
493
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [
|
|
621
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles6.chip, { borderColor: colors.border, backgroundColor }], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles6.chipText, { color: textColor }], children: option.label }) })
|
|
494
622
|
}
|
|
495
623
|
);
|
|
496
624
|
}
|
|
@@ -508,6 +636,7 @@ var ChipSelector = ({
|
|
|
508
636
|
disabled = false,
|
|
509
637
|
variant = "solid",
|
|
510
638
|
containerStyle,
|
|
639
|
+
spacing,
|
|
511
640
|
required = false,
|
|
512
641
|
error,
|
|
513
642
|
testID,
|
|
@@ -550,10 +679,21 @@ var ChipSelector = ({
|
|
|
550
679
|
const key = String(option.value);
|
|
551
680
|
return variant === "outline" ? /* @__PURE__ */ jsxRuntime.jsx(OutlineChip, { ...chipProps }, key) : /* @__PURE__ */ jsxRuntime.jsx(SolidChip, { ...chipProps }, key);
|
|
552
681
|
}
|
|
553
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
682
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
683
|
+
Field,
|
|
684
|
+
{
|
|
685
|
+
containerStyle,
|
|
686
|
+
error,
|
|
687
|
+
label,
|
|
688
|
+
required,
|
|
689
|
+
spacing,
|
|
690
|
+
testID,
|
|
691
|
+
children: ({ describedById, hasError }) => /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles6.chipContainer, ...groupA11yProps(describedById, hasError), children: options.map(renderChip) })
|
|
692
|
+
}
|
|
693
|
+
);
|
|
554
694
|
};
|
|
555
|
-
var
|
|
556
|
-
var
|
|
695
|
+
var DESCRIPTION_FONT_SIZE2 = 12;
|
|
696
|
+
var styles7 = reactNative.StyleSheet.create({
|
|
557
697
|
container: {
|
|
558
698
|
flexDirection: "row",
|
|
559
699
|
justifyContent: "space-between",
|
|
@@ -567,7 +707,7 @@ var styles5 = reactNative.StyleSheet.create({
|
|
|
567
707
|
fontWeight: "600"
|
|
568
708
|
},
|
|
569
709
|
description: {
|
|
570
|
-
fontSize:
|
|
710
|
+
fontSize: DESCRIPTION_FONT_SIZE2,
|
|
571
711
|
marginTop: 2
|
|
572
712
|
}
|
|
573
713
|
});
|
|
@@ -593,13 +733,13 @@ var FormSwitch = ({
|
|
|
593
733
|
reactNative.View,
|
|
594
734
|
{
|
|
595
735
|
style: [
|
|
596
|
-
|
|
736
|
+
styles7.container,
|
|
597
737
|
containerStyle
|
|
598
738
|
],
|
|
599
739
|
children: [
|
|
600
|
-
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
601
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
602
|
-
hasDescription ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
740
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles7.textColumn, children: [
|
|
741
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles7.label, themeStyles.label], children: label }),
|
|
742
|
+
hasDescription ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles7.description, themeStyles.description], children: description }) : null
|
|
603
743
|
] }),
|
|
604
744
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
605
745
|
reactNative.Switch,
|
|
@@ -624,7 +764,7 @@ var BOX_SIZE = 20;
|
|
|
624
764
|
var BOX_RADIUS = 5;
|
|
625
765
|
var CHECK_FONT_SIZE = 14;
|
|
626
766
|
var DISABLED_OPACITY = 0.5;
|
|
627
|
-
var
|
|
767
|
+
var styles8 = reactNative.StyleSheet.create({
|
|
628
768
|
container: {
|
|
629
769
|
flexDirection: "row",
|
|
630
770
|
alignItems: "flex-start",
|
|
@@ -706,28 +846,439 @@ var FormCheckbox = ({
|
|
|
706
846
|
disabled,
|
|
707
847
|
onPress: toggle,
|
|
708
848
|
role: "checkbox",
|
|
709
|
-
style: [
|
|
849
|
+
style: [styles8.container, containerStyle, disabled ? { opacity: DISABLED_OPACITY } : null],
|
|
710
850
|
testID,
|
|
711
851
|
...keyboardProps,
|
|
712
852
|
children: [
|
|
713
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [
|
|
714
|
-
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
715
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
716
|
-
hasHint ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
853
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles8.box, value ? themeStyles.boxOn : themeStyles.boxOff], children: value ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles8.check, { color: colors.surface }], accessibilityElementsHidden: true, children: "\u2713" }) : null }),
|
|
854
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles8.textColumn, children: [
|
|
855
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles8.label, themeStyles.label], children: label }),
|
|
856
|
+
hasHint ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles8.hint, themeStyles.hint], children: hintText }) : null
|
|
717
857
|
] })
|
|
718
858
|
]
|
|
719
859
|
}
|
|
720
860
|
);
|
|
721
861
|
};
|
|
862
|
+
var FIELD_GAP = 4;
|
|
863
|
+
var LABEL_FONT = 11;
|
|
864
|
+
var LABEL_LETTER_SPACING = 0.4;
|
|
865
|
+
var INPUT_RADIUS = 8;
|
|
866
|
+
var INPUT_PAD_H = 12;
|
|
867
|
+
var INPUT_PAD_V = 10;
|
|
868
|
+
var INPUT_FONT = 14;
|
|
869
|
+
var INPUT_BORDER = 1;
|
|
870
|
+
var DATE_ROW_GAP = 8;
|
|
871
|
+
var CHEVRON_FONT = 10;
|
|
872
|
+
var MENU_TOP_GAP = 4;
|
|
873
|
+
var MENU_RADIUS = 8;
|
|
874
|
+
var MENU_PAD_V = 4;
|
|
875
|
+
var MENU_OPT_PAD_H = 12;
|
|
876
|
+
var MENU_OPT_PAD_V = 8;
|
|
877
|
+
var MENU_MIN_WIDTH = 160;
|
|
878
|
+
var MENU_MAX_HEIGHT = 260;
|
|
879
|
+
var MENU_Z = 1e3;
|
|
880
|
+
var MENU_ELEVATION = 8;
|
|
881
|
+
var MENU_BOX_SHADOW = "0px 2px 8px rgba(0, 0, 0, 0.15)";
|
|
882
|
+
var OPTION_FONT = 14;
|
|
883
|
+
var ERROR_FONT = 12;
|
|
884
|
+
var ERROR_GAP = 3;
|
|
885
|
+
var controlStyles = reactNative.StyleSheet.create({
|
|
886
|
+
/** The shared bordered box every dense text control renders in. */
|
|
887
|
+
input: {
|
|
888
|
+
borderWidth: INPUT_BORDER,
|
|
889
|
+
borderRadius: INPUT_RADIUS,
|
|
890
|
+
paddingHorizontal: INPUT_PAD_H,
|
|
891
|
+
paddingVertical: INPUT_PAD_V,
|
|
892
|
+
fontSize: INPUT_FONT
|
|
893
|
+
},
|
|
894
|
+
/** The select trigger: a bordered field box matching the text inputs + a chevron. */
|
|
895
|
+
selectTrigger: {
|
|
896
|
+
flexDirection: "row",
|
|
897
|
+
alignItems: "center",
|
|
898
|
+
justifyContent: "space-between",
|
|
899
|
+
gap: DATE_ROW_GAP,
|
|
900
|
+
borderWidth: INPUT_BORDER,
|
|
901
|
+
borderRadius: INPUT_RADIUS,
|
|
902
|
+
paddingHorizontal: INPUT_PAD_H,
|
|
903
|
+
paddingVertical: INPUT_PAD_V
|
|
904
|
+
},
|
|
905
|
+
selectTriggerText: { fontSize: INPUT_FONT, flexShrink: 1 },
|
|
906
|
+
chevron: { fontSize: CHEVRON_FONT },
|
|
907
|
+
dateRow: { flexDirection: "row", gap: DATE_ROW_GAP },
|
|
908
|
+
dateCol: { gap: FIELD_GAP, flex: 1 },
|
|
909
|
+
/**
|
|
910
|
+
* The micro-caption above a sub-control (a date range's From/To) and beside a switch. Note it
|
|
911
|
+
* is deliberately NOT the `control` label voice: it carries no `700`/uppercase, because it
|
|
912
|
+
* names a HALF of a control that already has a `control`-voice label above it. Uppercasing it
|
|
913
|
+
* too would make one field shout twice.
|
|
914
|
+
*/
|
|
915
|
+
subLabel: { fontSize: LABEL_FONT, letterSpacing: LABEL_LETTER_SPACING },
|
|
916
|
+
/** Positioning context for a floating `AnchoredMenu` (`position:absolute; top:100%`). */
|
|
917
|
+
anchor: { position: "relative" },
|
|
918
|
+
menu: {
|
|
919
|
+
position: "absolute",
|
|
920
|
+
top: "100%",
|
|
921
|
+
left: 0,
|
|
922
|
+
marginTop: MENU_TOP_GAP,
|
|
923
|
+
minWidth: MENU_MIN_WIDTH,
|
|
924
|
+
maxHeight: MENU_MAX_HEIGHT,
|
|
925
|
+
borderWidth: INPUT_BORDER,
|
|
926
|
+
borderRadius: MENU_RADIUS,
|
|
927
|
+
paddingVertical: MENU_PAD_V,
|
|
928
|
+
zIndex: MENU_Z,
|
|
929
|
+
boxShadow: MENU_BOX_SHADOW,
|
|
930
|
+
elevation: MENU_ELEVATION,
|
|
931
|
+
overflow: "hidden"
|
|
932
|
+
},
|
|
933
|
+
option: { paddingHorizontal: MENU_OPT_PAD_H, paddingVertical: MENU_OPT_PAD_V },
|
|
934
|
+
optionText: { fontSize: OPTION_FONT },
|
|
935
|
+
error: { fontSize: ERROR_FONT, marginTop: ERROR_GAP }
|
|
936
|
+
});
|
|
937
|
+
var IS_WEB4 = typeof document !== "undefined";
|
|
938
|
+
var ESCAPE_KEY = "Escape";
|
|
939
|
+
var ACTIVE_WEIGHT = "700";
|
|
940
|
+
var IDLE_WEIGHT = "400";
|
|
941
|
+
function useDismiss(anchorRef, menuRef, onDismiss) {
|
|
942
|
+
React.useEffect(() => {
|
|
943
|
+
if (!IS_WEB4) return void 0;
|
|
944
|
+
const onMouseDown = (event) => {
|
|
945
|
+
const anchorNode = anchorRef.current;
|
|
946
|
+
const menuNode = menuRef.current;
|
|
947
|
+
const target = event.target instanceof Node ? event.target : null;
|
|
948
|
+
const insideAnchor = anchorNode !== null && target !== null && anchorNode.contains(target);
|
|
949
|
+
const insideMenu = menuNode !== null && target !== null && menuNode.contains(target);
|
|
950
|
+
if (!insideAnchor && !insideMenu) onDismiss();
|
|
951
|
+
};
|
|
952
|
+
const onKeyDown = (event) => {
|
|
953
|
+
if (event.key === ESCAPE_KEY) onDismiss();
|
|
954
|
+
};
|
|
955
|
+
document.addEventListener("mousedown", onMouseDown);
|
|
956
|
+
document.addEventListener("keydown", onKeyDown);
|
|
957
|
+
return () => {
|
|
958
|
+
document.removeEventListener("mousedown", onMouseDown);
|
|
959
|
+
document.removeEventListener("keydown", onKeyDown);
|
|
960
|
+
};
|
|
961
|
+
}, [anchorRef, menuRef, onDismiss]);
|
|
962
|
+
}
|
|
963
|
+
function AnchoredMenu({
|
|
964
|
+
options,
|
|
965
|
+
selectedValue,
|
|
966
|
+
onSelect,
|
|
967
|
+
onDismiss,
|
|
968
|
+
colors,
|
|
969
|
+
optionHint,
|
|
970
|
+
testID,
|
|
971
|
+
anchorRef
|
|
972
|
+
}) {
|
|
973
|
+
const menuRef = React__default.default.useRef(null);
|
|
974
|
+
useDismiss(anchorRef, menuRef, onDismiss);
|
|
975
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
976
|
+
reactNative.View,
|
|
977
|
+
{
|
|
978
|
+
ref: menuRef,
|
|
979
|
+
accessibilityRole: "menu",
|
|
980
|
+
style: [controlStyles.menu, { borderColor: colors.border, backgroundColor: colors.surface }],
|
|
981
|
+
testID: `${testID}-menu`,
|
|
982
|
+
children: options.map((opt) => {
|
|
983
|
+
const active = opt.value === selectedValue;
|
|
984
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
985
|
+
reactNative.Pressable,
|
|
986
|
+
{
|
|
987
|
+
accessibilityRole: "menuitem",
|
|
988
|
+
accessibilityLabel: opt.label,
|
|
989
|
+
accessibilityHint: optionHint,
|
|
990
|
+
accessibilityState: { selected: active },
|
|
991
|
+
"aria-selected": active,
|
|
992
|
+
onPress: () => onSelect(opt.value),
|
|
993
|
+
style: controlStyles.option,
|
|
994
|
+
testID: `${testID}-option-${opt.value}`,
|
|
995
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [controlStyles.optionText, { color: active ? colors.brand : colors.text, fontWeight: active ? ACTIVE_WEIGHT : IDLE_WEIGHT }], children: opt.label })
|
|
996
|
+
},
|
|
997
|
+
opt.value
|
|
998
|
+
);
|
|
999
|
+
})
|
|
1000
|
+
}
|
|
1001
|
+
);
|
|
1002
|
+
}
|
|
1003
|
+
var CHEVRON_DOWN = "\u25BE";
|
|
1004
|
+
var CHEVRON_UP = "\u25B4";
|
|
1005
|
+
function SelectControl({
|
|
1006
|
+
options,
|
|
1007
|
+
value,
|
|
1008
|
+
onChange,
|
|
1009
|
+
placeholder = "",
|
|
1010
|
+
accessibilityLabel,
|
|
1011
|
+
accessibilityHint,
|
|
1012
|
+
optionHint = "",
|
|
1013
|
+
style,
|
|
1014
|
+
testID
|
|
1015
|
+
}) {
|
|
1016
|
+
const { theme } = uiFeedback.useUi();
|
|
1017
|
+
const { colors, palette } = theme;
|
|
1018
|
+
const anchorRef = React.useRef(null);
|
|
1019
|
+
const [isOpen, setIsOpen] = React.useState(false);
|
|
1020
|
+
const selectedLabel = React.useMemo(() => {
|
|
1021
|
+
const found = options.find((o) => o.value === value);
|
|
1022
|
+
return found?.label ?? placeholder;
|
|
1023
|
+
}, [options, placeholder, value]);
|
|
1024
|
+
const close = React.useCallback(() => {
|
|
1025
|
+
setIsOpen(false);
|
|
1026
|
+
}, []);
|
|
1027
|
+
const toggle = React.useCallback(() => {
|
|
1028
|
+
setIsOpen((prev) => !prev);
|
|
1029
|
+
}, []);
|
|
1030
|
+
const select = React.useCallback(
|
|
1031
|
+
(next) => {
|
|
1032
|
+
onChange(next);
|
|
1033
|
+
setIsOpen(false);
|
|
1034
|
+
},
|
|
1035
|
+
[onChange]
|
|
1036
|
+
);
|
|
1037
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { ref: anchorRef, style: [controlStyles.anchor, style], children: [
|
|
1038
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1039
|
+
reactNative.Pressable,
|
|
1040
|
+
{
|
|
1041
|
+
accessibilityRole: "button",
|
|
1042
|
+
accessibilityLabel,
|
|
1043
|
+
accessibilityHint,
|
|
1044
|
+
accessibilityState: { expanded: isOpen },
|
|
1045
|
+
"aria-expanded": isOpen,
|
|
1046
|
+
onPress: toggle,
|
|
1047
|
+
style: [controlStyles.selectTrigger, { borderColor: colors.border, backgroundColor: colors.surface }],
|
|
1048
|
+
testID: `${testID}-trigger`,
|
|
1049
|
+
children: [
|
|
1050
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { numberOfLines: 1, style: [controlStyles.selectTriggerText, { color: value === "" ? colors.textSecondary : colors.text }], children: selectedLabel }),
|
|
1051
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { "aria-hidden": true, style: [controlStyles.chevron, { color: colors.textSecondary }], children: isOpen ? CHEVRON_UP : CHEVRON_DOWN })
|
|
1052
|
+
]
|
|
1053
|
+
}
|
|
1054
|
+
),
|
|
1055
|
+
isOpen ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1056
|
+
AnchoredMenu,
|
|
1057
|
+
{
|
|
1058
|
+
options,
|
|
1059
|
+
selectedValue: value,
|
|
1060
|
+
onSelect: select,
|
|
1061
|
+
onDismiss: close,
|
|
1062
|
+
colors: { text: colors.text, border: colors.border, surface: colors.surface, brand: palette.primary["500"] },
|
|
1063
|
+
optionHint,
|
|
1064
|
+
testID,
|
|
1065
|
+
anchorRef
|
|
1066
|
+
}
|
|
1067
|
+
) : null
|
|
1068
|
+
] });
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
// src/controls/suggestOptions.ts
|
|
1072
|
+
var RANK_VALUE_EXACT = 0;
|
|
1073
|
+
var RANK_VALUE_PREFIX = 1;
|
|
1074
|
+
var RANK_LABEL_PREFIX = 2;
|
|
1075
|
+
var RANK_LABEL_CONTAINS = 3;
|
|
1076
|
+
var NO_MATCH = -1;
|
|
1077
|
+
function rankOf(option, needle) {
|
|
1078
|
+
const value = option.value.toLowerCase();
|
|
1079
|
+
const label = option.label.toLowerCase();
|
|
1080
|
+
if (value === needle) return RANK_VALUE_EXACT;
|
|
1081
|
+
if (value.startsWith(needle)) return RANK_VALUE_PREFIX;
|
|
1082
|
+
if (label.startsWith(needle)) return RANK_LABEL_PREFIX;
|
|
1083
|
+
if (label.includes(needle)) return RANK_LABEL_CONTAINS;
|
|
1084
|
+
return NO_MATCH;
|
|
1085
|
+
}
|
|
1086
|
+
function suggestOptions(options, query, minChars, limit) {
|
|
1087
|
+
const needle = query.trim().toLowerCase();
|
|
1088
|
+
if (needle.length < minChars) return [];
|
|
1089
|
+
const scored = [];
|
|
1090
|
+
for (const option of options) {
|
|
1091
|
+
const rank = rankOf(option, needle);
|
|
1092
|
+
if (rank !== NO_MATCH) scored.push({ option, rank });
|
|
1093
|
+
}
|
|
1094
|
+
scored.sort((a, b) => a.rank !== b.rank ? a.rank - b.rank : a.option.label.localeCompare(b.option.label));
|
|
1095
|
+
return scored.slice(0, limit).map((entry) => entry.option);
|
|
1096
|
+
}
|
|
1097
|
+
function isUnmatched(options, text) {
|
|
1098
|
+
const needle = text.trim().toLowerCase();
|
|
1099
|
+
if (needle === "") return false;
|
|
1100
|
+
return !options.some((o) => o.value.toLowerCase() === needle || o.label.toLowerCase() === needle);
|
|
1101
|
+
}
|
|
1102
|
+
var CLOSE_DELAY_MS = 140;
|
|
1103
|
+
var DEFAULT_TYPEAHEAD_MIN_CHARS = 1;
|
|
1104
|
+
var DEFAULT_TYPEAHEAD_MAX_SUGGESTIONS = 8;
|
|
1105
|
+
function TypeaheadControl({
|
|
1106
|
+
options,
|
|
1107
|
+
value,
|
|
1108
|
+
onChange,
|
|
1109
|
+
onSubmit,
|
|
1110
|
+
placeholder,
|
|
1111
|
+
accessibilityLabel,
|
|
1112
|
+
accessibilityHint,
|
|
1113
|
+
optionHint = "",
|
|
1114
|
+
error,
|
|
1115
|
+
minChars = DEFAULT_TYPEAHEAD_MIN_CHARS,
|
|
1116
|
+
maxSuggestions = DEFAULT_TYPEAHEAD_MAX_SUGGESTIONS,
|
|
1117
|
+
style,
|
|
1118
|
+
testID
|
|
1119
|
+
}) {
|
|
1120
|
+
const { theme } = uiFeedback.useUi();
|
|
1121
|
+
const { colors, palette, semantic } = theme;
|
|
1122
|
+
const anchorRef = React.useRef(null);
|
|
1123
|
+
const [isOpen, setIsOpen] = React.useState(false);
|
|
1124
|
+
const exactPick = React.useMemo(() => options.some((o) => o.label === value), [options, value]);
|
|
1125
|
+
const suggestions = React.useMemo(
|
|
1126
|
+
() => exactPick ? [] : suggestOptions(options, value, minChars, maxSuggestions),
|
|
1127
|
+
[exactPick, options, value, minChars, maxSuggestions]
|
|
1128
|
+
);
|
|
1129
|
+
const showMenu = isOpen && suggestions.length > 0;
|
|
1130
|
+
const handleChange = React.useCallback(
|
|
1131
|
+
(next) => {
|
|
1132
|
+
onChange(next);
|
|
1133
|
+
setIsOpen(true);
|
|
1134
|
+
},
|
|
1135
|
+
[onChange]
|
|
1136
|
+
);
|
|
1137
|
+
const pick = React.useCallback(
|
|
1138
|
+
(optionValue) => {
|
|
1139
|
+
const opt = options.find((o) => o.value === optionValue);
|
|
1140
|
+
onChange(opt?.label ?? optionValue);
|
|
1141
|
+
setIsOpen(false);
|
|
1142
|
+
},
|
|
1143
|
+
[options, onChange]
|
|
1144
|
+
);
|
|
1145
|
+
const handleBlur = React.useCallback(() => {
|
|
1146
|
+
setTimeout(() => setIsOpen(false), CLOSE_DELAY_MS);
|
|
1147
|
+
}, []);
|
|
1148
|
+
const handleSubmit = React.useCallback(() => {
|
|
1149
|
+
setIsOpen(false);
|
|
1150
|
+
onSubmit?.();
|
|
1151
|
+
}, [onSubmit]);
|
|
1152
|
+
const hasError = error !== void 0 && error !== "";
|
|
1153
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { ref: anchorRef, style: [controlStyles.anchor, style], children: [
|
|
1154
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1155
|
+
reactNative.TextInput,
|
|
1156
|
+
{
|
|
1157
|
+
accessibilityLabel,
|
|
1158
|
+
accessibilityHint,
|
|
1159
|
+
autoCapitalize: "none",
|
|
1160
|
+
autoCorrect: false,
|
|
1161
|
+
placeholder,
|
|
1162
|
+
placeholderTextColor: colors.textSecondary,
|
|
1163
|
+
spellCheck: false,
|
|
1164
|
+
value,
|
|
1165
|
+
onChangeText: handleChange,
|
|
1166
|
+
onFocus: () => setIsOpen(true),
|
|
1167
|
+
onBlur: handleBlur,
|
|
1168
|
+
onSubmitEditing: handleSubmit,
|
|
1169
|
+
style: [controlStyles.input, { borderColor: hasError ? semantic.error["500"] : colors.border, backgroundColor: colors.surface, color: colors.text }],
|
|
1170
|
+
testID: `${testID}-input`
|
|
1171
|
+
}
|
|
1172
|
+
),
|
|
1173
|
+
showMenu ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1174
|
+
AnchoredMenu,
|
|
1175
|
+
{
|
|
1176
|
+
options: suggestions,
|
|
1177
|
+
selectedValue: value,
|
|
1178
|
+
onSelect: pick,
|
|
1179
|
+
onDismiss: () => setIsOpen(false),
|
|
1180
|
+
colors: { text: colors.text, border: colors.border, surface: colors.surface, brand: palette.primary["500"] },
|
|
1181
|
+
optionHint,
|
|
1182
|
+
testID,
|
|
1183
|
+
anchorRef
|
|
1184
|
+
}
|
|
1185
|
+
) : null,
|
|
1186
|
+
hasError ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { role: "alert", style: [controlStyles.error, { color: semantic.error["500"] }], testID: `${testID}-error`, children: error }) : null
|
|
1187
|
+
] });
|
|
1188
|
+
}
|
|
1189
|
+
var WEB_DATE_PROPS = typeof document !== "undefined" ? { type: "date" } : {};
|
|
1190
|
+
function DateInput(p) {
|
|
1191
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: controlStyles.dateCol, children: [
|
|
1192
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [controlStyles.subLabel, { color: p.muted }], children: p.label }),
|
|
1193
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1194
|
+
reactNative.TextInput,
|
|
1195
|
+
{
|
|
1196
|
+
accessibilityLabel: p.label,
|
|
1197
|
+
accessibilityHint: p.hint,
|
|
1198
|
+
placeholder: p.placeholder,
|
|
1199
|
+
placeholderTextColor: p.muted,
|
|
1200
|
+
value: p.value,
|
|
1201
|
+
onChangeText: p.onChangeText,
|
|
1202
|
+
onSubmitEditing: p.onSubmit,
|
|
1203
|
+
style: [controlStyles.input, { borderColor: p.border, backgroundColor: p.surface, color: p.color }],
|
|
1204
|
+
testID: `${p.testID}-${p.side}`,
|
|
1205
|
+
...WEB_DATE_PROPS
|
|
1206
|
+
}
|
|
1207
|
+
)
|
|
1208
|
+
] });
|
|
1209
|
+
}
|
|
1210
|
+
function DateRangeControl({
|
|
1211
|
+
value,
|
|
1212
|
+
onChange,
|
|
1213
|
+
onSubmit,
|
|
1214
|
+
fromLabel,
|
|
1215
|
+
toLabel,
|
|
1216
|
+
fromPlaceholder,
|
|
1217
|
+
toPlaceholder,
|
|
1218
|
+
accessibilityHint,
|
|
1219
|
+
style,
|
|
1220
|
+
testID
|
|
1221
|
+
}) {
|
|
1222
|
+
const { theme } = uiFeedback.useUi();
|
|
1223
|
+
const { colors } = theme;
|
|
1224
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [controlStyles.dateRow, style], testID: `${testID}-range`, children: [
|
|
1225
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1226
|
+
DateInput,
|
|
1227
|
+
{
|
|
1228
|
+
side: "from",
|
|
1229
|
+
label: fromLabel,
|
|
1230
|
+
placeholder: fromPlaceholder,
|
|
1231
|
+
value: value.from,
|
|
1232
|
+
color: colors.text,
|
|
1233
|
+
border: colors.border,
|
|
1234
|
+
surface: colors.surface,
|
|
1235
|
+
muted: colors.textSecondary,
|
|
1236
|
+
hint: accessibilityHint,
|
|
1237
|
+
testID,
|
|
1238
|
+
onChangeText: (from) => onChange({ from, to: value.to }),
|
|
1239
|
+
onSubmit
|
|
1240
|
+
}
|
|
1241
|
+
),
|
|
1242
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1243
|
+
DateInput,
|
|
1244
|
+
{
|
|
1245
|
+
side: "to",
|
|
1246
|
+
label: toLabel,
|
|
1247
|
+
placeholder: toPlaceholder,
|
|
1248
|
+
value: value.to,
|
|
1249
|
+
color: colors.text,
|
|
1250
|
+
border: colors.border,
|
|
1251
|
+
surface: colors.surface,
|
|
1252
|
+
muted: colors.textSecondary,
|
|
1253
|
+
hint: accessibilityHint,
|
|
1254
|
+
testID,
|
|
1255
|
+
onChangeText: (to) => onChange({ from: value.from, to }),
|
|
1256
|
+
onSubmit
|
|
1257
|
+
}
|
|
1258
|
+
)
|
|
1259
|
+
] });
|
|
1260
|
+
}
|
|
722
1261
|
|
|
1262
|
+
exports.AnchoredMenu = AnchoredMenu;
|
|
723
1263
|
exports.ChipSelector = ChipSelector;
|
|
724
1264
|
exports.DEFAULT_OPTIONAL_LABEL = DEFAULT_OPTIONAL_LABEL;
|
|
1265
|
+
exports.DEFAULT_TYPEAHEAD_MAX_SUGGESTIONS = DEFAULT_TYPEAHEAD_MAX_SUGGESTIONS;
|
|
1266
|
+
exports.DEFAULT_TYPEAHEAD_MIN_CHARS = DEFAULT_TYPEAHEAD_MIN_CHARS;
|
|
1267
|
+
exports.DateRangeControl = DateRangeControl;
|
|
725
1268
|
exports.Field = Field;
|
|
726
1269
|
exports.FormActions = FormActions;
|
|
1270
|
+
exports.FormCell = FormCell;
|
|
727
1271
|
exports.FormCheckbox = FormCheckbox;
|
|
728
1272
|
exports.FormField = FormField;
|
|
1273
|
+
exports.FormGrid = FormGrid;
|
|
1274
|
+
exports.FormSection = FormSection;
|
|
729
1275
|
exports.FormSwitch = FormSwitch;
|
|
1276
|
+
exports.SelectControl = SelectControl;
|
|
730
1277
|
exports.ThemedTextInput = ThemedTextInput;
|
|
1278
|
+
exports.TypeaheadControl = TypeaheadControl;
|
|
1279
|
+
exports.controlStyles = controlStyles;
|
|
1280
|
+
exports.isUnmatched = isUnmatched;
|
|
1281
|
+
exports.suggestOptions = suggestOptions;
|
|
731
1282
|
exports.useThemedInput = useThemedInput;
|
|
732
1283
|
//# sourceMappingURL=index.js.map
|
|
733
1284
|
//# sourceMappingURL=index.js.map
|