@nativetail/ui 0.2.4 → 0.2.6
Sign up to get free protection for your applications and to get access to all the features.
package/package.json
CHANGED
@@ -2,7 +2,7 @@ import { cn, Text, useTw, View } from "@nativetail/core";
|
|
2
2
|
import { Pressable } from "react-native";
|
3
3
|
import { Button, ButtonProps } from "../button";
|
4
4
|
|
5
|
-
type CardProps = {
|
5
|
+
export type CardProps = {
|
6
6
|
renderHeader?: () => React.ReactNode;
|
7
7
|
title?: string;
|
8
8
|
subtitle?: string;
|
@@ -37,7 +37,7 @@ type DropdownState = {
|
|
37
37
|
toggle: () => void;
|
38
38
|
close: () => void;
|
39
39
|
open: () => void;
|
40
|
-
position: PositionType | null
|
40
|
+
position: React.MutableRefObject<PositionType | null>;
|
41
41
|
setPosition: (position: PositionType | null) => void;
|
42
42
|
};
|
43
43
|
const DropdownContext = React.createContext<DropdownState | null>(null);
|
@@ -57,7 +57,7 @@ const DropdownRoot = ({
|
|
57
57
|
children: ReactNode;
|
58
58
|
}) => {
|
59
59
|
const [open, setOpen] = useState(false);
|
60
|
-
const
|
60
|
+
const position = useRef<PositionType | null>(null);
|
61
61
|
return (
|
62
62
|
<DropdownContext.Provider
|
63
63
|
value={{
|
@@ -66,7 +66,9 @@ const DropdownRoot = ({
|
|
66
66
|
close: () => setOpen(false),
|
67
67
|
open: () => setOpen(true),
|
68
68
|
position,
|
69
|
-
setPosition
|
69
|
+
setPosition: (pos) => {
|
70
|
+
position.current = pos;
|
71
|
+
},
|
70
72
|
}}
|
71
73
|
>
|
72
74
|
<View className={className} animated>
|
@@ -118,6 +120,11 @@ const DropdownTrigger = ({
|
|
118
120
|
}
|
119
121
|
toggle();
|
120
122
|
}, [toggle, _measure]);
|
123
|
+
|
124
|
+
useEffect(() => {
|
125
|
+
_measure();
|
126
|
+
}, [_measure]);
|
127
|
+
|
121
128
|
return (
|
122
129
|
<Pressable
|
123
130
|
className={className}
|
@@ -141,28 +148,57 @@ const DropdownMenu = ({
|
|
141
148
|
useBlur?: boolean;
|
142
149
|
}) => {
|
143
150
|
const { isOpen, close } = useDropdownContext();
|
144
|
-
const position = useDropdownContext().position;
|
151
|
+
const position = useDropdownContext().position.current;
|
152
|
+
|
153
|
+
const [modalOpen, setModalOpen] = useState(isOpen);
|
154
|
+
const [layout, setLayout] = useState<PositionType>({
|
155
|
+
bottom: 0,
|
156
|
+
height: 0,
|
157
|
+
left: 0,
|
158
|
+
right: 0,
|
159
|
+
top: 0,
|
160
|
+
width: 0,
|
161
|
+
});
|
162
|
+
const itemRef = useRef<NativeView>(null);
|
163
|
+
const screen = useWindowDimensions();
|
164
|
+
const tw = useTw();
|
145
165
|
const left = position?.left || 0;
|
146
166
|
const top = position?.top || 0;
|
147
167
|
const menuX = left;
|
148
|
-
const menuY = top;
|
149
168
|
const width = position?.width || 0;
|
150
|
-
const screen = useWindowDimensions();
|
151
|
-
const tw = useTw();
|
152
169
|
const style = tw`${className}`;
|
153
170
|
const styleWidth = !isNaN(Number(style?.width)) ? Number(style?.width) : 0;
|
154
171
|
const menuWidth = styleWidth || width || 0;
|
155
|
-
const
|
172
|
+
const isEndOfXScreen = screen.width - menuX < menuWidth;
|
173
|
+
const isEndOfYScreen = top + layout.height > screen.height;
|
156
174
|
const menuStyle: ViewStyle = {
|
157
|
-
top: menuY,
|
158
175
|
left: menuX,
|
159
176
|
transformOrigin: "top left",
|
160
177
|
};
|
161
|
-
|
178
|
+
menuStyle.top = top;
|
179
|
+
|
180
|
+
if (isEndOfXScreen) {
|
162
181
|
menuStyle.left = menuX - menuWidth + width;
|
163
182
|
menuStyle.transformOrigin = "top right";
|
164
183
|
}
|
165
|
-
|
184
|
+
if (isEndOfYScreen) {
|
185
|
+
menuStyle.top = top - layout.height - position.height;
|
186
|
+
menuStyle.transformOrigin = "bottom left";
|
187
|
+
}
|
188
|
+
const measureLayout = useCallback(() => {
|
189
|
+
if (itemRef.current) {
|
190
|
+
itemRef.current.measure((x, y, width, height, pageX, pageY) => {
|
191
|
+
setLayout({
|
192
|
+
width,
|
193
|
+
height,
|
194
|
+
top: pageY,
|
195
|
+
left: pageX,
|
196
|
+
right: screen.width - pageX - width,
|
197
|
+
bottom: screen.height - pageY - height,
|
198
|
+
});
|
199
|
+
});
|
200
|
+
}
|
201
|
+
}, []);
|
166
202
|
|
167
203
|
useEffect(() => {
|
168
204
|
if (isOpen) {
|
@@ -205,6 +241,7 @@ const DropdownMenu = ({
|
|
205
241
|
<AnimatePresence exitBeforeEnter>
|
206
242
|
{isOpen && (
|
207
243
|
<View
|
244
|
+
ref={itemRef}
|
208
245
|
className={mergeClasses(
|
209
246
|
"absolute in:scale-0 scale-100 out:scale-0 overflow-hidden z-10 bg-card/95 rounded-xl border border-muted/15",
|
210
247
|
width ? `w-[${width}px]` : "",
|
@@ -212,6 +249,7 @@ const DropdownMenu = ({
|
|
212
249
|
)}
|
213
250
|
onDidAnimate={onDidAnimate}
|
214
251
|
style={menuStyle}
|
252
|
+
onLayout={measureLayout}
|
215
253
|
animated
|
216
254
|
print
|
217
255
|
>
|