@dloizides/ui-forms 1.9.1 → 1.12.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 +327 -280
- package/dist/index.d.mts +79 -3
- package/dist/index.d.ts +79 -3
- package/dist/index.js +240 -166
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +216 -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,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,41 +600,39 @@ 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,
|
|
609
|
+
labelHidden = false,
|
|
472
610
|
required = false,
|
|
473
611
|
error,
|
|
474
612
|
containerStyle,
|
|
475
613
|
...textInputProps
|
|
476
|
-
}) => /* @__PURE__ */ jsx(
|
|
477
|
-
|
|
614
|
+
}) => /* @__PURE__ */ jsx(
|
|
615
|
+
Field,
|
|
478
616
|
{
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
617
|
+
containerStyle,
|
|
618
|
+
error,
|
|
619
|
+
label: labelHidden ? void 0 : label,
|
|
620
|
+
required,
|
|
621
|
+
children: ({ describedById, hasError, controlId }) => /* @__PURE__ */ jsx(
|
|
622
|
+
ThemedTextInput,
|
|
623
|
+
{
|
|
624
|
+
accessibilityHint: `Enter ${label}`,
|
|
625
|
+
accessibilityLabel: label,
|
|
626
|
+
describedById,
|
|
627
|
+
hasError,
|
|
628
|
+
id: controlId,
|
|
629
|
+
requiredField: required,
|
|
630
|
+
testID: "form-field-input",
|
|
631
|
+
...textInputProps
|
|
632
|
+
}
|
|
633
|
+
)
|
|
487
634
|
}
|
|
488
|
-
)
|
|
635
|
+
);
|
|
489
636
|
var TRANSPARENT_COLOR = "transparent";
|
|
490
637
|
var WHITE_COLOR = "#fff";
|
|
491
638
|
var SOLID_RADIUS = 20;
|
|
@@ -519,7 +666,7 @@ function withAlpha2(hex, alpha) {
|
|
|
519
666
|
const isValid = !Number.isNaN(r) && !Number.isNaN(g) && !Number.isNaN(b);
|
|
520
667
|
return isValid ? `rgba(${r}, ${g}, ${b}, ${alpha})` : hex;
|
|
521
668
|
}
|
|
522
|
-
var
|
|
669
|
+
var styles5 = StyleSheet.create({
|
|
523
670
|
chipContainer: {
|
|
524
671
|
flexDirection: "row",
|
|
525
672
|
flexWrap: "wrap",
|
|
@@ -571,7 +718,7 @@ function OutlineChip({
|
|
|
571
718
|
ariaPressed,
|
|
572
719
|
onPress
|
|
573
720
|
}) {
|
|
574
|
-
const [hovered, setHovered] =
|
|
721
|
+
const [hovered, setHovered] = React2.useState(false);
|
|
575
722
|
const active = selected || hovered;
|
|
576
723
|
const borderColor = active ? colors.primary : colors.border;
|
|
577
724
|
const backgroundColor = selected ? colors.tint : colors.muted;
|
|
@@ -590,7 +737,7 @@ function OutlineChip({
|
|
|
590
737
|
onHoverIn: () => setHovered(true),
|
|
591
738
|
onHoverOut: () => setHovered(false),
|
|
592
739
|
onPress,
|
|
593
|
-
children: /* @__PURE__ */ jsx(View, { style: [
|
|
740
|
+
children: /* @__PURE__ */ jsx(View, { style: [styles5.chipOutline, { borderColor, backgroundColor }], children: /* @__PURE__ */ jsx(Text, { style: [styles5.chipText, styles5.chipTextOutline, { color: textColor }], children: option.label }) })
|
|
594
741
|
}
|
|
595
742
|
);
|
|
596
743
|
}
|
|
@@ -618,7 +765,7 @@ function SolidChip({
|
|
|
618
765
|
hitSlop: CHIP_HIT_SLOP,
|
|
619
766
|
testID,
|
|
620
767
|
onPress,
|
|
621
|
-
children: /* @__PURE__ */ jsx(View, { style: [
|
|
768
|
+
children: /* @__PURE__ */ jsx(View, { style: [styles5.chip, { borderColor: colors.border, backgroundColor }], children: /* @__PURE__ */ jsx(Text, { style: [styles5.chipText, { color: textColor }], children: option.label }) })
|
|
622
769
|
}
|
|
623
770
|
);
|
|
624
771
|
}
|
|
@@ -640,7 +787,7 @@ var ChipSelector = ({
|
|
|
640
787
|
}) => {
|
|
641
788
|
const { theme } = useUi();
|
|
642
789
|
const { colors, palette } = theme;
|
|
643
|
-
const chipColors =
|
|
790
|
+
const chipColors = React2.useMemo(() => {
|
|
644
791
|
const primary = palette.primary["500"];
|
|
645
792
|
return {
|
|
646
793
|
border: colors.border,
|
|
@@ -683,12 +830,12 @@ var ChipSelector = ({
|
|
|
683
830
|
required,
|
|
684
831
|
spacing,
|
|
685
832
|
testID,
|
|
686
|
-
children: ({ describedById, hasError }) => /* @__PURE__ */ jsx(View, { style:
|
|
833
|
+
children: ({ describedById, hasError }) => /* @__PURE__ */ jsx(View, { style: styles5.chipContainer, ...webFieldA11y({ describedById, hasError }), children: options.map(renderChip) })
|
|
687
834
|
}
|
|
688
835
|
);
|
|
689
836
|
};
|
|
690
837
|
var DESCRIPTION_FONT_SIZE2 = 12;
|
|
691
|
-
var
|
|
838
|
+
var styles6 = StyleSheet.create({
|
|
692
839
|
container: {
|
|
693
840
|
flexDirection: "row",
|
|
694
841
|
justifyContent: "space-between",
|
|
@@ -719,7 +866,7 @@ var FormSwitch = ({
|
|
|
719
866
|
const { theme } = useUi();
|
|
720
867
|
const { colors } = theme;
|
|
721
868
|
const hasDescription = typeof description === "string" && description !== "";
|
|
722
|
-
const themeStyles =
|
|
869
|
+
const themeStyles = React2.useMemo(() => {
|
|
723
870
|
const labelStyle = { color: colors.text };
|
|
724
871
|
const descriptionStyle = { color: colors.textSecondary };
|
|
725
872
|
return { label: labelStyle, description: descriptionStyle };
|
|
@@ -728,13 +875,13 @@ var FormSwitch = ({
|
|
|
728
875
|
View,
|
|
729
876
|
{
|
|
730
877
|
style: [
|
|
731
|
-
|
|
878
|
+
styles6.container,
|
|
732
879
|
containerStyle
|
|
733
880
|
],
|
|
734
881
|
children: [
|
|
735
|
-
/* @__PURE__ */ jsxs(View, { style:
|
|
736
|
-
/* @__PURE__ */ jsx(Text, { style: [
|
|
737
|
-
hasDescription ? /* @__PURE__ */ jsx(Text, { style: [
|
|
882
|
+
/* @__PURE__ */ jsxs(View, { style: styles6.textColumn, children: [
|
|
883
|
+
/* @__PURE__ */ jsx(Text, { style: [styles6.label, themeStyles.label], children: label }),
|
|
884
|
+
hasDescription ? /* @__PURE__ */ jsx(Text, { style: [styles6.description, themeStyles.description], children: description }) : null
|
|
738
885
|
] }),
|
|
739
886
|
/* @__PURE__ */ jsx(
|
|
740
887
|
Switch,
|
|
@@ -759,7 +906,7 @@ var BOX_SIZE = 20;
|
|
|
759
906
|
var BOX_RADIUS = 5;
|
|
760
907
|
var CHECK_FONT_SIZE = 14;
|
|
761
908
|
var DISABLED_OPACITY = 0.5;
|
|
762
|
-
var
|
|
909
|
+
var styles7 = StyleSheet.create({
|
|
763
910
|
container: {
|
|
764
911
|
flexDirection: "row",
|
|
765
912
|
alignItems: "flex-start",
|
|
@@ -810,7 +957,7 @@ var FormCheckbox = ({
|
|
|
810
957
|
const brand = palette.primary["500"];
|
|
811
958
|
const hintText = typeof hint === "string" && hint !== "" ? hint : description;
|
|
812
959
|
const hasHint = typeof hintText === "string" && hintText !== "";
|
|
813
|
-
const themeStyles =
|
|
960
|
+
const themeStyles = React2.useMemo(() => {
|
|
814
961
|
const boxOn = { backgroundColor: brand, borderColor: brand };
|
|
815
962
|
const boxOff = { backgroundColor: "transparent", borderColor: colors.border };
|
|
816
963
|
const labelStyle = { color: colors.text };
|
|
@@ -841,101 +988,26 @@ var FormCheckbox = ({
|
|
|
841
988
|
disabled,
|
|
842
989
|
onPress: toggle,
|
|
843
990
|
role: "checkbox",
|
|
844
|
-
style: [
|
|
991
|
+
style: [styles7.container, containerStyle, disabled ? { opacity: DISABLED_OPACITY } : null],
|
|
845
992
|
testID,
|
|
846
993
|
...keyboardProps,
|
|
847
994
|
children: [
|
|
848
|
-
/* @__PURE__ */ jsx(View, { style: [
|
|
849
|
-
/* @__PURE__ */ jsxs(View, { style:
|
|
850
|
-
/* @__PURE__ */ jsx(Text, { style: [
|
|
851
|
-
hasHint ? /* @__PURE__ */ jsx(Text, { style: [
|
|
995
|
+
/* @__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 }),
|
|
996
|
+
/* @__PURE__ */ jsxs(View, { style: styles7.textColumn, children: [
|
|
997
|
+
/* @__PURE__ */ jsx(Text, { style: [styles7.label, themeStyles.label], children: label }),
|
|
998
|
+
hasHint ? /* @__PURE__ */ jsx(Text, { style: [styles7.hint, themeStyles.hint], children: hintText }) : null
|
|
852
999
|
] })
|
|
853
1000
|
]
|
|
854
1001
|
}
|
|
855
1002
|
);
|
|
856
1003
|
};
|
|
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";
|
|
1004
|
+
var IS_WEB5 = typeof document !== "undefined";
|
|
933
1005
|
var ESCAPE_KEY = "Escape";
|
|
934
1006
|
var ACTIVE_WEIGHT = "700";
|
|
935
1007
|
var IDLE_WEIGHT = "400";
|
|
936
1008
|
function useDismiss(anchorRef, menuRef, onDismiss) {
|
|
937
1009
|
useEffect(() => {
|
|
938
|
-
if (!
|
|
1010
|
+
if (!IS_WEB5) return void 0;
|
|
939
1011
|
const onMouseDown = (event) => {
|
|
940
1012
|
const anchorNode = anchorRef.current;
|
|
941
1013
|
const menuNode = menuRef.current;
|
|
@@ -965,7 +1037,7 @@ function AnchoredMenu({
|
|
|
965
1037
|
testID,
|
|
966
1038
|
anchorRef
|
|
967
1039
|
}) {
|
|
968
|
-
const menuRef =
|
|
1040
|
+
const menuRef = React2.useRef(null);
|
|
969
1041
|
useDismiss(anchorRef, menuRef, onDismiss);
|
|
970
1042
|
return /* @__PURE__ */ jsx(
|
|
971
1043
|
View,
|
|
@@ -1004,6 +1076,7 @@ function SelectControl({
|
|
|
1004
1076
|
placeholder = "",
|
|
1005
1077
|
accessibilityLabel,
|
|
1006
1078
|
accessibilityHint,
|
|
1079
|
+
labelledById,
|
|
1007
1080
|
optionHint = "",
|
|
1008
1081
|
style,
|
|
1009
1082
|
testID
|
|
@@ -1038,6 +1111,7 @@ function SelectControl({
|
|
|
1038
1111
|
accessibilityHint,
|
|
1039
1112
|
accessibilityState: { expanded: isOpen },
|
|
1040
1113
|
"aria-expanded": isOpen,
|
|
1114
|
+
"aria-labelledby": labelledById,
|
|
1041
1115
|
onPress: toggle,
|
|
1042
1116
|
style: [controlStyles.selectTrigger, { borderColor: colors.border, backgroundColor: colors.surface }],
|
|
1043
1117
|
testID: `${testID}-trigger`,
|