@dloizides/ui-forms 1.12.0 → 1.13.2
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/dist/index.d.mts +20 -9
- package/dist/index.d.ts +20 -9
- package/dist/index.js +78 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +80 -10
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import React2, { useState, useCallback, useMemo, useRef, useEffect } from 'react';
|
|
2
|
-
import { Platform, StyleSheet, TextInput, View, Text, Switch, Pressable, TouchableOpacity } from 'react-native';
|
|
1
|
+
import React2, { useState, useCallback, useMemo, useRef, useEffect, useLayoutEffect } from 'react';
|
|
2
|
+
import { Platform, StyleSheet, TextInput, View, Text, Switch, Pressable, ScrollView, 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
6
|
import { MIN_TOUCH_TARGET_PX } from '@dloizides/a11y';
|
|
7
|
+
import { createPortal } from 'react-dom';
|
|
7
8
|
|
|
8
9
|
// src/Field/Field.tsx
|
|
9
10
|
function attachControlId(child, candidateId, describedById) {
|
|
@@ -1001,13 +1002,76 @@ var FormCheckbox = ({
|
|
|
1001
1002
|
}
|
|
1002
1003
|
);
|
|
1003
1004
|
};
|
|
1004
|
-
var IS_WEB5 =
|
|
1005
|
+
var IS_WEB5 = Platform.OS === "web";
|
|
1006
|
+
var MENU_PORTAL_Z_INDEX = 1e3;
|
|
1007
|
+
var MENU_TOP_GAP2 = 4;
|
|
1008
|
+
function toDomNode(ref) {
|
|
1009
|
+
const node = ref.current;
|
|
1010
|
+
if (node === null || typeof node.getBoundingClientRect !== "function") return null;
|
|
1011
|
+
return node;
|
|
1012
|
+
}
|
|
1013
|
+
function readAnchorRect(ref) {
|
|
1014
|
+
if (!IS_WEB5) return null;
|
|
1015
|
+
const node = toDomNode(ref);
|
|
1016
|
+
if (node === null) return null;
|
|
1017
|
+
const r = node.getBoundingClientRect();
|
|
1018
|
+
return { top: r.top, left: r.left, width: r.width, bottom: r.bottom };
|
|
1019
|
+
}
|
|
1020
|
+
function buildPortalPopoverStyle(rect) {
|
|
1021
|
+
return {
|
|
1022
|
+
// RN's ViewStyle union omits 'fixed', but react-native-web honours it at runtime.
|
|
1023
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- web-only position value
|
|
1024
|
+
position: "fixed",
|
|
1025
|
+
top: rect.bottom + MENU_TOP_GAP2,
|
|
1026
|
+
left: rect.left,
|
|
1027
|
+
width: rect.width,
|
|
1028
|
+
zIndex: MENU_PORTAL_Z_INDEX
|
|
1029
|
+
};
|
|
1030
|
+
}
|
|
1031
|
+
function useAnchorRect(ref, enabled) {
|
|
1032
|
+
const [rect, setRect] = useState(null);
|
|
1033
|
+
useLayoutEffect(() => {
|
|
1034
|
+
if (!IS_WEB5 || !enabled) {
|
|
1035
|
+
setRect(null);
|
|
1036
|
+
return void 0;
|
|
1037
|
+
}
|
|
1038
|
+
let frame = null;
|
|
1039
|
+
let disposed = false;
|
|
1040
|
+
const apply = () => {
|
|
1041
|
+
frame = null;
|
|
1042
|
+
if (disposed) return;
|
|
1043
|
+
setRect(readAnchorRect(ref));
|
|
1044
|
+
};
|
|
1045
|
+
const schedule = () => {
|
|
1046
|
+
if (frame !== null) return;
|
|
1047
|
+
frame = window.requestAnimationFrame(apply);
|
|
1048
|
+
};
|
|
1049
|
+
apply();
|
|
1050
|
+
document.addEventListener("scroll", schedule, true);
|
|
1051
|
+
window.addEventListener("resize", schedule);
|
|
1052
|
+
const node = toDomNode(ref);
|
|
1053
|
+
const observer = typeof ResizeObserver === "function" ? new ResizeObserver(schedule) : null;
|
|
1054
|
+
if (observer !== null) {
|
|
1055
|
+
if (node !== null) observer.observe(node);
|
|
1056
|
+
observer.observe(document.body);
|
|
1057
|
+
}
|
|
1058
|
+
return () => {
|
|
1059
|
+
disposed = true;
|
|
1060
|
+
if (frame !== null) window.cancelAnimationFrame(frame);
|
|
1061
|
+
document.removeEventListener("scroll", schedule, true);
|
|
1062
|
+
window.removeEventListener("resize", schedule);
|
|
1063
|
+
if (observer !== null) observer.disconnect();
|
|
1064
|
+
};
|
|
1065
|
+
}, [ref, enabled]);
|
|
1066
|
+
return IS_WEB5 && enabled ? rect : null;
|
|
1067
|
+
}
|
|
1068
|
+
var IS_WEB6 = typeof document !== "undefined";
|
|
1005
1069
|
var ESCAPE_KEY = "Escape";
|
|
1006
1070
|
var ACTIVE_WEIGHT = "700";
|
|
1007
1071
|
var IDLE_WEIGHT = "400";
|
|
1008
1072
|
function useDismiss(anchorRef, menuRef, onDismiss) {
|
|
1009
1073
|
useEffect(() => {
|
|
1010
|
-
if (!
|
|
1074
|
+
if (!IS_WEB6) return void 0;
|
|
1011
1075
|
const onMouseDown = (event) => {
|
|
1012
1076
|
const anchorNode = anchorRef.current;
|
|
1013
1077
|
const menuNode = menuRef.current;
|
|
@@ -1035,18 +1099,21 @@ function AnchoredMenu({
|
|
|
1035
1099
|
colors,
|
|
1036
1100
|
optionHint,
|
|
1037
1101
|
testID,
|
|
1038
|
-
anchorRef
|
|
1102
|
+
anchorRef,
|
|
1103
|
+
usePortal = false
|
|
1039
1104
|
}) {
|
|
1040
1105
|
const menuRef = React2.useRef(null);
|
|
1041
1106
|
useDismiss(anchorRef, menuRef, onDismiss);
|
|
1042
|
-
|
|
1107
|
+
const rect = useAnchorRect(anchorRef, usePortal);
|
|
1108
|
+
const portalStyle = rect !== null ? buildPortalPopoverStyle(rect) : null;
|
|
1109
|
+
const menu = /* @__PURE__ */ jsx(
|
|
1043
1110
|
View,
|
|
1044
1111
|
{
|
|
1045
1112
|
ref: menuRef,
|
|
1046
1113
|
accessibilityRole: "menu",
|
|
1047
|
-
style: [controlStyles.menu, { borderColor: colors.border, backgroundColor: colors.surface }],
|
|
1114
|
+
style: [controlStyles.menu, { borderColor: colors.border, backgroundColor: colors.surface }, portalStyle],
|
|
1048
1115
|
testID: `${testID}-menu`,
|
|
1049
|
-
children: options.map((opt) => {
|
|
1116
|
+
children: /* @__PURE__ */ jsx(ScrollView, { keyboardShouldPersistTaps: "handled", nestedScrollEnabled: true, children: options.map((opt) => {
|
|
1050
1117
|
const active = opt.value === selectedValue;
|
|
1051
1118
|
return /* @__PURE__ */ jsx(
|
|
1052
1119
|
Pressable,
|
|
@@ -1063,9 +1130,11 @@ function AnchoredMenu({
|
|
|
1063
1130
|
},
|
|
1064
1131
|
opt.value
|
|
1065
1132
|
);
|
|
1066
|
-
})
|
|
1133
|
+
}) })
|
|
1067
1134
|
}
|
|
1068
1135
|
);
|
|
1136
|
+
if (usePortal && IS_WEB6) return createPortal(menu, document.body);
|
|
1137
|
+
return menu;
|
|
1069
1138
|
}
|
|
1070
1139
|
var CHEVRON_DOWN = "\u25BE";
|
|
1071
1140
|
var CHEVRON_UP = "\u25B4";
|
|
@@ -1249,7 +1318,8 @@ function TypeaheadControl({
|
|
|
1249
1318
|
colors: { text: colors.text, border: colors.border, surface: colors.surface, brand: palette.primary["500"] },
|
|
1250
1319
|
optionHint,
|
|
1251
1320
|
testID,
|
|
1252
|
-
anchorRef
|
|
1321
|
+
anchorRef,
|
|
1322
|
+
usePortal: true
|
|
1253
1323
|
}
|
|
1254
1324
|
) : null,
|
|
1255
1325
|
hasError ? /* @__PURE__ */ jsx(Text, { role: "alert", style: [controlStyles.error, { color: semantic.error["500"] }], testID: `${testID}-error`, children: error }) : null
|