@dloizides/ui-forms 1.9.1 → 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 +312 -280
- package/dist/index.d.mts +67 -2
- package/dist/index.d.ts +67 -2
- package/dist/index.js +221 -157
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +197 -133
- 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,9 +552,9 @@ function useThemedInput(options = {}) {
|
|
|
422
552
|
hoverBind
|
|
423
553
|
};
|
|
424
554
|
}
|
|
425
|
-
var
|
|
555
|
+
var IS_WEB4 = Platform.OS === "web";
|
|
426
556
|
function webFieldA11y({ describedById, hasError = false, required = false }) {
|
|
427
|
-
if (!
|
|
557
|
+
if (!IS_WEB4) {
|
|
428
558
|
return {};
|
|
429
559
|
}
|
|
430
560
|
return {
|
|
@@ -433,7 +563,24 @@ function webFieldA11y({ describedById, hasError = false, required = false }) {
|
|
|
433
563
|
"aria-required": required ? true : void 0
|
|
434
564
|
};
|
|
435
565
|
}
|
|
436
|
-
var
|
|
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) {
|
|
437
584
|
const {
|
|
438
585
|
style: themedStyle,
|
|
439
586
|
placeholderTextColor: themedPlaceholder,
|
|
@@ -441,6 +588,8 @@ var ThemedTextInput = React.forwardRef(function ThemedTextInput2({ hasError = fa
|
|
|
441
588
|
hoverBind
|
|
442
589
|
} = useThemedInput({ hasError, onFocus, onBlur });
|
|
443
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;
|
|
444
593
|
return /* @__PURE__ */ jsx(
|
|
445
594
|
TextInput,
|
|
446
595
|
{
|
|
@@ -451,37 +600,25 @@ var ThemedTextInput = React.forwardRef(function ThemedTextInput2({ hasError = fa
|
|
|
451
600
|
...hoverBind,
|
|
452
601
|
onFocus: focusBind.onFocus,
|
|
453
602
|
onBlur: focusBind.onBlur,
|
|
454
|
-
style: [style, themedStyle]
|
|
603
|
+
style: [boxStyle, multilineStyle, style, themedStyle]
|
|
455
604
|
}
|
|
456
605
|
);
|
|
457
606
|
});
|
|
458
|
-
var INPUT_PADDING_V = 10;
|
|
459
|
-
var INPUT_PADDING_H = 12;
|
|
460
|
-
var INPUT_BORDER_RADIUS = 8;
|
|
461
|
-
var INPUT_BORDER_WIDTH = 1;
|
|
462
|
-
var styles5 = StyleSheet.create({
|
|
463
|
-
input: {
|
|
464
|
-
paddingVertical: INPUT_PADDING_V,
|
|
465
|
-
paddingHorizontal: INPUT_PADDING_H,
|
|
466
|
-
borderRadius: INPUT_BORDER_RADIUS,
|
|
467
|
-
borderWidth: INPUT_BORDER_WIDTH
|
|
468
|
-
}
|
|
469
|
-
});
|
|
470
607
|
var FormField = ({
|
|
471
608
|
label,
|
|
472
609
|
required = false,
|
|
473
610
|
error,
|
|
474
611
|
containerStyle,
|
|
475
612
|
...textInputProps
|
|
476
|
-
}) => /* @__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(
|
|
477
614
|
ThemedTextInput,
|
|
478
615
|
{
|
|
479
616
|
accessibilityHint: `Enter ${label}`,
|
|
480
617
|
accessibilityLabel: label,
|
|
481
618
|
describedById,
|
|
482
619
|
hasError,
|
|
620
|
+
id: controlId,
|
|
483
621
|
requiredField: required,
|
|
484
|
-
style: styles5.input,
|
|
485
622
|
testID: "form-field-input",
|
|
486
623
|
...textInputProps
|
|
487
624
|
}
|
|
@@ -519,7 +656,7 @@ function withAlpha2(hex, alpha) {
|
|
|
519
656
|
const isValid = !Number.isNaN(r) && !Number.isNaN(g) && !Number.isNaN(b);
|
|
520
657
|
return isValid ? `rgba(${r}, ${g}, ${b}, ${alpha})` : hex;
|
|
521
658
|
}
|
|
522
|
-
var
|
|
659
|
+
var styles5 = StyleSheet.create({
|
|
523
660
|
chipContainer: {
|
|
524
661
|
flexDirection: "row",
|
|
525
662
|
flexWrap: "wrap",
|
|
@@ -571,7 +708,7 @@ function OutlineChip({
|
|
|
571
708
|
ariaPressed,
|
|
572
709
|
onPress
|
|
573
710
|
}) {
|
|
574
|
-
const [hovered, setHovered] =
|
|
711
|
+
const [hovered, setHovered] = React2.useState(false);
|
|
575
712
|
const active = selected || hovered;
|
|
576
713
|
const borderColor = active ? colors.primary : colors.border;
|
|
577
714
|
const backgroundColor = selected ? colors.tint : colors.muted;
|
|
@@ -590,7 +727,7 @@ function OutlineChip({
|
|
|
590
727
|
onHoverIn: () => setHovered(true),
|
|
591
728
|
onHoverOut: () => setHovered(false),
|
|
592
729
|
onPress,
|
|
593
|
-
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 }) })
|
|
594
731
|
}
|
|
595
732
|
);
|
|
596
733
|
}
|
|
@@ -618,7 +755,7 @@ function SolidChip({
|
|
|
618
755
|
hitSlop: CHIP_HIT_SLOP,
|
|
619
756
|
testID,
|
|
620
757
|
onPress,
|
|
621
|
-
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 }) })
|
|
622
759
|
}
|
|
623
760
|
);
|
|
624
761
|
}
|
|
@@ -640,7 +777,7 @@ var ChipSelector = ({
|
|
|
640
777
|
}) => {
|
|
641
778
|
const { theme } = useUi();
|
|
642
779
|
const { colors, palette } = theme;
|
|
643
|
-
const chipColors =
|
|
780
|
+
const chipColors = React2.useMemo(() => {
|
|
644
781
|
const primary = palette.primary["500"];
|
|
645
782
|
return {
|
|
646
783
|
border: colors.border,
|
|
@@ -683,12 +820,12 @@ var ChipSelector = ({
|
|
|
683
820
|
required,
|
|
684
821
|
spacing,
|
|
685
822
|
testID,
|
|
686
|
-
children: ({ describedById, hasError }) => /* @__PURE__ */ jsx(View, { style:
|
|
823
|
+
children: ({ describedById, hasError }) => /* @__PURE__ */ jsx(View, { style: styles5.chipContainer, ...webFieldA11y({ describedById, hasError }), children: options.map(renderChip) })
|
|
687
824
|
}
|
|
688
825
|
);
|
|
689
826
|
};
|
|
690
827
|
var DESCRIPTION_FONT_SIZE2 = 12;
|
|
691
|
-
var
|
|
828
|
+
var styles6 = StyleSheet.create({
|
|
692
829
|
container: {
|
|
693
830
|
flexDirection: "row",
|
|
694
831
|
justifyContent: "space-between",
|
|
@@ -719,7 +856,7 @@ var FormSwitch = ({
|
|
|
719
856
|
const { theme } = useUi();
|
|
720
857
|
const { colors } = theme;
|
|
721
858
|
const hasDescription = typeof description === "string" && description !== "";
|
|
722
|
-
const themeStyles =
|
|
859
|
+
const themeStyles = React2.useMemo(() => {
|
|
723
860
|
const labelStyle = { color: colors.text };
|
|
724
861
|
const descriptionStyle = { color: colors.textSecondary };
|
|
725
862
|
return { label: labelStyle, description: descriptionStyle };
|
|
@@ -728,13 +865,13 @@ var FormSwitch = ({
|
|
|
728
865
|
View,
|
|
729
866
|
{
|
|
730
867
|
style: [
|
|
731
|
-
|
|
868
|
+
styles6.container,
|
|
732
869
|
containerStyle
|
|
733
870
|
],
|
|
734
871
|
children: [
|
|
735
|
-
/* @__PURE__ */ jsxs(View, { style:
|
|
736
|
-
/* @__PURE__ */ jsx(Text, { style: [
|
|
737
|
-
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
|
|
738
875
|
] }),
|
|
739
876
|
/* @__PURE__ */ jsx(
|
|
740
877
|
Switch,
|
|
@@ -759,7 +896,7 @@ var BOX_SIZE = 20;
|
|
|
759
896
|
var BOX_RADIUS = 5;
|
|
760
897
|
var CHECK_FONT_SIZE = 14;
|
|
761
898
|
var DISABLED_OPACITY = 0.5;
|
|
762
|
-
var
|
|
899
|
+
var styles7 = StyleSheet.create({
|
|
763
900
|
container: {
|
|
764
901
|
flexDirection: "row",
|
|
765
902
|
alignItems: "flex-start",
|
|
@@ -810,7 +947,7 @@ var FormCheckbox = ({
|
|
|
810
947
|
const brand = palette.primary["500"];
|
|
811
948
|
const hintText = typeof hint === "string" && hint !== "" ? hint : description;
|
|
812
949
|
const hasHint = typeof hintText === "string" && hintText !== "";
|
|
813
|
-
const themeStyles =
|
|
950
|
+
const themeStyles = React2.useMemo(() => {
|
|
814
951
|
const boxOn = { backgroundColor: brand, borderColor: brand };
|
|
815
952
|
const boxOff = { backgroundColor: "transparent", borderColor: colors.border };
|
|
816
953
|
const labelStyle = { color: colors.text };
|
|
@@ -841,101 +978,26 @@ var FormCheckbox = ({
|
|
|
841
978
|
disabled,
|
|
842
979
|
onPress: toggle,
|
|
843
980
|
role: "checkbox",
|
|
844
|
-
style: [
|
|
981
|
+
style: [styles7.container, containerStyle, disabled ? { opacity: DISABLED_OPACITY } : null],
|
|
845
982
|
testID,
|
|
846
983
|
...keyboardProps,
|
|
847
984
|
children: [
|
|
848
|
-
/* @__PURE__ */ jsx(View, { style: [
|
|
849
|
-
/* @__PURE__ */ jsxs(View, { style:
|
|
850
|
-
/* @__PURE__ */ jsx(Text, { style: [
|
|
851
|
-
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
|
|
852
989
|
] })
|
|
853
990
|
]
|
|
854
991
|
}
|
|
855
992
|
);
|
|
856
993
|
};
|
|
857
|
-
var
|
|
858
|
-
var LABEL_FONT = 11;
|
|
859
|
-
var LABEL_LETTER_SPACING = 0.4;
|
|
860
|
-
var INPUT_RADIUS = 8;
|
|
861
|
-
var INPUT_PAD_H = 12;
|
|
862
|
-
var INPUT_PAD_V = 10;
|
|
863
|
-
var INPUT_FONT = 14;
|
|
864
|
-
var INPUT_BORDER = 1;
|
|
865
|
-
var DATE_ROW_GAP = 8;
|
|
866
|
-
var CHEVRON_FONT = 10;
|
|
867
|
-
var MENU_TOP_GAP = 4;
|
|
868
|
-
var MENU_RADIUS = 8;
|
|
869
|
-
var MENU_PAD_V = 4;
|
|
870
|
-
var MENU_OPT_PAD_H = 12;
|
|
871
|
-
var MENU_OPT_PAD_V = 8;
|
|
872
|
-
var MENU_MIN_WIDTH = 160;
|
|
873
|
-
var MENU_MAX_HEIGHT = 260;
|
|
874
|
-
var MENU_Z = 1e3;
|
|
875
|
-
var MENU_ELEVATION = 8;
|
|
876
|
-
var MENU_BOX_SHADOW = "0px 2px 8px rgba(0, 0, 0, 0.15)";
|
|
877
|
-
var OPTION_FONT = 14;
|
|
878
|
-
var ERROR_FONT = 12;
|
|
879
|
-
var ERROR_GAP = 3;
|
|
880
|
-
var controlStyles = StyleSheet.create({
|
|
881
|
-
/** The shared bordered box every dense text control renders in. */
|
|
882
|
-
input: {
|
|
883
|
-
borderWidth: INPUT_BORDER,
|
|
884
|
-
borderRadius: INPUT_RADIUS,
|
|
885
|
-
paddingHorizontal: INPUT_PAD_H,
|
|
886
|
-
paddingVertical: INPUT_PAD_V,
|
|
887
|
-
fontSize: INPUT_FONT
|
|
888
|
-
},
|
|
889
|
-
/** The select trigger: a bordered field box matching the text inputs + a chevron. */
|
|
890
|
-
selectTrigger: {
|
|
891
|
-
flexDirection: "row",
|
|
892
|
-
alignItems: "center",
|
|
893
|
-
justifyContent: "space-between",
|
|
894
|
-
gap: DATE_ROW_GAP,
|
|
895
|
-
borderWidth: INPUT_BORDER,
|
|
896
|
-
borderRadius: INPUT_RADIUS,
|
|
897
|
-
paddingHorizontal: INPUT_PAD_H,
|
|
898
|
-
paddingVertical: INPUT_PAD_V
|
|
899
|
-
},
|
|
900
|
-
selectTriggerText: { fontSize: INPUT_FONT, flexShrink: 1 },
|
|
901
|
-
chevron: { fontSize: CHEVRON_FONT },
|
|
902
|
-
dateRow: { flexDirection: "row", gap: DATE_ROW_GAP },
|
|
903
|
-
dateCol: { gap: FIELD_GAP, flex: 1 },
|
|
904
|
-
/**
|
|
905
|
-
* The micro-caption above a sub-control (a date range's From/To) and beside a switch. Note it
|
|
906
|
-
* is deliberately NOT the `control` label voice: it carries no `700`/uppercase, because it
|
|
907
|
-
* names a HALF of a control that already has a `control`-voice label above it. Uppercasing it
|
|
908
|
-
* too would make one field shout twice.
|
|
909
|
-
*/
|
|
910
|
-
subLabel: { fontSize: LABEL_FONT, letterSpacing: LABEL_LETTER_SPACING },
|
|
911
|
-
/** Positioning context for a floating `AnchoredMenu` (`position:absolute; top:100%`). */
|
|
912
|
-
anchor: { position: "relative" },
|
|
913
|
-
menu: {
|
|
914
|
-
position: "absolute",
|
|
915
|
-
top: "100%",
|
|
916
|
-
left: 0,
|
|
917
|
-
marginTop: MENU_TOP_GAP,
|
|
918
|
-
minWidth: MENU_MIN_WIDTH,
|
|
919
|
-
maxHeight: MENU_MAX_HEIGHT,
|
|
920
|
-
borderWidth: INPUT_BORDER,
|
|
921
|
-
borderRadius: MENU_RADIUS,
|
|
922
|
-
paddingVertical: MENU_PAD_V,
|
|
923
|
-
zIndex: MENU_Z,
|
|
924
|
-
boxShadow: MENU_BOX_SHADOW,
|
|
925
|
-
elevation: MENU_ELEVATION,
|
|
926
|
-
overflow: "hidden"
|
|
927
|
-
},
|
|
928
|
-
option: { paddingHorizontal: MENU_OPT_PAD_H, paddingVertical: MENU_OPT_PAD_V },
|
|
929
|
-
optionText: { fontSize: OPTION_FONT },
|
|
930
|
-
error: { fontSize: ERROR_FONT, marginTop: ERROR_GAP }
|
|
931
|
-
});
|
|
932
|
-
var IS_WEB3 = typeof document !== "undefined";
|
|
994
|
+
var IS_WEB5 = typeof document !== "undefined";
|
|
933
995
|
var ESCAPE_KEY = "Escape";
|
|
934
996
|
var ACTIVE_WEIGHT = "700";
|
|
935
997
|
var IDLE_WEIGHT = "400";
|
|
936
998
|
function useDismiss(anchorRef, menuRef, onDismiss) {
|
|
937
999
|
useEffect(() => {
|
|
938
|
-
if (!
|
|
1000
|
+
if (!IS_WEB5) return void 0;
|
|
939
1001
|
const onMouseDown = (event) => {
|
|
940
1002
|
const anchorNode = anchorRef.current;
|
|
941
1003
|
const menuNode = menuRef.current;
|
|
@@ -965,7 +1027,7 @@ function AnchoredMenu({
|
|
|
965
1027
|
testID,
|
|
966
1028
|
anchorRef
|
|
967
1029
|
}) {
|
|
968
|
-
const menuRef =
|
|
1030
|
+
const menuRef = React2.useRef(null);
|
|
969
1031
|
useDismiss(anchorRef, menuRef, onDismiss);
|
|
970
1032
|
return /* @__PURE__ */ jsx(
|
|
971
1033
|
View,
|
|
@@ -1004,6 +1066,7 @@ function SelectControl({
|
|
|
1004
1066
|
placeholder = "",
|
|
1005
1067
|
accessibilityLabel,
|
|
1006
1068
|
accessibilityHint,
|
|
1069
|
+
labelledById,
|
|
1007
1070
|
optionHint = "",
|
|
1008
1071
|
style,
|
|
1009
1072
|
testID
|
|
@@ -1038,6 +1101,7 @@ function SelectControl({
|
|
|
1038
1101
|
accessibilityHint,
|
|
1039
1102
|
accessibilityState: { expanded: isOpen },
|
|
1040
1103
|
"aria-expanded": isOpen,
|
|
1104
|
+
"aria-labelledby": labelledById,
|
|
1041
1105
|
onPress: toggle,
|
|
1042
1106
|
style: [controlStyles.selectTrigger, { borderColor: colors.border, backgroundColor: colors.surface }],
|
|
1043
1107
|
testID: `${testID}-trigger`,
|