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