@dloizides/ui-forms 1.21.0 → 1.23.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 +17 -0
- package/dist/index.d.mts +116 -8
- package/dist/index.d.ts +116 -8
- package/dist/index.js +537 -93
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +535 -97
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import React2, { useState, useCallback, useMemo,
|
|
2
|
-
import { Platform, StyleSheet, TextInput, View, Text, useWindowDimensions, ScrollView, Pressable, Switch, TouchableOpacity } from 'react-native';
|
|
1
|
+
import React2, { forwardRef, useState, useCallback, useMemo, useRef, useEffect, useLayoutEffect } from 'react';
|
|
2
|
+
import { Platform, StyleSheet, TextInput, View, Text, useWindowDimensions, ScrollView, Pressable, Switch, Image, TouchableOpacity } from 'react-native';
|
|
3
3
|
import { useUi } from '@dloizides/ui-feedback';
|
|
4
4
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
5
|
import { Z_INDEX, focusRingOutline, readableScaleInk } from '@dloizides/design-tokens';
|
|
6
|
-
import { themeFocusRingColor, Button } from '@dloizides/ui-buttons';
|
|
6
|
+
import { themeFocusRingColor, Button, useFocusRing } from '@dloizides/ui-buttons';
|
|
7
7
|
import { createPortal } from 'react-dom';
|
|
8
8
|
import { MIN_TOUCH_TARGET_PX } from '@dloizides/a11y';
|
|
9
9
|
|
|
@@ -544,9 +544,55 @@ var controlStyles = StyleSheet.create({
|
|
|
544
544
|
optionText: { fontSize: OPTION_FONT },
|
|
545
545
|
error: { fontSize: ERROR_FONT, marginTop: ERROR_GAP }
|
|
546
546
|
});
|
|
547
|
+
var ACTIVE_WEIGHT = "700";
|
|
548
|
+
var IDLE_WEIGHT = "400";
|
|
549
|
+
var DETAIL_FONT = 12;
|
|
550
|
+
var DETAIL_GAP = 12;
|
|
551
|
+
var STACK_GAP = 2;
|
|
552
|
+
var DETAIL_BESIDE_MIN_MENU_WIDTH = 400;
|
|
553
|
+
var styles7 = StyleSheet.create({
|
|
554
|
+
beside: { alignItems: "baseline", flexDirection: "row", gap: DETAIL_GAP, justifyContent: "space-between" },
|
|
555
|
+
stacked: { gap: STACK_GAP },
|
|
556
|
+
shrink: { flexShrink: 1 },
|
|
557
|
+
detail: { flexShrink: 1, fontSize: DETAIL_FONT }
|
|
558
|
+
});
|
|
559
|
+
function optionDomId(testID, value) {
|
|
560
|
+
return `${testID}-option-${value}`.replace(/\s+/g, "_");
|
|
561
|
+
}
|
|
562
|
+
function listboxDomId(testID) {
|
|
563
|
+
return `${testID}-listbox`;
|
|
564
|
+
}
|
|
565
|
+
function isDetailBesideTitle(menuWidth) {
|
|
566
|
+
return menuWidth >= DETAIL_BESIDE_MIN_MENU_WIDTH;
|
|
567
|
+
}
|
|
568
|
+
function OptionRow({ option, isActive, isHighlighted, isListboxRow, menuWidth, hint, colors, testID, onSelect }) {
|
|
569
|
+
const hasDetail = option.detail !== void 0 && option.detail !== "";
|
|
570
|
+
const label = hasDetail ? `${option.label}, ${option.detail}` : option.label;
|
|
571
|
+
const roleProps = isListboxRow ? { role: "option", tabIndex: -1, id: optionDomId(testID, option.value), "aria-selected": isHighlighted } : { accessibilityRole: "menuitem", "aria-selected": isActive };
|
|
572
|
+
const isBold = isActive || isHighlighted;
|
|
573
|
+
const titleColor = isActive ? colors.brand : colors.text;
|
|
574
|
+
return /* @__PURE__ */ jsx(
|
|
575
|
+
Pressable,
|
|
576
|
+
{
|
|
577
|
+
...roleProps,
|
|
578
|
+
accessibilityLabel: label,
|
|
579
|
+
accessibilityHint: hint,
|
|
580
|
+
accessibilityState: { selected: isActive },
|
|
581
|
+
onPress: () => onSelect(option.value),
|
|
582
|
+
style: [controlStyles.option, isHighlighted ? { backgroundColor: colors.border } : null],
|
|
583
|
+
testID: `${testID}-option-${option.value}`,
|
|
584
|
+
children: /* @__PURE__ */ jsxs(View, { style: isDetailBesideTitle(menuWidth) ? styles7.beside : styles7.stacked, children: [
|
|
585
|
+
/* @__PURE__ */ jsx(Text, { style: [controlStyles.optionText, styles7.shrink, { color: titleColor, fontWeight: isBold ? ACTIVE_WEIGHT : IDLE_WEIGHT }], children: option.label }),
|
|
586
|
+
hasDetail ? /* @__PURE__ */ jsx(Text, { style: [styles7.detail, { color: colors.textSecondary ?? colors.text }], children: option.detail }) : null
|
|
587
|
+
] })
|
|
588
|
+
}
|
|
589
|
+
);
|
|
590
|
+
}
|
|
547
591
|
var IS_WEB3 = Platform.OS === "web";
|
|
548
592
|
var MENU_PORTAL_Z_INDEX = Z_INDEX.popover;
|
|
549
593
|
var MENU_TOP_GAP2 = 4;
|
|
594
|
+
var MENU_MIN_HEIGHT = 96;
|
|
595
|
+
var VIEWPORT_MARGIN = 8;
|
|
550
596
|
function toDomNode(ref) {
|
|
551
597
|
const node = ref.current;
|
|
552
598
|
if (node === null || typeof node.getBoundingClientRect !== "function") return null;
|
|
@@ -559,8 +605,9 @@ function readAnchorRect(ref) {
|
|
|
559
605
|
const r = node.getBoundingClientRect();
|
|
560
606
|
return { top: r.top, left: r.left, width: r.width, bottom: r.bottom };
|
|
561
607
|
}
|
|
562
|
-
function buildPortalPopoverStyle(rect) {
|
|
608
|
+
function buildPortalPopoverStyle(rect, viewportBottom) {
|
|
563
609
|
return {
|
|
610
|
+
...viewportBottom !== void 0 ? { maxHeight: menuMaxHeight(rect.bottom, viewportBottom) } : null,
|
|
564
611
|
// RN's ViewStyle union omits 'fixed', but react-native-web honours it at runtime.
|
|
565
612
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- web-only position value
|
|
566
613
|
position: "fixed",
|
|
@@ -607,10 +654,64 @@ function useAnchorRect(ref, enabled) {
|
|
|
607
654
|
}, [ref, enabled]);
|
|
608
655
|
return IS_WEB3 && enabled ? rect : null;
|
|
609
656
|
}
|
|
657
|
+
function roomUnderAnchor(anchorBottom, viewportBottom) {
|
|
658
|
+
return viewportBottom - anchorBottom - MENU_TOP_GAP2 - VIEWPORT_MARGIN;
|
|
659
|
+
}
|
|
660
|
+
function menuMaxHeight(anchorBottom, viewportBottom) {
|
|
661
|
+
return Math.min(MENU_MAX_HEIGHT, Math.max(MENU_MIN_HEIGHT, roomUnderAnchor(anchorBottom, viewportBottom)));
|
|
662
|
+
}
|
|
663
|
+
function anchorScrollBlock(anchorBottom, viewportBottom) {
|
|
664
|
+
return roomUnderAnchor(anchorBottom, viewportBottom) < MENU_MAX_HEIGHT ? "start" : "nearest";
|
|
665
|
+
}
|
|
666
|
+
function readViewportBottom() {
|
|
667
|
+
const viewport = window.visualViewport ?? null;
|
|
668
|
+
return viewport === null ? window.innerHeight : viewport.offsetTop + viewport.height;
|
|
669
|
+
}
|
|
670
|
+
function useVisualViewportBottom(enabled) {
|
|
671
|
+
const [bottom, setBottom] = useState(null);
|
|
672
|
+
useLayoutEffect(() => {
|
|
673
|
+
if (!IS_WEB3 || !enabled) {
|
|
674
|
+
setBottom(null);
|
|
675
|
+
return void 0;
|
|
676
|
+
}
|
|
677
|
+
const update = () => setBottom(readViewportBottom());
|
|
678
|
+
update();
|
|
679
|
+
const viewport = window.visualViewport ?? null;
|
|
680
|
+
viewport?.addEventListener("resize", update);
|
|
681
|
+
viewport?.addEventListener("scroll", update);
|
|
682
|
+
window.addEventListener("resize", update);
|
|
683
|
+
return () => {
|
|
684
|
+
viewport?.removeEventListener("resize", update);
|
|
685
|
+
viewport?.removeEventListener("scroll", update);
|
|
686
|
+
window.removeEventListener("resize", update);
|
|
687
|
+
};
|
|
688
|
+
}, [enabled]);
|
|
689
|
+
return bottom;
|
|
690
|
+
}
|
|
691
|
+
function scrollNodeIntoView(node, block) {
|
|
692
|
+
if (node !== null && typeof node.scrollIntoView === "function") node.scrollIntoView({ block });
|
|
693
|
+
}
|
|
694
|
+
function scrollAnchorIntoView(ref, marginTop) {
|
|
695
|
+
if (!IS_WEB3) return;
|
|
696
|
+
const node = toDomNode(ref);
|
|
697
|
+
if (node === null) return;
|
|
698
|
+
node.style.scrollMarginTop = `${marginTop}px`;
|
|
699
|
+
scrollNodeIntoView(node, anchorScrollBlock(node.getBoundingClientRect().bottom, readViewportBottom()));
|
|
700
|
+
}
|
|
701
|
+
function useKeepAnchorInRoom(ref, marginTop, enabled) {
|
|
702
|
+
useLayoutEffect(() => {
|
|
703
|
+
if (!IS_WEB3 || !enabled) return void 0;
|
|
704
|
+
const place = () => scrollAnchorIntoView(ref, marginTop);
|
|
705
|
+
place();
|
|
706
|
+
const viewport = window.visualViewport ?? null;
|
|
707
|
+
viewport?.addEventListener("resize", place);
|
|
708
|
+
return () => viewport?.removeEventListener("resize", place);
|
|
709
|
+
}, [ref, marginTop, enabled]);
|
|
710
|
+
}
|
|
610
711
|
var IS_WEB4 = typeof document !== "undefined";
|
|
611
712
|
var ESCAPE_KEY = "Escape";
|
|
612
|
-
var
|
|
613
|
-
var
|
|
713
|
+
var LISTBOX_ROLE = { role: "listbox" };
|
|
714
|
+
var KEEP_FIELD_FOCUS = { onMouseDown: (event) => event.preventDefault() };
|
|
614
715
|
function useDismiss(anchorRef, menuRef, onDismiss) {
|
|
615
716
|
useEffect(() => {
|
|
616
717
|
if (!IS_WEB4) return void 0;
|
|
@@ -633,6 +734,12 @@ function useDismiss(anchorRef, menuRef, onDismiss) {
|
|
|
633
734
|
};
|
|
634
735
|
}, [anchorRef, menuRef, onDismiss]);
|
|
635
736
|
}
|
|
737
|
+
function useKeepHighlightInView(testID, highlightedValue) {
|
|
738
|
+
useEffect(() => {
|
|
739
|
+
if (!IS_WEB4 || highlightedValue === void 0 || highlightedValue === "") return;
|
|
740
|
+
scrollNodeIntoView(document.getElementById(optionDomId(testID, highlightedValue)), "nearest");
|
|
741
|
+
}, [testID, highlightedValue]);
|
|
742
|
+
}
|
|
636
743
|
function AnchoredMenu({
|
|
637
744
|
options,
|
|
638
745
|
selectedValue,
|
|
@@ -643,38 +750,48 @@ function AnchoredMenu({
|
|
|
643
750
|
accessibilityLabel,
|
|
644
751
|
testID,
|
|
645
752
|
anchorRef,
|
|
646
|
-
usePortal = true
|
|
753
|
+
usePortal = true,
|
|
754
|
+
listbox
|
|
647
755
|
}) {
|
|
648
756
|
const menuRef = React2.useRef(null);
|
|
649
757
|
useDismiss(anchorRef, menuRef, onDismiss);
|
|
758
|
+
useKeepHighlightInView(testID, listbox?.highlightedValue);
|
|
650
759
|
const rect = useAnchorRect(anchorRef, usePortal);
|
|
651
|
-
const
|
|
652
|
-
const
|
|
760
|
+
const viewportBottom = useVisualViewportBottom(usePortal);
|
|
761
|
+
const portalStyle = rect !== null ? buildPortalPopoverStyle(rect, viewportBottom ?? void 0) : null;
|
|
762
|
+
const { width: windowWidth } = useWindowDimensions();
|
|
763
|
+
const menuWidth = rect?.width ?? windowWidth;
|
|
764
|
+
const isListbox = listbox !== void 0;
|
|
765
|
+
const statusText = listbox?.statusText;
|
|
766
|
+
const rows = options.map((option) => /* @__PURE__ */ jsx(
|
|
767
|
+
OptionRow,
|
|
768
|
+
{
|
|
769
|
+
colors,
|
|
770
|
+
hint: optionHint,
|
|
771
|
+
isActive: option.value === selectedValue,
|
|
772
|
+
isHighlighted: option.value === listbox?.highlightedValue,
|
|
773
|
+
isListboxRow: isListbox,
|
|
774
|
+
menuWidth,
|
|
775
|
+
option,
|
|
776
|
+
testID,
|
|
777
|
+
onSelect
|
|
778
|
+
},
|
|
779
|
+
option.value
|
|
780
|
+
));
|
|
781
|
+
const listboxBody = options.length > 0 ? /* @__PURE__ */ jsx(View, { accessibilityLabel, id: listboxDomId(testID), ...LISTBOX_ROLE, testID: listboxDomId(testID), children: rows }) : null;
|
|
782
|
+
const menu = /* @__PURE__ */ jsxs(
|
|
653
783
|
View,
|
|
654
784
|
{
|
|
785
|
+
...isListbox ? KEEP_FIELD_FOCUS : null,
|
|
655
786
|
ref: menuRef,
|
|
656
|
-
accessibilityLabel,
|
|
657
|
-
accessibilityRole: "menu",
|
|
787
|
+
accessibilityLabel: isListbox ? void 0 : accessibilityLabel,
|
|
788
|
+
accessibilityRole: isListbox ? void 0 : "menu",
|
|
658
789
|
style: [controlStyles.menu, { borderColor: colors.border, backgroundColor: colors.surface }, portalStyle],
|
|
659
790
|
testID: `${testID}-menu`,
|
|
660
|
-
children:
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
{
|
|
665
|
-
accessibilityRole: "menuitem",
|
|
666
|
-
accessibilityLabel: opt.label,
|
|
667
|
-
accessibilityHint: optionHint,
|
|
668
|
-
accessibilityState: { selected: active },
|
|
669
|
-
"aria-selected": active,
|
|
670
|
-
onPress: () => onSelect(opt.value),
|
|
671
|
-
style: controlStyles.option,
|
|
672
|
-
testID: `${testID}-option-${opt.value}`,
|
|
673
|
-
children: /* @__PURE__ */ jsx(Text, { style: [controlStyles.optionText, { color: active ? colors.brand : colors.text, fontWeight: active ? ACTIVE_WEIGHT : IDLE_WEIGHT }], children: opt.label })
|
|
674
|
-
},
|
|
675
|
-
opt.value
|
|
676
|
-
);
|
|
677
|
-
}) })
|
|
791
|
+
children: [
|
|
792
|
+
isListbox ? /* @__PURE__ */ jsx(Text, { role: "status", style: statusText !== void 0 ? [controlStyles.option, controlStyles.optionText, { color: colors.text }] : void 0, children: statusText ?? "" }) : null,
|
|
793
|
+
/* @__PURE__ */ jsx(ScrollView, { keyboardShouldPersistTaps: "handled", nestedScrollEnabled: true, children: isListbox ? listboxBody : rows })
|
|
794
|
+
]
|
|
678
795
|
}
|
|
679
796
|
);
|
|
680
797
|
if (usePortal && IS_WEB4) return createPortal(menu, document.body);
|
|
@@ -1249,7 +1366,7 @@ function chipIdentity(option, selected, config) {
|
|
|
1249
1366
|
ariaChecked: isRadio ? selected : void 0
|
|
1250
1367
|
};
|
|
1251
1368
|
}
|
|
1252
|
-
var
|
|
1369
|
+
var styles8 = StyleSheet.create({
|
|
1253
1370
|
chipContainer: {
|
|
1254
1371
|
flexDirection: "row",
|
|
1255
1372
|
flexWrap: "wrap",
|
|
@@ -1335,7 +1452,7 @@ var ChipSelector = ({
|
|
|
1335
1452
|
View,
|
|
1336
1453
|
{
|
|
1337
1454
|
accessibilityRole: isRadioGroup ? "radiogroup" : void 0,
|
|
1338
|
-
style:
|
|
1455
|
+
style: styles8.chipContainer,
|
|
1339
1456
|
...webFieldA11y({ describedById, hasError }),
|
|
1340
1457
|
...radio.groupProps,
|
|
1341
1458
|
children: options.map(renderChip)
|
|
@@ -1345,7 +1462,7 @@ var ChipSelector = ({
|
|
|
1345
1462
|
);
|
|
1346
1463
|
};
|
|
1347
1464
|
var DESCRIPTION_FONT_SIZE2 = 12;
|
|
1348
|
-
var
|
|
1465
|
+
var styles9 = StyleSheet.create({
|
|
1349
1466
|
container: {
|
|
1350
1467
|
flexDirection: "row",
|
|
1351
1468
|
justifyContent: "space-between",
|
|
@@ -1406,15 +1523,15 @@ var FormSwitch = ({
|
|
|
1406
1523
|
accessible: false,
|
|
1407
1524
|
disabled,
|
|
1408
1525
|
onPress: toggle,
|
|
1409
|
-
style: [
|
|
1526
|
+
style: [styles9.container, containerStyle],
|
|
1410
1527
|
tabIndex: -1,
|
|
1411
1528
|
testID: `${testID}-row`,
|
|
1412
1529
|
children: [
|
|
1413
|
-
/* @__PURE__ */ jsxs(View, { style:
|
|
1414
|
-
/* @__PURE__ */ jsx(Text, { style: [
|
|
1415
|
-
hasDescription ? /* @__PURE__ */ jsx(Text, { style: [
|
|
1530
|
+
/* @__PURE__ */ jsxs(View, { style: styles9.textColumn, children: [
|
|
1531
|
+
/* @__PURE__ */ jsx(Text, { style: [styles9.label, themeStyles.label], children: label }),
|
|
1532
|
+
hasDescription ? /* @__PURE__ */ jsx(Text, { style: [styles9.description, themeStyles.description], children: description }) : null
|
|
1416
1533
|
] }),
|
|
1417
|
-
/* @__PURE__ */ jsx(View, { pointerEvents: "none", style:
|
|
1534
|
+
/* @__PURE__ */ jsx(View, { pointerEvents: "none", style: styles9.switchSlot, testID: `${testID}-hitbox`, children: /* @__PURE__ */ jsx(
|
|
1418
1535
|
Switch,
|
|
1419
1536
|
{
|
|
1420
1537
|
accessibilityHint: accessibilityHint ?? label,
|
|
@@ -1443,7 +1560,7 @@ var DISABLED_OPACITY = 0.5;
|
|
|
1443
1560
|
var FOCUS_RING_WIDTH = 2;
|
|
1444
1561
|
var WEB_NO_DEFAULT_OUTLINE = { outlineStyle: "none" };
|
|
1445
1562
|
var FOCUS_RING_INSET = -6;
|
|
1446
|
-
var
|
|
1563
|
+
var styles10 = StyleSheet.create({
|
|
1447
1564
|
container: {
|
|
1448
1565
|
flexDirection: "row",
|
|
1449
1566
|
alignItems: "flex-start",
|
|
@@ -1548,8 +1665,8 @@ var FormCheckbox = ({
|
|
|
1548
1665
|
onPress: toggle,
|
|
1549
1666
|
role: "checkbox",
|
|
1550
1667
|
style: [
|
|
1551
|
-
|
|
1552
|
-
hasHint ? null :
|
|
1668
|
+
styles10.container,
|
|
1669
|
+
hasHint ? null : styles10.centered,
|
|
1553
1670
|
containerStyle,
|
|
1554
1671
|
disabled ? { opacity: DISABLED_OPACITY } : null,
|
|
1555
1672
|
Platform.OS === "web" ? WEB_NO_DEFAULT_OUTLINE : null
|
|
@@ -1557,13 +1674,13 @@ var FormCheckbox = ({
|
|
|
1557
1674
|
testID,
|
|
1558
1675
|
...keyboardProps,
|
|
1559
1676
|
children: [
|
|
1560
|
-
/* @__PURE__ */ jsxs(View, { style: [
|
|
1561
|
-
focused ? /* @__PURE__ */ jsx(View, { pointerEvents: "none", style: [
|
|
1562
|
-
value ? /* @__PURE__ */ jsx(Text, { style: [
|
|
1677
|
+
/* @__PURE__ */ jsxs(View, { style: [styles10.box, value ? themeStyles.boxOn : themeStyles.boxOff], testID: `${testID}-box`, children: [
|
|
1678
|
+
focused ? /* @__PURE__ */ jsx(View, { pointerEvents: "none", style: [styles10.focusRing, themeStyles.ring], testID: `${testID}-focus-ring` }) : null,
|
|
1679
|
+
value ? /* @__PURE__ */ jsx(Text, { style: [styles10.check, { color: colors.surface }], accessibilityElementsHidden: true, children: "\u2713" }) : null
|
|
1563
1680
|
] }),
|
|
1564
|
-
/* @__PURE__ */ jsxs(View, { style:
|
|
1565
|
-
/* @__PURE__ */ jsx(Text, { style: [
|
|
1566
|
-
hasHint ? /* @__PURE__ */ jsx(Text, { nativeID: hintId, style: [
|
|
1681
|
+
/* @__PURE__ */ jsxs(View, { style: styles10.textColumn, children: [
|
|
1682
|
+
/* @__PURE__ */ jsx(Text, { style: [styles10.label, themeStyles.label], children: label }),
|
|
1683
|
+
hasHint ? /* @__PURE__ */ jsx(Text, { nativeID: hintId, style: [styles10.hint, themeStyles.hint], children: hintText }) : null
|
|
1567
1684
|
] })
|
|
1568
1685
|
]
|
|
1569
1686
|
}
|
|
@@ -1670,94 +1787,212 @@ function isUnmatched(options, text) {
|
|
|
1670
1787
|
if (needle === "") return false;
|
|
1671
1788
|
return !options.some((o) => o.value.toLowerCase() === needle || o.label.toLowerCase() === needle);
|
|
1672
1789
|
}
|
|
1673
|
-
var
|
|
1674
|
-
var
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1790
|
+
var DEFAULT_TYPEAHEAD_DEBOUNCE_MS = 250;
|
|
1791
|
+
var IDLE = { results: [], isLoading: false, hasFailed: false, hasSettled: false };
|
|
1792
|
+
function useTypeaheadSearch(load, query, enabled, debounceMs) {
|
|
1793
|
+
const [state, setState] = useState(IDLE);
|
|
1794
|
+
const loadRef = useRef(load);
|
|
1795
|
+
loadRef.current = load;
|
|
1796
|
+
useEffect(() => {
|
|
1797
|
+
if (!enabled) {
|
|
1798
|
+
setState(IDLE);
|
|
1799
|
+
return void 0;
|
|
1800
|
+
}
|
|
1801
|
+
setState((current) => ({ ...current, isLoading: true, hasFailed: false }));
|
|
1802
|
+
const controller = new AbortController();
|
|
1803
|
+
const settle = (next) => {
|
|
1804
|
+
if (!controller.signal.aborted) setState(next);
|
|
1805
|
+
};
|
|
1806
|
+
const timer = setTimeout(() => {
|
|
1807
|
+
Promise.resolve().then(() => loadRef.current?.(query, controller.signal) ?? []).then(
|
|
1808
|
+
(results) => settle({ results, isLoading: false, hasFailed: false, hasSettled: true }),
|
|
1809
|
+
() => settle({ results: [], isLoading: false, hasFailed: true, hasSettled: true })
|
|
1810
|
+
);
|
|
1811
|
+
}, debounceMs);
|
|
1812
|
+
return () => {
|
|
1813
|
+
clearTimeout(timer);
|
|
1814
|
+
controller.abort();
|
|
1815
|
+
};
|
|
1816
|
+
}, [query, enabled, debounceMs]);
|
|
1817
|
+
return state;
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
// src/TypeaheadControl/hooks/useTypeaheadState.ts
|
|
1821
|
+
var NO_HIGHLIGHT = -1;
|
|
1822
|
+
var FORWARD = 1;
|
|
1823
|
+
var BACKWARD = -1;
|
|
1824
|
+
var NO_ROWS = [];
|
|
1825
|
+
function nextHighlight(current, count, delta) {
|
|
1826
|
+
if (count === 0) return NO_HIGHLIGHT;
|
|
1827
|
+
if (current === NO_HIGHLIGHT) return delta > 0 ? 0 : count - 1;
|
|
1828
|
+
return (current + delta + count) % count;
|
|
1829
|
+
}
|
|
1830
|
+
function searchStatusText(found, search) {
|
|
1831
|
+
if (found.hasFailed) return search.errorText;
|
|
1832
|
+
if (found.results.length > 0) return void 0;
|
|
1833
|
+
if (found.isLoading) return search.loadingText;
|
|
1834
|
+
return found.hasSettled ? search.emptyText : void 0;
|
|
1835
|
+
}
|
|
1836
|
+
function useTypeaheadRows(input, isOpen, isPicked) {
|
|
1837
|
+
const { options, search, value, minChars, maxSuggestions } = input;
|
|
1838
|
+
const query = value.trim();
|
|
1839
|
+
const isSearching = search !== void 0 && isOpen && !isPicked && query.length >= minChars;
|
|
1840
|
+
const found = useTypeaheadSearch(search?.load, query, isSearching, search?.debounceMs ?? DEFAULT_TYPEAHEAD_DEBOUNCE_MS);
|
|
1841
|
+
const staticRows = useMemo(() => {
|
|
1842
|
+
if (options === void 0 || options.some((o) => o.label === value)) return NO_ROWS;
|
|
1843
|
+
return suggestOptions(options, value, minChars, maxSuggestions);
|
|
1844
|
+
}, [options, value, minChars, maxSuggestions]);
|
|
1845
|
+
const foundRows = useMemo(() => found.results.slice(0, maxSuggestions), [found.results, maxSuggestions]);
|
|
1846
|
+
if (search === void 0) return { rows: staticRows, statusText: void 0 };
|
|
1847
|
+
return { rows: foundRows, statusText: searchStatusText(found, search) };
|
|
1848
|
+
}
|
|
1849
|
+
function useTypeaheadState(input) {
|
|
1850
|
+
const { search, value, onChange, onSubmit } = input;
|
|
1694
1851
|
const [isOpen, setIsOpen] = useState(false);
|
|
1695
|
-
const
|
|
1696
|
-
const
|
|
1697
|
-
|
|
1698
|
-
|
|
1852
|
+
const [picked, setPicked] = useState(null);
|
|
1853
|
+
const [highlightIndex, setHighlightIndex] = useState(NO_HIGHLIGHT);
|
|
1854
|
+
const { rows, statusText } = useTypeaheadRows(input, isOpen, picked !== null && picked.label === value);
|
|
1855
|
+
const rowKey = rows.map((row) => row.value).join("\n");
|
|
1856
|
+
const highlighted = isOpen ? rows[highlightIndex] : void 0;
|
|
1857
|
+
useEffect(() => setHighlightIndex(NO_HIGHLIGHT), [rowKey]);
|
|
1858
|
+
useEffect(() => setPicked((current) => current !== null && current.label !== value ? null : current), [value]);
|
|
1859
|
+
const open = useCallback(() => setIsOpen(true), []);
|
|
1860
|
+
const close = useCallback(() => {
|
|
1861
|
+
setIsOpen(false);
|
|
1862
|
+
setHighlightIndex(NO_HIGHLIGHT);
|
|
1863
|
+
}, []);
|
|
1864
|
+
const pick = useCallback(
|
|
1865
|
+
(option) => {
|
|
1866
|
+
setPicked(option);
|
|
1867
|
+
onChange(option.label);
|
|
1868
|
+
search?.onPick(option);
|
|
1869
|
+
close();
|
|
1870
|
+
},
|
|
1871
|
+
[onChange, search, close]
|
|
1872
|
+
);
|
|
1873
|
+
const selectValue = useCallback(
|
|
1874
|
+
(optionValue) => {
|
|
1875
|
+
const option = rows.find((row) => row.value === optionValue);
|
|
1876
|
+
if (option !== void 0) pick(option);
|
|
1877
|
+
},
|
|
1878
|
+
[rows, pick]
|
|
1699
1879
|
);
|
|
1700
|
-
const showMenu = isOpen && suggestions.length > 0;
|
|
1701
1880
|
const handleChange = useCallback(
|
|
1702
1881
|
(next) => {
|
|
1882
|
+
if (picked !== null) {
|
|
1883
|
+
setPicked(null);
|
|
1884
|
+
search?.onPick(null);
|
|
1885
|
+
}
|
|
1703
1886
|
onChange(next);
|
|
1704
1887
|
setIsOpen(true);
|
|
1888
|
+
setHighlightIndex(NO_HIGHLIGHT);
|
|
1705
1889
|
},
|
|
1706
|
-
[onChange]
|
|
1890
|
+
[picked, search, onChange]
|
|
1707
1891
|
);
|
|
1708
|
-
const
|
|
1709
|
-
(optionValue) => {
|
|
1710
|
-
const opt = options.find((o) => o.value === optionValue);
|
|
1711
|
-
onChange(opt?.label ?? optionValue);
|
|
1712
|
-
setIsOpen(false);
|
|
1713
|
-
},
|
|
1714
|
-
[options, onChange]
|
|
1715
|
-
);
|
|
1716
|
-
const handleBlur = useCallback(() => {
|
|
1717
|
-
setTimeout(() => setIsOpen(false), CLOSE_DELAY_MS2);
|
|
1718
|
-
}, []);
|
|
1892
|
+
const handleKeyPress = useTypeaheadKeys({ rowCount: rows.length, isOpen, highlighted, setIsOpen, setHighlightIndex, close, pick });
|
|
1719
1893
|
const handleSubmit = useCallback(() => {
|
|
1720
|
-
|
|
1894
|
+
if (highlighted !== void 0) {
|
|
1895
|
+
pick(highlighted);
|
|
1896
|
+
return;
|
|
1897
|
+
}
|
|
1898
|
+
close();
|
|
1721
1899
|
onSubmit?.();
|
|
1722
|
-
}, [onSubmit]);
|
|
1900
|
+
}, [highlighted, pick, close, onSubmit]);
|
|
1901
|
+
return { rows, statusText, isOpen, picked, highlighted, open, close, selectValue, handleChange, handleKeyPress, handleSubmit };
|
|
1902
|
+
}
|
|
1903
|
+
function useTypeaheadKeys(input) {
|
|
1904
|
+
const { rowCount, isOpen, highlighted, setIsOpen, setHighlightIndex, close, pick } = input;
|
|
1905
|
+
return useCallback(
|
|
1906
|
+
(event) => {
|
|
1907
|
+
const { key } = event.nativeEvent;
|
|
1908
|
+
if (key === "ArrowDown" || key === "ArrowUp") {
|
|
1909
|
+
event.preventDefault();
|
|
1910
|
+
setIsOpen(true);
|
|
1911
|
+
setHighlightIndex((current) => nextHighlight(current, rowCount, key === "ArrowDown" ? FORWARD : BACKWARD));
|
|
1912
|
+
} else if (key === "Escape" && isOpen) {
|
|
1913
|
+
event.preventDefault();
|
|
1914
|
+
close();
|
|
1915
|
+
} else if (key === "Enter" && highlighted !== void 0) {
|
|
1916
|
+
event.preventDefault();
|
|
1917
|
+
pick(highlighted);
|
|
1918
|
+
}
|
|
1919
|
+
},
|
|
1920
|
+
[rowCount, isOpen, highlighted, setIsOpen, setHighlightIndex, close, pick]
|
|
1921
|
+
);
|
|
1922
|
+
}
|
|
1923
|
+
var CLOSE_DELAY_MS2 = 140;
|
|
1924
|
+
var DEFAULT_TYPEAHEAD_MIN_CHARS = 1;
|
|
1925
|
+
var DEFAULT_TYPEAHEAD_MAX_SUGGESTIONS = 8;
|
|
1926
|
+
function comboboxAria(testID, isExpanded, highlighted) {
|
|
1927
|
+
return {
|
|
1928
|
+
role: "combobox",
|
|
1929
|
+
"aria-autocomplete": "list",
|
|
1930
|
+
"aria-expanded": isExpanded,
|
|
1931
|
+
"aria-controls": isExpanded ? listboxDomId(testID) : void 0,
|
|
1932
|
+
"aria-activedescendant": highlighted !== void 0 ? optionDomId(testID, highlighted.value) : void 0
|
|
1933
|
+
};
|
|
1934
|
+
}
|
|
1935
|
+
function TypeaheadControlImpl(props, ref) {
|
|
1936
|
+
const { value, onChange, onSubmit, placeholder, accessibilityLabel, accessibilityHint, optionHint = "", error, minChars = DEFAULT_TYPEAHEAD_MIN_CHARS, style, testID } = props;
|
|
1937
|
+
const { id, describedById } = props;
|
|
1938
|
+
const search = "search" in props ? props.search : void 0;
|
|
1939
|
+
const options = "options" in props ? props.options : void 0;
|
|
1940
|
+
const maxSuggestions = ("search" in props ? props.search.maxResults : props.maxSuggestions) ?? DEFAULT_TYPEAHEAD_MAX_SUGGESTIONS;
|
|
1941
|
+
const { theme } = useUi();
|
|
1942
|
+
const { colors, palette } = theme;
|
|
1943
|
+
const anchorRef = useRef(null);
|
|
1944
|
+
const state = useTypeaheadState({ options, search, value, minChars, maxSuggestions, onChange, onSubmit });
|
|
1945
|
+
const showMenu = state.isOpen && (state.rows.length > 0 || state.statusText !== void 0);
|
|
1946
|
+
const isExpanded = state.isOpen && state.rows.length > 0;
|
|
1723
1947
|
const hasError = error !== void 0 && error !== "";
|
|
1948
|
+
useKeepAnchorInRoom(anchorRef, search?.scrollMarginTop ?? 0, search !== void 0 && state.isOpen);
|
|
1724
1949
|
return /* @__PURE__ */ jsxs(View, { ref: anchorRef, style: [controlStyles.anchor, style], children: [
|
|
1725
1950
|
/* @__PURE__ */ jsx(
|
|
1726
1951
|
TextInput,
|
|
1727
1952
|
{
|
|
1953
|
+
ref,
|
|
1954
|
+
id,
|
|
1955
|
+
...comboboxAria(testID, isExpanded, state.highlighted),
|
|
1956
|
+
...webFieldA11y({ describedById }),
|
|
1728
1957
|
accessibilityLabel,
|
|
1729
1958
|
accessibilityHint,
|
|
1730
1959
|
autoCapitalize: "none",
|
|
1960
|
+
autoComplete: "off",
|
|
1731
1961
|
autoCorrect: false,
|
|
1962
|
+
blurOnSubmit: search === void 0,
|
|
1732
1963
|
placeholder,
|
|
1733
1964
|
placeholderTextColor: colors.textSecondary,
|
|
1734
1965
|
spellCheck: false,
|
|
1735
1966
|
value,
|
|
1736
|
-
onChangeText: handleChange,
|
|
1737
|
-
onFocus:
|
|
1738
|
-
onBlur:
|
|
1739
|
-
|
|
1967
|
+
onChangeText: state.handleChange,
|
|
1968
|
+
onFocus: state.open,
|
|
1969
|
+
onBlur: () => setTimeout(state.close, CLOSE_DELAY_MS2),
|
|
1970
|
+
onKeyPress: state.handleKeyPress,
|
|
1971
|
+
onSubmitEditing: state.handleSubmit,
|
|
1740
1972
|
style: [controlStyles.input, { borderColor: hasError ? fieldErrorInk(theme) : colors.border, backgroundColor: colors.surface, color: colors.text }],
|
|
1741
|
-
testID: `${testID}-input`
|
|
1973
|
+
testID: search?.inputTestID ?? `${testID}-input`
|
|
1742
1974
|
}
|
|
1743
1975
|
),
|
|
1744
1976
|
showMenu ? /* @__PURE__ */ jsx(
|
|
1745
1977
|
AnchoredMenu,
|
|
1746
1978
|
{
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1979
|
+
accessibilityLabel,
|
|
1980
|
+
options: state.rows,
|
|
1981
|
+
selectedValue: search !== void 0 ? state.picked?.value ?? "" : value,
|
|
1982
|
+
onSelect: state.selectValue,
|
|
1983
|
+
onDismiss: state.close,
|
|
1984
|
+
colors: { text: colors.text, textSecondary: colors.textSecondary, border: colors.border, surface: colors.surface, brand: palette.primary["500"] },
|
|
1752
1985
|
optionHint,
|
|
1753
1986
|
testID,
|
|
1754
1987
|
anchorRef,
|
|
1988
|
+
listbox: { highlightedValue: state.highlighted?.value ?? "", statusText: state.statusText },
|
|
1755
1989
|
usePortal: true
|
|
1756
1990
|
}
|
|
1757
1991
|
) : null,
|
|
1758
1992
|
hasError ? /* @__PURE__ */ jsx(Text, { role: "alert", style: [controlStyles.error, { color: fieldErrorInk(theme) }], testID: `${testID}-error`, children: error }) : null
|
|
1759
1993
|
] });
|
|
1760
1994
|
}
|
|
1995
|
+
var TypeaheadControl = forwardRef(TypeaheadControlImpl);
|
|
1761
1996
|
var WEB_DATE_PROPS = typeof document !== "undefined" ? { type: "date" } : {};
|
|
1762
1997
|
function DateInput(p) {
|
|
1763
1998
|
return /* @__PURE__ */ jsxs(View, { style: controlStyles.dateCol, children: [
|
|
@@ -1854,7 +2089,210 @@ function toggleGroupSelection(selected, groupKeys, order) {
|
|
|
1854
2089
|
});
|
|
1855
2090
|
return order === void 0 ? merged : order.filter((key) => merged.includes(key));
|
|
1856
2091
|
}
|
|
2092
|
+
var ROW_GAP = 4;
|
|
2093
|
+
var TAB_PADDING = 4;
|
|
2094
|
+
var INDICATOR_WIDTH = 2;
|
|
2095
|
+
var TAB_FONT_SIZE = 12;
|
|
2096
|
+
var styles11 = StyleSheet.create({
|
|
2097
|
+
row: { flexDirection: "row", flexWrap: "nowrap", gap: ROW_GAP },
|
|
2098
|
+
tab: {
|
|
2099
|
+
borderBottomWidth: INDICATOR_WIDTH,
|
|
2100
|
+
flexBasis: 0,
|
|
2101
|
+
flexGrow: 1,
|
|
2102
|
+
flexShrink: 1,
|
|
2103
|
+
justifyContent: "center",
|
|
2104
|
+
minHeight: MIN_TOUCH_TARGET_PX,
|
|
2105
|
+
minWidth: 0,
|
|
2106
|
+
paddingHorizontal: TAB_PADDING
|
|
2107
|
+
},
|
|
2108
|
+
text: { fontSize: TAB_FONT_SIZE, textAlign: "center" },
|
|
2109
|
+
textSelected: { fontWeight: "700" }
|
|
2110
|
+
});
|
|
2111
|
+
var StepperTab = ({
|
|
2112
|
+
step,
|
|
2113
|
+
selected,
|
|
2114
|
+
hint,
|
|
2115
|
+
onStep,
|
|
2116
|
+
testID
|
|
2117
|
+
}) => {
|
|
2118
|
+
const { theme } = useUi();
|
|
2119
|
+
const ring = useFocusRing();
|
|
2120
|
+
const indicator = selected ? theme.palette.primary["500"] : theme.colors.border;
|
|
2121
|
+
const webKeyProps = {
|
|
2122
|
+
onKeyDown: (event) => {
|
|
2123
|
+
if (event.key !== " ") return;
|
|
2124
|
+
event.preventDefault?.();
|
|
2125
|
+
onStep(step.key);
|
|
2126
|
+
}
|
|
2127
|
+
};
|
|
2128
|
+
return /* @__PURE__ */ jsx(
|
|
2129
|
+
Pressable,
|
|
2130
|
+
{
|
|
2131
|
+
accessibilityHint: hint,
|
|
2132
|
+
accessibilityLabel: step.label,
|
|
2133
|
+
accessibilityRole: "tab",
|
|
2134
|
+
accessibilityState: { selected },
|
|
2135
|
+
"aria-selected": selected,
|
|
2136
|
+
style: [styles11.tab, { borderBottomColor: indicator }, ring.ringStyle],
|
|
2137
|
+
testID,
|
|
2138
|
+
onBlur: ring.onBlur,
|
|
2139
|
+
onFocus: ring.onFocus,
|
|
2140
|
+
onPress: () => onStep(step.key),
|
|
2141
|
+
...webKeyProps,
|
|
2142
|
+
children: /* @__PURE__ */ jsx(Text, { style: [styles11.text, { color: theme.colors.text }, selected ? styles11.textSelected : void 0], children: step.label })
|
|
2143
|
+
}
|
|
2144
|
+
);
|
|
2145
|
+
};
|
|
2146
|
+
var StepperTabs = ({
|
|
2147
|
+
steps,
|
|
2148
|
+
current,
|
|
2149
|
+
onStep,
|
|
2150
|
+
stepHint,
|
|
2151
|
+
testID
|
|
2152
|
+
}) => /* @__PURE__ */ jsx(View, { accessibilityRole: "tablist", style: styles11.row, testID, children: steps.map((step) => /* @__PURE__ */ jsx(
|
|
2153
|
+
StepperTab,
|
|
2154
|
+
{
|
|
2155
|
+
hint: stepHint,
|
|
2156
|
+
selected: step.key === current,
|
|
2157
|
+
step,
|
|
2158
|
+
testID: `${testID}-${step.key}`,
|
|
2159
|
+
onStep
|
|
2160
|
+
},
|
|
2161
|
+
step.key
|
|
2162
|
+
)) });
|
|
2163
|
+
|
|
2164
|
+
// src/Stepper/stepperModel.ts
|
|
2165
|
+
function resolveStepNeighbours(steps, current) {
|
|
2166
|
+
const index = steps.findIndex((step) => step.key === current);
|
|
2167
|
+
if (index < 0) return { previous: null, next: null };
|
|
2168
|
+
return { previous: steps[index - 1] ?? null, next: steps[index + 1] ?? null };
|
|
2169
|
+
}
|
|
2170
|
+
var ROW_GAP2 = 8;
|
|
2171
|
+
var styles12 = StyleSheet.create({
|
|
2172
|
+
cell: { flex: 1, minWidth: 0 },
|
|
2173
|
+
row: { flexDirection: "row", gap: ROW_GAP2 }
|
|
2174
|
+
});
|
|
2175
|
+
var StepperNav = ({
|
|
2176
|
+
steps,
|
|
2177
|
+
current,
|
|
2178
|
+
onStep,
|
|
2179
|
+
labels,
|
|
2180
|
+
testID
|
|
2181
|
+
}) => {
|
|
2182
|
+
const { previous, next } = resolveStepNeighbours(steps, current);
|
|
2183
|
+
return /* @__PURE__ */ jsxs(View, { style: styles12.row, testID, children: [
|
|
2184
|
+
/* @__PURE__ */ jsx(View, { style: styles12.cell, children: /* @__PURE__ */ jsx(
|
|
2185
|
+
Button,
|
|
2186
|
+
{
|
|
2187
|
+
fullWidth: true,
|
|
2188
|
+
accessibilityHint: labels.backHint,
|
|
2189
|
+
accessibilityLabel: labels.back,
|
|
2190
|
+
autoLoading: false,
|
|
2191
|
+
disabled: previous === null,
|
|
2192
|
+
label: labels.back,
|
|
2193
|
+
testID: `${testID}-back`,
|
|
2194
|
+
variant: "outline",
|
|
2195
|
+
onPress: () => {
|
|
2196
|
+
if (previous !== null) onStep(previous.key);
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2199
|
+
) }),
|
|
2200
|
+
next === null ? null : /* @__PURE__ */ jsx(View, { style: styles12.cell, children: /* @__PURE__ */ jsx(
|
|
2201
|
+
Button,
|
|
2202
|
+
{
|
|
2203
|
+
fullWidth: true,
|
|
2204
|
+
accessibilityHint: labels.nextHint,
|
|
2205
|
+
accessibilityLabel: labels.next(next),
|
|
2206
|
+
autoLoading: false,
|
|
2207
|
+
label: labels.next(next),
|
|
2208
|
+
testID: `${testID}-next`,
|
|
2209
|
+
onPress: () => onStep(next.key)
|
|
2210
|
+
}
|
|
2211
|
+
) })
|
|
2212
|
+
] });
|
|
2213
|
+
};
|
|
2214
|
+
var STATUS_FONT = 16;
|
|
2215
|
+
var styles13 = StyleSheet.create({
|
|
2216
|
+
line: { fontSize: STATUS_FONT }
|
|
2217
|
+
});
|
|
2218
|
+
function FormStatusLine({ message, testID, style }) {
|
|
2219
|
+
const { theme } = useUi();
|
|
2220
|
+
if (message === null || message === void 0 || message === "") return null;
|
|
2221
|
+
return /* @__PURE__ */ jsx(Text, { role: "alert", style: [styles13.line, { color: theme.colors.text }, style], testID, children: message });
|
|
2222
|
+
}
|
|
2223
|
+
function useFocusFirstInvalid(refs) {
|
|
2224
|
+
const latest = useRef(refs);
|
|
2225
|
+
latest.current = refs;
|
|
2226
|
+
return useCallback((invalid) => {
|
|
2227
|
+
const first = invalid.map((field) => latest.current[field].current).find((node) => node !== null);
|
|
2228
|
+
first?.focus();
|
|
2229
|
+
}, []);
|
|
2230
|
+
}
|
|
2231
|
+
var DEFAULT_PREVIEW_PX = 48;
|
|
2232
|
+
var PREVIEW_RADIUS = 8;
|
|
2233
|
+
var GAP = 8;
|
|
2234
|
+
var TITLE_FONT_SIZE = 14;
|
|
2235
|
+
var HELP_FONT_SIZE = 13;
|
|
2236
|
+
var styles14 = StyleSheet.create({
|
|
2237
|
+
help: { flex: 1, fontSize: HELP_FONT_SIZE },
|
|
2238
|
+
root: { gap: GAP },
|
|
2239
|
+
tile: { alignItems: "center", flexDirection: "row", gap: GAP },
|
|
2240
|
+
title: { fontSize: TITLE_FONT_SIZE, fontWeight: "700" },
|
|
2241
|
+
toggle: { alignSelf: "flex-start", justifyContent: "center", minHeight: MIN_TOUCH_TARGET_PX },
|
|
2242
|
+
toggleText: { fontSize: TITLE_FONT_SIZE, fontWeight: "700", textDecorationLine: "underline" }
|
|
2243
|
+
});
|
|
2244
|
+
var UploadWithLinkField = ({
|
|
2245
|
+
value,
|
|
2246
|
+
onChange,
|
|
2247
|
+
labels,
|
|
2248
|
+
uploadControl,
|
|
2249
|
+
testID,
|
|
2250
|
+
disabled = false,
|
|
2251
|
+
previewSize = DEFAULT_PREVIEW_PX
|
|
2252
|
+
}) => {
|
|
2253
|
+
const { theme } = useUi();
|
|
2254
|
+
const ring = useFocusRing();
|
|
2255
|
+
const url = value ?? "";
|
|
2256
|
+
const [pasting, setPasting] = useState(url !== "");
|
|
2257
|
+
const previewBox = { borderRadius: PREVIEW_RADIUS, height: previewSize, width: previewSize };
|
|
2258
|
+
return /* @__PURE__ */ jsxs(View, { style: styles14.root, children: [
|
|
2259
|
+
/* @__PURE__ */ jsx(Text, { style: [styles14.title, { color: theme.colors.text }], children: labels.title }),
|
|
2260
|
+
/* @__PURE__ */ jsxs(View, { style: styles14.tile, children: [
|
|
2261
|
+
url === "" ? /* @__PURE__ */ jsx(View, { style: [previewBox, { backgroundColor: theme.colors.border }] }) : /* @__PURE__ */ jsx(Image, { accessible: false, source: { uri: url }, style: previewBox, testID: `${testID}-preview` }),
|
|
2262
|
+
labels.help === void 0 ? null : /* @__PURE__ */ jsx(Text, { style: [styles14.help, { color: theme.colors.text }], children: labels.help })
|
|
2263
|
+
] }),
|
|
2264
|
+
uploadControl,
|
|
2265
|
+
/* @__PURE__ */ jsx(
|
|
2266
|
+
Pressable,
|
|
2267
|
+
{
|
|
2268
|
+
accessibilityHint: labels.pasteToggleHint,
|
|
2269
|
+
accessibilityLabel: labels.pasteToggle,
|
|
2270
|
+
accessibilityRole: "button",
|
|
2271
|
+
accessibilityState: { expanded: pasting },
|
|
2272
|
+
"aria-expanded": pasting,
|
|
2273
|
+
style: [styles14.toggle, ring.ringStyle],
|
|
2274
|
+
testID: `${testID}-paste`,
|
|
2275
|
+
onBlur: ring.onBlur,
|
|
2276
|
+
onFocus: ring.onFocus,
|
|
2277
|
+
onPress: () => setPasting(!pasting),
|
|
2278
|
+
children: /* @__PURE__ */ jsx(Text, { style: [styles14.toggleText, { color: theme.colors.text }], children: labels.pasteToggle })
|
|
2279
|
+
}
|
|
2280
|
+
),
|
|
2281
|
+
pasting ? /* @__PURE__ */ jsx(
|
|
2282
|
+
FormField,
|
|
2283
|
+
{
|
|
2284
|
+
accessibilityHint: labels.linkHint,
|
|
2285
|
+
editable: !disabled,
|
|
2286
|
+
label: labels.link,
|
|
2287
|
+
placeholder: labels.linkPlaceholder,
|
|
2288
|
+
testID,
|
|
2289
|
+
value: url,
|
|
2290
|
+
onChangeText: onChange
|
|
2291
|
+
}
|
|
2292
|
+
) : null
|
|
2293
|
+
] });
|
|
2294
|
+
};
|
|
1857
2295
|
|
|
1858
|
-
export { AlignToControl, AnchoredMenu, ChipSelector, DEFAULT_MAX_RECENTS, DEFAULT_OPTIONAL_LABEL, DEFAULT_TYPEAHEAD_MAX_SUGGESTIONS, DEFAULT_TYPEAHEAD_MIN_CHARS, DateRangeControl, Field, FormActions, FormCell, FormCheckbox, FormField, FormGrid, FormSection, FormSwitch, INLINE_FIELD_ROW_MIN_WIDTH, InlineFieldRow, SelectControl, ThemedTextInput, TypeaheadControl, controlStyles, groupAriaChecked, inlineFieldRowLayout, isUnmatched, resolveGroupSelection, suggestOptions, toggleGroupSelection, useRecentValues, useThemedInput };
|
|
2296
|
+
export { AlignToControl, AnchoredMenu, ChipSelector, DEFAULT_MAX_RECENTS, DEFAULT_OPTIONAL_LABEL, DEFAULT_TYPEAHEAD_MAX_SUGGESTIONS, DEFAULT_TYPEAHEAD_MIN_CHARS, DateRangeControl, Field, FormActions, FormCell, FormCheckbox, FormField, FormGrid, FormSection, FormStatusLine, FormSwitch, INLINE_FIELD_ROW_MIN_WIDTH, InlineFieldRow, SelectControl, StepperNav, StepperTabs, ThemedTextInput, TypeaheadControl, UploadWithLinkField, controlStyles, groupAriaChecked, inlineFieldRowLayout, isUnmatched, resolveGroupSelection, resolveStepNeighbours, suggestOptions, toggleGroupSelection, useFocusFirstInvalid, useRecentValues, useThemedInput };
|
|
1859
2297
|
//# sourceMappingURL=index.mjs.map
|
|
1860
2298
|
//# sourceMappingURL=index.mjs.map
|