@dloizides/ui-forms 1.9.0 → 1.11.1
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 +32 -0
- package/dist/index.d.mts +67 -2
- package/dist/index.d.ts +67 -2
- package/dist/index.js +231 -166
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +207 -142
- package/dist/index.mjs.map +1 -1
- package/package.json +110 -107
package/dist/index.mjs
CHANGED
|
@@ -1,19 +1,57 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import React2, { useState, useCallback, useMemo, useRef, useEffect } from 'react';
|
|
2
|
+
import { Platform, StyleSheet, 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';
|
|
5
5
|
import { Button } from '@dloizides/ui-buttons';
|
|
6
|
+
import { MIN_TOUCH_TARGET_PX } from '@dloizides/a11y';
|
|
6
7
|
|
|
7
8
|
// src/Field/Field.tsx
|
|
9
|
+
function attachControlId(child, candidateId, describedById) {
|
|
10
|
+
if (!React2.isValidElement(child) || child.type === React2.Fragment) {
|
|
11
|
+
return { node: child };
|
|
12
|
+
}
|
|
13
|
+
const props = child.props;
|
|
14
|
+
const existing = props.id ?? props.nativeID;
|
|
15
|
+
const element = child;
|
|
16
|
+
const controlId = existing !== void 0 && existing !== "" ? existing : candidateId;
|
|
17
|
+
const injected = { id: controlId };
|
|
18
|
+
if (describedById !== void 0 && props.describedById === void 0) {
|
|
19
|
+
injected.describedById = describedById;
|
|
20
|
+
}
|
|
21
|
+
return { node: React2.cloneElement(element, injected), controlId };
|
|
22
|
+
}
|
|
23
|
+
var IS_WEB = Platform.OS === "web";
|
|
24
|
+
function isAttributeHost(node) {
|
|
25
|
+
return typeof node === "object" && node !== null && typeof node.setAttribute === "function";
|
|
26
|
+
}
|
|
27
|
+
function useHtmlFor(controlId) {
|
|
28
|
+
const ref = useRef(null);
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
const node = ref.current;
|
|
31
|
+
if (!IS_WEB || !isAttributeHost(node)) return;
|
|
32
|
+
const target = controlId !== void 0 && controlId !== "" ? node.ownerDocument?.getElementById(controlId) : null;
|
|
33
|
+
if (target === null || target === void 0) {
|
|
34
|
+
node.removeAttribute("for");
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
node.setAttribute("for", controlId);
|
|
38
|
+
}, [controlId]);
|
|
39
|
+
return ref;
|
|
40
|
+
}
|
|
41
|
+
var IS_WEB2 = Platform.OS === "web";
|
|
8
42
|
function FieldLabel({
|
|
9
43
|
label,
|
|
10
44
|
marker,
|
|
11
45
|
optionalLabel,
|
|
46
|
+
controlId,
|
|
47
|
+
labelId,
|
|
12
48
|
style,
|
|
13
49
|
requiredMarkStyle,
|
|
14
50
|
optionalMarkStyle
|
|
15
51
|
}) {
|
|
16
|
-
|
|
52
|
+
const webProps = IS_WEB2 ? { role: "label" } : {};
|
|
53
|
+
const labelRef = useHtmlFor(controlId);
|
|
54
|
+
return /* @__PURE__ */ jsxs(Text, { id: labelId, ref: labelRef, style, ...webProps, children: [
|
|
17
55
|
label,
|
|
18
56
|
" ",
|
|
19
57
|
marker === "required" ? (
|
|
@@ -90,15 +128,15 @@ var labelVariantStyles = StyleSheet.create({
|
|
|
90
128
|
function resolveLabelVariantStyle(variant) {
|
|
91
129
|
return variant === "control" ? labelVariantStyles.control : labelVariantStyles.field;
|
|
92
130
|
}
|
|
93
|
-
var FormGridContext =
|
|
94
|
-
var GapOwnedContext =
|
|
131
|
+
var FormGridContext = React2.createContext(null);
|
|
132
|
+
var GapOwnedContext = React2.createContext(false);
|
|
95
133
|
var FormGridProvider = FormGridContext.Provider;
|
|
96
134
|
var GapOwnedProvider = GapOwnedContext.Provider;
|
|
97
135
|
function useFormGridMetrics() {
|
|
98
|
-
return
|
|
136
|
+
return React2.useContext(FormGridContext);
|
|
99
137
|
}
|
|
100
138
|
function useIsGapOwned() {
|
|
101
|
-
return
|
|
139
|
+
return React2.useContext(GapOwnedContext);
|
|
102
140
|
}
|
|
103
141
|
var ERROR_FONT_SIZE = 12;
|
|
104
142
|
var HINT_FONT_SIZE = 12;
|
|
@@ -116,10 +154,15 @@ var styles = StyleSheet.create({
|
|
|
116
154
|
});
|
|
117
155
|
var fieldSeq = 0;
|
|
118
156
|
function useFieldIds() {
|
|
119
|
-
const [ids] =
|
|
157
|
+
const [ids] = React2.useState(() => {
|
|
120
158
|
fieldSeq += 1;
|
|
121
159
|
const seq = String(fieldSeq);
|
|
122
|
-
return {
|
|
160
|
+
return {
|
|
161
|
+
hintId: `field-hint-${seq}`,
|
|
162
|
+
errorId: `field-error-${seq}`,
|
|
163
|
+
controlId: `field-control-${seq}`,
|
|
164
|
+
labelId: `field-label-${seq}`
|
|
165
|
+
};
|
|
123
166
|
});
|
|
124
167
|
return ids;
|
|
125
168
|
}
|
|
@@ -157,8 +200,8 @@ var Field = ({
|
|
|
157
200
|
const labelText = label ?? "";
|
|
158
201
|
const hasLabel = labelText !== "";
|
|
159
202
|
const marker = resolveFieldMarker(required, optional);
|
|
160
|
-
const { hintId, errorId } = useFieldIds();
|
|
161
|
-
const themeStyles =
|
|
203
|
+
const { hintId, errorId, controlId, labelId } = useFieldIds();
|
|
204
|
+
const themeStyles = React2.useMemo(
|
|
162
205
|
() => ({
|
|
163
206
|
label: { color: colors.textSecondary },
|
|
164
207
|
requiredMark: { color: errorColor },
|
|
@@ -170,12 +213,16 @@ var Field = ({
|
|
|
170
213
|
[colors.textSecondary, errorColor]
|
|
171
214
|
);
|
|
172
215
|
const describedById = joinDescribedBy(hasHint ? hintId : void 0, hasError ? errorId : void 0);
|
|
173
|
-
const
|
|
216
|
+
const isRenderChild = typeof children === "function";
|
|
217
|
+
const attached = isRenderChild ? { node: children({ describedById, hasError, controlId, labelId }), controlId } : attachControlId(children, controlId, describedById);
|
|
218
|
+
const control = attached.node;
|
|
174
219
|
return /* @__PURE__ */ jsxs(View, { style: [spacingStyles.container, containerStyle], testID, children: [
|
|
175
220
|
hasLabel ? /* @__PURE__ */ jsx(
|
|
176
221
|
FieldLabel,
|
|
177
222
|
{
|
|
223
|
+
controlId: attached.controlId,
|
|
178
224
|
label: labelText,
|
|
225
|
+
labelId,
|
|
179
226
|
marker,
|
|
180
227
|
optionalLabel,
|
|
181
228
|
optionalMarkStyle: [styles.optionalMark, themeStyles.optionalMark],
|
|
@@ -205,7 +252,7 @@ var FormGrid = ({
|
|
|
205
252
|
style,
|
|
206
253
|
testID
|
|
207
254
|
}) => {
|
|
208
|
-
const metrics =
|
|
255
|
+
const metrics = React2.useMemo(() => ({ minWidth, basis }), [minWidth, basis]);
|
|
209
256
|
return /* @__PURE__ */ jsx(FormGridProvider, { value: metrics, children: /* @__PURE__ */ jsx(GapOwnedProvider, { value: true, children: /* @__PURE__ */ jsx(View, { style: [styles2.grid, { gap }, style], testID, children }) }) });
|
|
210
257
|
};
|
|
211
258
|
var GROW = 1;
|
|
@@ -240,7 +287,7 @@ var styles3 = StyleSheet.create({
|
|
|
240
287
|
});
|
|
241
288
|
var sectionSeq = 0;
|
|
242
289
|
function useSectionLegendId() {
|
|
243
|
-
const [id] =
|
|
290
|
+
const [id] = React2.useState(() => {
|
|
244
291
|
sectionSeq += 1;
|
|
245
292
|
return `form-section-legend-${String(sectionSeq)}`;
|
|
246
293
|
});
|
|
@@ -327,7 +374,90 @@ var FormActions = ({
|
|
|
327
374
|
}
|
|
328
375
|
)
|
|
329
376
|
] });
|
|
330
|
-
var
|
|
377
|
+
var FIELD_GAP = 4;
|
|
378
|
+
var LABEL_FONT = 11;
|
|
379
|
+
var LABEL_LETTER_SPACING = 0.4;
|
|
380
|
+
var INPUT_RADIUS = 8;
|
|
381
|
+
var INPUT_PAD_H = 12;
|
|
382
|
+
var INPUT_PAD_V = 10;
|
|
383
|
+
var INPUT_FONT = 14;
|
|
384
|
+
var INPUT_BORDER = 1;
|
|
385
|
+
var DATE_ROW_GAP = 8;
|
|
386
|
+
var CHEVRON_FONT = 10;
|
|
387
|
+
var MENU_TOP_GAP = 4;
|
|
388
|
+
var MENU_RADIUS = 8;
|
|
389
|
+
var MENU_PAD_V = 4;
|
|
390
|
+
var MENU_OPT_PAD_H = 12;
|
|
391
|
+
var MENU_OPT_PAD_V = 8;
|
|
392
|
+
var MENU_MIN_WIDTH = 160;
|
|
393
|
+
var MENU_MAX_HEIGHT = 260;
|
|
394
|
+
var MENU_Z = 1e3;
|
|
395
|
+
var MENU_ELEVATION = 8;
|
|
396
|
+
var MENU_BOX_SHADOW = "0px 2px 8px rgba(0, 0, 0, 0.15)";
|
|
397
|
+
var OPTION_FONT = 14;
|
|
398
|
+
var ERROR_FONT = 12;
|
|
399
|
+
var ERROR_GAP = 3;
|
|
400
|
+
var controlStyles = StyleSheet.create({
|
|
401
|
+
/**
|
|
402
|
+
* The shared bordered box every dense text control renders in.
|
|
403
|
+
*
|
|
404
|
+
* `minHeight` is the kit floor: padding alone produced a ~38px box, and a bare input with no
|
|
405
|
+
* box style at all measured **19px** in production. Height is a hit-target guarantee, so it
|
|
406
|
+
* is stated rather than left to emerge from font size + padding.
|
|
407
|
+
*/
|
|
408
|
+
input: {
|
|
409
|
+
borderWidth: INPUT_BORDER,
|
|
410
|
+
borderRadius: INPUT_RADIUS,
|
|
411
|
+
paddingHorizontal: INPUT_PAD_H,
|
|
412
|
+
paddingVertical: INPUT_PAD_V,
|
|
413
|
+
fontSize: INPUT_FONT,
|
|
414
|
+
minHeight: MIN_TOUCH_TARGET_PX
|
|
415
|
+
},
|
|
416
|
+
/** The select trigger: a bordered field box matching the text inputs + a chevron. */
|
|
417
|
+
selectTrigger: {
|
|
418
|
+
minHeight: MIN_TOUCH_TARGET_PX,
|
|
419
|
+
flexDirection: "row",
|
|
420
|
+
alignItems: "center",
|
|
421
|
+
justifyContent: "space-between",
|
|
422
|
+
gap: DATE_ROW_GAP,
|
|
423
|
+
borderWidth: INPUT_BORDER,
|
|
424
|
+
borderRadius: INPUT_RADIUS,
|
|
425
|
+
paddingHorizontal: INPUT_PAD_H,
|
|
426
|
+
paddingVertical: INPUT_PAD_V
|
|
427
|
+
},
|
|
428
|
+
selectTriggerText: { fontSize: INPUT_FONT, flexShrink: 1 },
|
|
429
|
+
chevron: { fontSize: CHEVRON_FONT },
|
|
430
|
+
dateRow: { flexDirection: "row", gap: DATE_ROW_GAP },
|
|
431
|
+
dateCol: { gap: FIELD_GAP, flex: 1 },
|
|
432
|
+
/**
|
|
433
|
+
* The micro-caption above a sub-control (a date range's From/To) and beside a switch. Note it
|
|
434
|
+
* is deliberately NOT the `control` label voice: it carries no `700`/uppercase, because it
|
|
435
|
+
* names a HALF of a control that already has a `control`-voice label above it. Uppercasing it
|
|
436
|
+
* too would make one field shout twice.
|
|
437
|
+
*/
|
|
438
|
+
subLabel: { fontSize: LABEL_FONT, letterSpacing: LABEL_LETTER_SPACING },
|
|
439
|
+
/** Positioning context for a floating `AnchoredMenu` (`position:absolute; top:100%`). */
|
|
440
|
+
anchor: { position: "relative" },
|
|
441
|
+
menu: {
|
|
442
|
+
position: "absolute",
|
|
443
|
+
top: "100%",
|
|
444
|
+
left: 0,
|
|
445
|
+
marginTop: MENU_TOP_GAP,
|
|
446
|
+
minWidth: MENU_MIN_WIDTH,
|
|
447
|
+
maxHeight: MENU_MAX_HEIGHT,
|
|
448
|
+
borderWidth: INPUT_BORDER,
|
|
449
|
+
borderRadius: MENU_RADIUS,
|
|
450
|
+
paddingVertical: MENU_PAD_V,
|
|
451
|
+
zIndex: MENU_Z,
|
|
452
|
+
boxShadow: MENU_BOX_SHADOW,
|
|
453
|
+
elevation: MENU_ELEVATION,
|
|
454
|
+
overflow: "hidden"
|
|
455
|
+
},
|
|
456
|
+
option: { paddingHorizontal: MENU_OPT_PAD_H, paddingVertical: MENU_OPT_PAD_V },
|
|
457
|
+
optionText: { fontSize: OPTION_FONT },
|
|
458
|
+
error: { fontSize: ERROR_FONT, marginTop: ERROR_GAP }
|
|
459
|
+
});
|
|
460
|
+
var IS_WEB3 = Platform.OS === "web";
|
|
331
461
|
var TRANSITION_PROPERTY = "border-color, background-color, box-shadow";
|
|
332
462
|
var TRANSITION_DURATION = "0.14s";
|
|
333
463
|
var TRANSITION_TIMING = "ease";
|
|
@@ -342,7 +472,7 @@ var GREEN_START = 3;
|
|
|
342
472
|
var BLUE_START = 5;
|
|
343
473
|
var CHANNEL_END_OFFSET = 2;
|
|
344
474
|
function prefersReducedMotion() {
|
|
345
|
-
if (!
|
|
475
|
+
if (!IS_WEB3 || typeof window === "undefined" || typeof window.matchMedia !== "function") return false;
|
|
346
476
|
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
347
477
|
}
|
|
348
478
|
function withAlpha(color, alpha) {
|
|
@@ -385,7 +515,7 @@ function useThemedInput(options = {}) {
|
|
|
385
515
|
const borderColor = isFocused ? focusBorder : isHovered ? withAlpha(colors.text, HOVER_BORDER_ALPHA) : restBorder;
|
|
386
516
|
const backgroundColor = isFocused ? colors.surface : colors.surfaceElevated;
|
|
387
517
|
const base = { color: colors.text, borderColor, backgroundColor };
|
|
388
|
-
if (!
|
|
518
|
+
if (!IS_WEB3) return base;
|
|
389
519
|
const ringColor = hasError ? errorColor : primary;
|
|
390
520
|
const ring = isFocused ? `0 0 0 ${FOCUS_RING_WIDTH}px ${withAlpha(ringColor, FOCUS_RING_ALPHA)}` : "none";
|
|
391
521
|
const webStyle = {
|
|
@@ -410,7 +540,7 @@ function useThemedInput(options = {}) {
|
|
|
410
540
|
]);
|
|
411
541
|
const focusBind = useMemo(() => ({ onFocus: handleFocus, onBlur: handleBlur }), [handleFocus, handleBlur]);
|
|
412
542
|
const hoverBind = useMemo(
|
|
413
|
-
() =>
|
|
543
|
+
() => IS_WEB3 ? { onMouseEnter: handleHoverIn, onMouseLeave: handleHoverOut } : {},
|
|
414
544
|
[handleHoverIn, handleHoverOut]
|
|
415
545
|
);
|
|
416
546
|
return {
|
|
@@ -422,19 +552,44 @@ function useThemedInput(options = {}) {
|
|
|
422
552
|
hoverBind
|
|
423
553
|
};
|
|
424
554
|
}
|
|
425
|
-
var
|
|
426
|
-
|
|
555
|
+
var IS_WEB4 = Platform.OS === "web";
|
|
556
|
+
function webFieldA11y({ describedById, hasError = false, required = false }) {
|
|
557
|
+
if (!IS_WEB4) {
|
|
558
|
+
return {};
|
|
559
|
+
}
|
|
560
|
+
return {
|
|
561
|
+
"aria-invalid": hasError ? true : void 0,
|
|
562
|
+
"aria-describedby": describedById,
|
|
563
|
+
"aria-required": required ? true : void 0
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
var MULTILINE_MIN_HEIGHT = 96;
|
|
567
|
+
var boxStyles = StyleSheet.create({
|
|
568
|
+
multiline: {
|
|
569
|
+
minHeight: MULTILINE_MIN_HEIGHT,
|
|
570
|
+
textAlignVertical: "top"
|
|
571
|
+
}
|
|
572
|
+
});
|
|
573
|
+
var ThemedTextInput = React2.forwardRef(function ThemedTextInput2({
|
|
574
|
+
hasError = false,
|
|
575
|
+
describedById,
|
|
576
|
+
requiredField = false,
|
|
577
|
+
unstyledBox = false,
|
|
578
|
+
onFocus,
|
|
579
|
+
onBlur,
|
|
580
|
+
style,
|
|
581
|
+
placeholderTextColor,
|
|
582
|
+
...rest
|
|
583
|
+
}, ref) {
|
|
427
584
|
const {
|
|
428
585
|
style: themedStyle,
|
|
429
586
|
placeholderTextColor: themedPlaceholder,
|
|
430
587
|
focusBind,
|
|
431
588
|
hoverBind
|
|
432
589
|
} = useThemedInput({ hasError, onFocus, onBlur });
|
|
433
|
-
const webA11y =
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
"aria-required": requiredField ? true : void 0
|
|
437
|
-
} : {};
|
|
590
|
+
const webA11y = webFieldA11y({ describedById, hasError, required: requiredField });
|
|
591
|
+
const boxStyle = unstyledBox ? null : controlStyles.input;
|
|
592
|
+
const multilineStyle = rest.multiline === true && !unstyledBox ? boxStyles.multiline : null;
|
|
438
593
|
return /* @__PURE__ */ jsx(
|
|
439
594
|
TextInput,
|
|
440
595
|
{
|
|
@@ -445,37 +600,25 @@ var ThemedTextInput = React.forwardRef(function ThemedTextInput2({ hasError = fa
|
|
|
445
600
|
...hoverBind,
|
|
446
601
|
onFocus: focusBind.onFocus,
|
|
447
602
|
onBlur: focusBind.onBlur,
|
|
448
|
-
style: [style, themedStyle]
|
|
603
|
+
style: [boxStyle, multilineStyle, style, themedStyle]
|
|
449
604
|
}
|
|
450
605
|
);
|
|
451
606
|
});
|
|
452
|
-
var INPUT_PADDING_V = 10;
|
|
453
|
-
var INPUT_PADDING_H = 12;
|
|
454
|
-
var INPUT_BORDER_RADIUS = 8;
|
|
455
|
-
var INPUT_BORDER_WIDTH = 1;
|
|
456
|
-
var styles5 = StyleSheet.create({
|
|
457
|
-
input: {
|
|
458
|
-
paddingVertical: INPUT_PADDING_V,
|
|
459
|
-
paddingHorizontal: INPUT_PADDING_H,
|
|
460
|
-
borderRadius: INPUT_BORDER_RADIUS,
|
|
461
|
-
borderWidth: INPUT_BORDER_WIDTH
|
|
462
|
-
}
|
|
463
|
-
});
|
|
464
607
|
var FormField = ({
|
|
465
608
|
label,
|
|
466
609
|
required = false,
|
|
467
610
|
error,
|
|
468
611
|
containerStyle,
|
|
469
612
|
...textInputProps
|
|
470
|
-
}) => /* @__PURE__ */ jsx(Field, { containerStyle, error, label, required, children: ({ describedById, hasError }) => /* @__PURE__ */ jsx(
|
|
613
|
+
}) => /* @__PURE__ */ jsx(Field, { containerStyle, error, label, required, children: ({ describedById, hasError, controlId }) => /* @__PURE__ */ jsx(
|
|
471
614
|
ThemedTextInput,
|
|
472
615
|
{
|
|
473
616
|
accessibilityHint: `Enter ${label}`,
|
|
474
617
|
accessibilityLabel: label,
|
|
475
618
|
describedById,
|
|
476
619
|
hasError,
|
|
620
|
+
id: controlId,
|
|
477
621
|
requiredField: required,
|
|
478
|
-
style: styles5.input,
|
|
479
622
|
testID: "form-field-input",
|
|
480
623
|
...textInputProps
|
|
481
624
|
}
|
|
@@ -513,7 +656,7 @@ function withAlpha2(hex, alpha) {
|
|
|
513
656
|
const isValid = !Number.isNaN(r) && !Number.isNaN(g) && !Number.isNaN(b);
|
|
514
657
|
return isValid ? `rgba(${r}, ${g}, ${b}, ${alpha})` : hex;
|
|
515
658
|
}
|
|
516
|
-
var
|
|
659
|
+
var styles5 = StyleSheet.create({
|
|
517
660
|
chipContainer: {
|
|
518
661
|
flexDirection: "row",
|
|
519
662
|
flexWrap: "wrap",
|
|
@@ -565,7 +708,7 @@ function OutlineChip({
|
|
|
565
708
|
ariaPressed,
|
|
566
709
|
onPress
|
|
567
710
|
}) {
|
|
568
|
-
const [hovered, setHovered] =
|
|
711
|
+
const [hovered, setHovered] = React2.useState(false);
|
|
569
712
|
const active = selected || hovered;
|
|
570
713
|
const borderColor = active ? colors.primary : colors.border;
|
|
571
714
|
const backgroundColor = selected ? colors.tint : colors.muted;
|
|
@@ -584,7 +727,7 @@ function OutlineChip({
|
|
|
584
727
|
onHoverIn: () => setHovered(true),
|
|
585
728
|
onHoverOut: () => setHovered(false),
|
|
586
729
|
onPress,
|
|
587
|
-
children: /* @__PURE__ */ jsx(View, { style: [
|
|
730
|
+
children: /* @__PURE__ */ jsx(View, { style: [styles5.chipOutline, { borderColor, backgroundColor }], children: /* @__PURE__ */ jsx(Text, { style: [styles5.chipText, styles5.chipTextOutline, { color: textColor }], children: option.label }) })
|
|
588
731
|
}
|
|
589
732
|
);
|
|
590
733
|
}
|
|
@@ -612,15 +755,10 @@ function SolidChip({
|
|
|
612
755
|
hitSlop: CHIP_HIT_SLOP,
|
|
613
756
|
testID,
|
|
614
757
|
onPress,
|
|
615
|
-
children: /* @__PURE__ */ jsx(View, { style: [
|
|
758
|
+
children: /* @__PURE__ */ jsx(View, { style: [styles5.chip, { borderColor: colors.border, backgroundColor }], children: /* @__PURE__ */ jsx(Text, { style: [styles5.chipText, { color: textColor }], children: option.label }) })
|
|
616
759
|
}
|
|
617
760
|
);
|
|
618
761
|
}
|
|
619
|
-
var IS_WEB3 = Platform.OS === "web";
|
|
620
|
-
function groupA11yProps(describedById, hasError) {
|
|
621
|
-
if (!IS_WEB3) return {};
|
|
622
|
-
return { "aria-invalid": hasError ? true : void 0, "aria-describedby": describedById };
|
|
623
|
-
}
|
|
624
762
|
var ChipSelector = ({
|
|
625
763
|
label,
|
|
626
764
|
options,
|
|
@@ -639,7 +777,7 @@ var ChipSelector = ({
|
|
|
639
777
|
}) => {
|
|
640
778
|
const { theme } = useUi();
|
|
641
779
|
const { colors, palette } = theme;
|
|
642
|
-
const chipColors =
|
|
780
|
+
const chipColors = React2.useMemo(() => {
|
|
643
781
|
const primary = palette.primary["500"];
|
|
644
782
|
return {
|
|
645
783
|
border: colors.border,
|
|
@@ -682,12 +820,12 @@ var ChipSelector = ({
|
|
|
682
820
|
required,
|
|
683
821
|
spacing,
|
|
684
822
|
testID,
|
|
685
|
-
children: ({ describedById, hasError }) => /* @__PURE__ */ jsx(View, { style:
|
|
823
|
+
children: ({ describedById, hasError }) => /* @__PURE__ */ jsx(View, { style: styles5.chipContainer, ...webFieldA11y({ describedById, hasError }), children: options.map(renderChip) })
|
|
686
824
|
}
|
|
687
825
|
);
|
|
688
826
|
};
|
|
689
827
|
var DESCRIPTION_FONT_SIZE2 = 12;
|
|
690
|
-
var
|
|
828
|
+
var styles6 = StyleSheet.create({
|
|
691
829
|
container: {
|
|
692
830
|
flexDirection: "row",
|
|
693
831
|
justifyContent: "space-between",
|
|
@@ -718,7 +856,7 @@ var FormSwitch = ({
|
|
|
718
856
|
const { theme } = useUi();
|
|
719
857
|
const { colors } = theme;
|
|
720
858
|
const hasDescription = typeof description === "string" && description !== "";
|
|
721
|
-
const themeStyles =
|
|
859
|
+
const themeStyles = React2.useMemo(() => {
|
|
722
860
|
const labelStyle = { color: colors.text };
|
|
723
861
|
const descriptionStyle = { color: colors.textSecondary };
|
|
724
862
|
return { label: labelStyle, description: descriptionStyle };
|
|
@@ -727,13 +865,13 @@ var FormSwitch = ({
|
|
|
727
865
|
View,
|
|
728
866
|
{
|
|
729
867
|
style: [
|
|
730
|
-
|
|
868
|
+
styles6.container,
|
|
731
869
|
containerStyle
|
|
732
870
|
],
|
|
733
871
|
children: [
|
|
734
|
-
/* @__PURE__ */ jsxs(View, { style:
|
|
735
|
-
/* @__PURE__ */ jsx(Text, { style: [
|
|
736
|
-
hasDescription ? /* @__PURE__ */ jsx(Text, { style: [
|
|
872
|
+
/* @__PURE__ */ jsxs(View, { style: styles6.textColumn, children: [
|
|
873
|
+
/* @__PURE__ */ jsx(Text, { style: [styles6.label, themeStyles.label], children: label }),
|
|
874
|
+
hasDescription ? /* @__PURE__ */ jsx(Text, { style: [styles6.description, themeStyles.description], children: description }) : null
|
|
737
875
|
] }),
|
|
738
876
|
/* @__PURE__ */ jsx(
|
|
739
877
|
Switch,
|
|
@@ -758,7 +896,7 @@ var BOX_SIZE = 20;
|
|
|
758
896
|
var BOX_RADIUS = 5;
|
|
759
897
|
var CHECK_FONT_SIZE = 14;
|
|
760
898
|
var DISABLED_OPACITY = 0.5;
|
|
761
|
-
var
|
|
899
|
+
var styles7 = StyleSheet.create({
|
|
762
900
|
container: {
|
|
763
901
|
flexDirection: "row",
|
|
764
902
|
alignItems: "flex-start",
|
|
@@ -809,7 +947,7 @@ var FormCheckbox = ({
|
|
|
809
947
|
const brand = palette.primary["500"];
|
|
810
948
|
const hintText = typeof hint === "string" && hint !== "" ? hint : description;
|
|
811
949
|
const hasHint = typeof hintText === "string" && hintText !== "";
|
|
812
|
-
const themeStyles =
|
|
950
|
+
const themeStyles = React2.useMemo(() => {
|
|
813
951
|
const boxOn = { backgroundColor: brand, borderColor: brand };
|
|
814
952
|
const boxOff = { backgroundColor: "transparent", borderColor: colors.border };
|
|
815
953
|
const labelStyle = { color: colors.text };
|
|
@@ -840,101 +978,26 @@ var FormCheckbox = ({
|
|
|
840
978
|
disabled,
|
|
841
979
|
onPress: toggle,
|
|
842
980
|
role: "checkbox",
|
|
843
|
-
style: [
|
|
981
|
+
style: [styles7.container, containerStyle, disabled ? { opacity: DISABLED_OPACITY } : null],
|
|
844
982
|
testID,
|
|
845
983
|
...keyboardProps,
|
|
846
984
|
children: [
|
|
847
|
-
/* @__PURE__ */ jsx(View, { style: [
|
|
848
|
-
/* @__PURE__ */ jsxs(View, { style:
|
|
849
|
-
/* @__PURE__ */ jsx(Text, { style: [
|
|
850
|
-
hasHint ? /* @__PURE__ */ jsx(Text, { style: [
|
|
985
|
+
/* @__PURE__ */ jsx(View, { style: [styles7.box, value ? themeStyles.boxOn : themeStyles.boxOff], children: value ? /* @__PURE__ */ jsx(Text, { style: [styles7.check, { color: colors.surface }], accessibilityElementsHidden: true, children: "\u2713" }) : null }),
|
|
986
|
+
/* @__PURE__ */ jsxs(View, { style: styles7.textColumn, children: [
|
|
987
|
+
/* @__PURE__ */ jsx(Text, { style: [styles7.label, themeStyles.label], children: label }),
|
|
988
|
+
hasHint ? /* @__PURE__ */ jsx(Text, { style: [styles7.hint, themeStyles.hint], children: hintText }) : null
|
|
851
989
|
] })
|
|
852
990
|
]
|
|
853
991
|
}
|
|
854
992
|
);
|
|
855
993
|
};
|
|
856
|
-
var
|
|
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";
|
|
994
|
+
var IS_WEB5 = typeof document !== "undefined";
|
|
932
995
|
var ESCAPE_KEY = "Escape";
|
|
933
996
|
var ACTIVE_WEIGHT = "700";
|
|
934
997
|
var IDLE_WEIGHT = "400";
|
|
935
998
|
function useDismiss(anchorRef, menuRef, onDismiss) {
|
|
936
999
|
useEffect(() => {
|
|
937
|
-
if (!
|
|
1000
|
+
if (!IS_WEB5) return void 0;
|
|
938
1001
|
const onMouseDown = (event) => {
|
|
939
1002
|
const anchorNode = anchorRef.current;
|
|
940
1003
|
const menuNode = menuRef.current;
|
|
@@ -964,7 +1027,7 @@ function AnchoredMenu({
|
|
|
964
1027
|
testID,
|
|
965
1028
|
anchorRef
|
|
966
1029
|
}) {
|
|
967
|
-
const menuRef =
|
|
1030
|
+
const menuRef = React2.useRef(null);
|
|
968
1031
|
useDismiss(anchorRef, menuRef, onDismiss);
|
|
969
1032
|
return /* @__PURE__ */ jsx(
|
|
970
1033
|
View,
|
|
@@ -1003,6 +1066,7 @@ function SelectControl({
|
|
|
1003
1066
|
placeholder = "",
|
|
1004
1067
|
accessibilityLabel,
|
|
1005
1068
|
accessibilityHint,
|
|
1069
|
+
labelledById,
|
|
1006
1070
|
optionHint = "",
|
|
1007
1071
|
style,
|
|
1008
1072
|
testID
|
|
@@ -1037,6 +1101,7 @@ function SelectControl({
|
|
|
1037
1101
|
accessibilityHint,
|
|
1038
1102
|
accessibilityState: { expanded: isOpen },
|
|
1039
1103
|
"aria-expanded": isOpen,
|
|
1104
|
+
"aria-labelledby": labelledById,
|
|
1040
1105
|
onPress: toggle,
|
|
1041
1106
|
style: [controlStyles.selectTrigger, { borderColor: colors.border, backgroundColor: colors.surface }],
|
|
1042
1107
|
testID: `${testID}-trigger`,
|