@korsolutions/ui 0.0.20 → 0.0.21
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/components/index.d.mts +33 -2
- package/dist/components/index.mjs +41 -4
- package/dist/hooks/index.d.mts +32 -2
- package/dist/hooks/index.mjs +79 -2
- package/dist/{index-CGY0mO6z.d.mts → index-pCM7YTs1.d.mts} +1 -8
- package/dist/index.mjs +3 -2
- package/dist/primitives/index.d.mts +2 -1
- package/dist/primitives/index.mjs +2 -1
- package/dist/{primitives-P_8clvQr.mjs → primitives-DNeYBN-3.mjs} +3 -105
- package/dist/{toast-manager-DSo9oN8w.mjs → toast-manager-BfoJ-_dB.mjs} +1 -1
- package/dist/use-numeric-mask-B9WZG25o.d.mts +33 -0
- package/dist/use-numeric-mask-BQlz1Pus.mjs +113 -0
- package/dist/use-relative-position-BTKEyT1F.mjs +106 -0
- package/dist/use-relative-position-DBzhrBU7.d.mts +61 -0
- package/package.json +1 -1
- package/src/components/index.ts +1 -1
- package/src/components/input/index.ts +2 -0
- package/src/components/input/numeric-input.tsx +73 -0
- package/src/hooks/index.ts +4 -1
- package/src/hooks/use-currency-mask.ts +141 -0
- package/src/hooks/use-numeric-mask.ts +202 -0
- package/src/primitives/dropdown-menu/context.ts +1 -1
- package/src/primitives/dropdown-menu/dropdown-menu-content.tsx +1 -1
- package/src/primitives/dropdown-menu/dropdown-menu-root.tsx +1 -1
- package/src/primitives/popover/context.ts +1 -1
- package/src/primitives/popover/popover-content.tsx +1 -1
- package/src/primitives/popover/popover-root.tsx +1 -1
- /package/src/hooks/{useRelativePosition.ts → use-relative-position.ts} +0 -0
- /package/src/hooks/{useScreenSize.ts → use-screen-size.ts} +0 -0
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { D as BadgeStyles, I as AvatarStyles, S as TextareaPrimitiveBaseProps, V as EmptyStyles, d as PopoverTriggerRef, dt as ButtonStyles, et as SelectRootBaseProps, gt as InputStyles, h as DropdownMenuStyles, j as ToastStyles, lt as ButtonPrimitiveRootProps, mt as InputPrimitiveBaseProps, nt as SelectStyles, q as CardStyles, s as PopoverStyles, w as TextareaStyles, yt as FieldStyles } from "../index-
|
|
1
|
+
import { D as BadgeStyles, I as AvatarStyles, S as TextareaPrimitiveBaseProps, V as EmptyStyles, d as PopoverTriggerRef, dt as ButtonStyles, et as SelectRootBaseProps, gt as InputStyles, h as DropdownMenuStyles, j as ToastStyles, lt as ButtonPrimitiveRootProps, mt as InputPrimitiveBaseProps, nt as SelectStyles, q as CardStyles, s as PopoverStyles, w as TextareaStyles, yt as FieldStyles } from "../index-pCM7YTs1.mjs";
|
|
2
|
+
import "../use-relative-position-DBzhrBU7.mjs";
|
|
3
|
+
import { t as NumericMaskFormat } from "../use-numeric-mask-B9WZG25o.mjs";
|
|
2
4
|
import React from "react";
|
|
3
5
|
import { ImageSource, PressableProps, TextProps, TextStyle } from "react-native";
|
|
4
6
|
|
|
@@ -49,6 +51,35 @@ interface InputProps extends InputPrimitiveBaseProps {
|
|
|
49
51
|
}
|
|
50
52
|
declare function Input(props: InputProps): React.JSX.Element;
|
|
51
53
|
//#endregion
|
|
54
|
+
//#region src/components/input/numeric-input.d.ts
|
|
55
|
+
interface NumericInputProps extends Omit<InputPrimitiveBaseProps, "value" | "onChange" | "keyboardType"> {
|
|
56
|
+
variant?: "default";
|
|
57
|
+
value?: number | null;
|
|
58
|
+
onChange?: (value: number | null) => void;
|
|
59
|
+
format?: NumericMaskFormat;
|
|
60
|
+
locale?: string;
|
|
61
|
+
currency?: string;
|
|
62
|
+
precision?: number;
|
|
63
|
+
min?: number;
|
|
64
|
+
max?: number;
|
|
65
|
+
allowNegative?: boolean;
|
|
66
|
+
}
|
|
67
|
+
declare function NumericInput({
|
|
68
|
+
value,
|
|
69
|
+
onChange,
|
|
70
|
+
format,
|
|
71
|
+
locale,
|
|
72
|
+
currency,
|
|
73
|
+
precision,
|
|
74
|
+
min,
|
|
75
|
+
max,
|
|
76
|
+
allowNegative,
|
|
77
|
+
variant,
|
|
78
|
+
onBlur,
|
|
79
|
+
onFocus,
|
|
80
|
+
...props
|
|
81
|
+
}: NumericInputProps): React.JSX.Element;
|
|
82
|
+
//#endregion
|
|
52
83
|
//#region src/components/field/variants/index.d.ts
|
|
53
84
|
declare const FieldVariants: {
|
|
54
85
|
default: () => FieldStyles;
|
|
@@ -262,4 +293,4 @@ interface PopoverProps {
|
|
|
262
293
|
}
|
|
263
294
|
declare const Popover: React.ForwardRefExoticComponent<PopoverProps & React.RefAttributes<PopoverTriggerRef>>;
|
|
264
295
|
//#endregion
|
|
265
|
-
export { Avatar, AvatarProps, Badge, Button, Card, DropdownMenu, Empty, EmptyProps, Field, FieldProps, Input, Link, LinkProps, Popover, PopoverProps, Select, SelectOption, SelectProps, Textarea, Toast, Typography, TypographyProps };
|
|
296
|
+
export { Avatar, AvatarProps, Badge, Button, Card, DropdownMenu, Empty, EmptyProps, Field, FieldProps, Input, Link, LinkProps, NumericInput, NumericInputProps, Popover, PopoverProps, Select, SelectOption, SelectProps, Textarea, Toast, Typography, TypographyProps };
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { i as useThemedStyles, r as ToastComponent, t as ToastAPI } from "../toast-manager-
|
|
2
|
-
import { a as BadgePrimitive, c as EmptyPrimitive, d as ButtonPrimitive, f as InputPrimitive, i as TextareaPrimitive, l as CardPrimitive, n as usePopover, p as FieldPrimitive, r as DropdownMenuPrimitive, s as AvatarPrimitive, t as PopoverPrimitive, u as SelectPrimitive } from "../primitives-
|
|
3
|
-
import
|
|
1
|
+
import { i as useThemedStyles, r as ToastComponent, t as ToastAPI } from "../toast-manager-BfoJ-_dB.mjs";
|
|
2
|
+
import { a as BadgePrimitive, c as EmptyPrimitive, d as ButtonPrimitive, f as InputPrimitive, i as TextareaPrimitive, l as CardPrimitive, n as usePopover, p as FieldPrimitive, r as DropdownMenuPrimitive, s as AvatarPrimitive, t as PopoverPrimitive, u as SelectPrimitive } from "../primitives-DNeYBN-3.mjs";
|
|
3
|
+
import "../use-relative-position-BTKEyT1F.mjs";
|
|
4
|
+
import { t as useNumericMask } from "../use-numeric-mask-BQlz1Pus.mjs";
|
|
5
|
+
import React, { forwardRef, useEffect, useState } from "react";
|
|
4
6
|
import { Linking, Text } from "react-native";
|
|
5
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
8
|
|
|
@@ -205,6 +207,41 @@ function Input(props) {
|
|
|
205
207
|
});
|
|
206
208
|
}
|
|
207
209
|
|
|
210
|
+
//#endregion
|
|
211
|
+
//#region src/components/input/numeric-input.tsx
|
|
212
|
+
function NumericInput({ value, onChange, format = "decimal", locale = "en-US", currency = "USD", precision = 2, min, max, allowNegative = true, variant = "default", onBlur, onFocus, ...props }) {
|
|
213
|
+
const numericMask = useNumericMask({
|
|
214
|
+
format,
|
|
215
|
+
locale,
|
|
216
|
+
currency,
|
|
217
|
+
precision,
|
|
218
|
+
min,
|
|
219
|
+
max,
|
|
220
|
+
allowNegative,
|
|
221
|
+
onChange
|
|
222
|
+
});
|
|
223
|
+
useEffect(() => {
|
|
224
|
+
if (value !== numericMask.numericValue) numericMask.setValue(value ?? null);
|
|
225
|
+
}, [value]);
|
|
226
|
+
const handleBlur = (e) => {
|
|
227
|
+
numericMask.onBlur();
|
|
228
|
+
onBlur?.(e);
|
|
229
|
+
};
|
|
230
|
+
const handleFocus = (e) => {
|
|
231
|
+
numericMask.onFocus();
|
|
232
|
+
onFocus?.(e);
|
|
233
|
+
};
|
|
234
|
+
return /* @__PURE__ */ jsx(Input, {
|
|
235
|
+
...props,
|
|
236
|
+
variant,
|
|
237
|
+
value: numericMask.value,
|
|
238
|
+
onChange: numericMask.onChangeText,
|
|
239
|
+
onBlur: handleBlur,
|
|
240
|
+
onFocus: handleFocus,
|
|
241
|
+
keyboardType: numericMask.keyboardType
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
|
|
208
245
|
//#endregion
|
|
209
246
|
//#region src/components/field/variants/default.tsx
|
|
210
247
|
const useFieldVariantDefault = () => {
|
|
@@ -790,4 +827,4 @@ PopoverComponent.displayName = "Popover";
|
|
|
790
827
|
const Popover = PopoverComponent;
|
|
791
828
|
|
|
792
829
|
//#endregion
|
|
793
|
-
export { Avatar, Badge, Button, Card, DropdownMenu, Empty, Field, Input, Link, Popover, Select, Textarea, Toast, Typography };
|
|
830
|
+
export { Avatar, Badge, Button, Card, DropdownMenu, Empty, Field, Input, Link, NumericInput, Popover, Select, Textarea, Toast, Typography };
|
package/dist/hooks/index.d.mts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
import { i as useRelativePosition, n as DEFAULT_POSITION, r as LayoutPosition, t as DEFAULT_LAYOUT } from "../use-relative-position-DBzhrBU7.mjs";
|
|
2
|
+
import { i as useNumericMask, n as UseNumericMaskOptions, r as UseNumericMaskReturn, t as NumericMaskFormat } from "../use-numeric-mask-B9WZG25o.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/hooks/use-screen-size.d.ts
|
|
2
5
|
type ScreenSize = "mobile" | "tablet" | "desktop";
|
|
3
6
|
interface Response {
|
|
4
7
|
readonly size: ScreenSize;
|
|
@@ -14,4 +17,31 @@ interface Response {
|
|
|
14
17
|
}
|
|
15
18
|
declare function useScreenSize(): Response;
|
|
16
19
|
//#endregion
|
|
17
|
-
|
|
20
|
+
//#region src/hooks/use-currency-mask.d.ts
|
|
21
|
+
interface UseCurrencyMaskOptions {
|
|
22
|
+
locale?: string;
|
|
23
|
+
currency?: string;
|
|
24
|
+
precision?: number;
|
|
25
|
+
min?: number;
|
|
26
|
+
max?: number;
|
|
27
|
+
onValueChange?: (value: number | null) => void;
|
|
28
|
+
}
|
|
29
|
+
interface UseCurrencyMaskReturn {
|
|
30
|
+
value: string;
|
|
31
|
+
numericValue: number | null;
|
|
32
|
+
onChangeText: (text: string) => void;
|
|
33
|
+
onBlur: () => void;
|
|
34
|
+
onFocus: () => void;
|
|
35
|
+
keyboardType: "decimal-pad";
|
|
36
|
+
setValue: (value: number | null) => void;
|
|
37
|
+
}
|
|
38
|
+
declare function useCurrencyMask({
|
|
39
|
+
locale,
|
|
40
|
+
currency,
|
|
41
|
+
precision,
|
|
42
|
+
min,
|
|
43
|
+
max,
|
|
44
|
+
onValueChange
|
|
45
|
+
}?: UseCurrencyMaskOptions): UseCurrencyMaskReturn;
|
|
46
|
+
//#endregion
|
|
47
|
+
export { DEFAULT_LAYOUT, DEFAULT_POSITION, LayoutPosition, NumericMaskFormat, ScreenSize, UseCurrencyMaskOptions, UseCurrencyMaskReturn, UseNumericMaskOptions, UseNumericMaskReturn, useCurrencyMask, useNumericMask, useRelativePosition, useScreenSize };
|
package/dist/hooks/index.mjs
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { n as DEFAULT_POSITION, r as useRelativePosition, t as DEFAULT_LAYOUT } from "../use-relative-position-BTKEyT1F.mjs";
|
|
2
|
+
import { t as useNumericMask } from "../use-numeric-mask-BQlz1Pus.mjs";
|
|
3
|
+
import { useCallback, useState } from "react";
|
|
1
4
|
import { useWindowDimensions } from "react-native";
|
|
2
5
|
|
|
3
|
-
//#region src/hooks/
|
|
6
|
+
//#region src/hooks/use-screen-size.ts
|
|
4
7
|
function useScreenSize() {
|
|
5
8
|
const windowDimensions = useWindowDimensions();
|
|
6
9
|
const size = windowDimensions.width < 768 ? "mobile" : windowDimensions.width < 1024 ? "tablet" : "desktop";
|
|
@@ -23,4 +26,78 @@ function useScreenSize() {
|
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
//#endregion
|
|
26
|
-
|
|
29
|
+
//#region src/hooks/use-currency-mask.ts
|
|
30
|
+
function useCurrencyMask({ locale = "en-US", currency = "USD", precision = 2, min, max, onValueChange } = {}) {
|
|
31
|
+
const [numericValue, setNumericValue] = useState(null);
|
|
32
|
+
const [displayValue, setDisplayValue] = useState("");
|
|
33
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
34
|
+
const formatCurrency = useCallback((num) => {
|
|
35
|
+
if (num === null || isNaN(num)) return "";
|
|
36
|
+
return new Intl.NumberFormat(locale, {
|
|
37
|
+
style: "currency",
|
|
38
|
+
currency,
|
|
39
|
+
minimumFractionDigits: precision,
|
|
40
|
+
maximumFractionDigits: precision
|
|
41
|
+
}).format(num);
|
|
42
|
+
}, [
|
|
43
|
+
locale,
|
|
44
|
+
currency,
|
|
45
|
+
precision
|
|
46
|
+
]);
|
|
47
|
+
const parseCurrency = useCallback((text) => {
|
|
48
|
+
const cleaned = text.replace(/[^\d.-]/g, "");
|
|
49
|
+
const parsed = parseFloat(cleaned);
|
|
50
|
+
if (isNaN(parsed) || cleaned === "") return null;
|
|
51
|
+
let constrained = parsed;
|
|
52
|
+
if (min !== void 0 && constrained < min) constrained = min;
|
|
53
|
+
if (max !== void 0 && constrained > max) constrained = max;
|
|
54
|
+
return constrained;
|
|
55
|
+
}, [min, max]);
|
|
56
|
+
return {
|
|
57
|
+
value: displayValue,
|
|
58
|
+
numericValue,
|
|
59
|
+
onChangeText: useCallback((text) => {
|
|
60
|
+
if (isFocused) {
|
|
61
|
+
const cleaned = text.replace(/[^\d.-]/g, "");
|
|
62
|
+
const decimalIndex = cleaned.indexOf(".");
|
|
63
|
+
if (decimalIndex !== -1) {
|
|
64
|
+
if (cleaned.substring(decimalIndex + 1).length > precision) return;
|
|
65
|
+
}
|
|
66
|
+
if ((cleaned.match(/\./g) || []).length > 1) return;
|
|
67
|
+
}
|
|
68
|
+
setDisplayValue(text);
|
|
69
|
+
const value = parseCurrency(text);
|
|
70
|
+
setNumericValue(value);
|
|
71
|
+
onValueChange?.(value);
|
|
72
|
+
}, [
|
|
73
|
+
parseCurrency,
|
|
74
|
+
onValueChange,
|
|
75
|
+
isFocused,
|
|
76
|
+
precision
|
|
77
|
+
]),
|
|
78
|
+
onBlur: useCallback(() => {
|
|
79
|
+
setIsFocused(false);
|
|
80
|
+
if (numericValue !== null) setDisplayValue(formatCurrency(numericValue));
|
|
81
|
+
else setDisplayValue("");
|
|
82
|
+
}, [numericValue, formatCurrency]),
|
|
83
|
+
onFocus: useCallback(() => {
|
|
84
|
+
setIsFocused(true);
|
|
85
|
+
if (numericValue !== null) setDisplayValue(numericValue.toString());
|
|
86
|
+
}, [numericValue]),
|
|
87
|
+
keyboardType: "decimal-pad",
|
|
88
|
+
setValue: useCallback((value) => {
|
|
89
|
+
setNumericValue(value);
|
|
90
|
+
if (value !== null) if (isFocused) setDisplayValue(value.toString());
|
|
91
|
+
else setDisplayValue(formatCurrency(value));
|
|
92
|
+
else setDisplayValue("");
|
|
93
|
+
onValueChange?.(value);
|
|
94
|
+
}, [
|
|
95
|
+
isFocused,
|
|
96
|
+
formatCurrency,
|
|
97
|
+
onValueChange
|
|
98
|
+
])
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
//#endregion
|
|
103
|
+
export { DEFAULT_LAYOUT, DEFAULT_POSITION, useCurrencyMask, useNumericMask, useRelativePosition, useScreenSize };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { r as LayoutPosition } from "./use-relative-position-DBzhrBU7.mjs";
|
|
1
2
|
import * as react7 from "react";
|
|
2
3
|
import React$1, { Dispatch, RefAttributes } from "react";
|
|
3
4
|
import { ImageSource, ImageStyle, LayoutRectangle, PressableProps, StyleProp, TextInputProps, TextProps, TextStyle, View, ViewStyle } from "react-native";
|
|
@@ -567,14 +568,6 @@ interface PopoverCloseProps extends Omit<PressableProps, "onPress"> {
|
|
|
567
568
|
}
|
|
568
569
|
declare function PopoverClose(props: PopoverCloseProps): React$1.JSX.Element;
|
|
569
570
|
//#endregion
|
|
570
|
-
//#region src/hooks/useRelativePosition.d.ts
|
|
571
|
-
interface LayoutPosition {
|
|
572
|
-
pageY: number;
|
|
573
|
-
pageX: number;
|
|
574
|
-
width: number;
|
|
575
|
-
height: number;
|
|
576
|
-
}
|
|
577
|
-
//#endregion
|
|
578
571
|
//#region src/primitives/popover/context.d.ts
|
|
579
572
|
interface PopoverContext {
|
|
580
573
|
isOpen: boolean;
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { a as ThemeProvider, n as ToastContainer, o as useTheme } from "./toast-manager-
|
|
2
|
-
import { m as PortalHost } from "./primitives-
|
|
1
|
+
import { a as ThemeProvider, n as ToastContainer, o as useTheme } from "./toast-manager-BfoJ-_dB.mjs";
|
|
2
|
+
import { m as PortalHost } from "./primitives-DNeYBN-3.mjs";
|
|
3
|
+
import "./use-relative-position-BTKEyT1F.mjs";
|
|
3
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
5
|
|
|
5
6
|
//#region src/index.tsx
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import { $ as SelectPortalProps, A as ToastRootProps, B as EmptyRootProps, C as TextareaPrimitiveProps, D as BadgeStyles, E as BadgeRootProps, F as AvatarRootProps, G as CardPrimitive, H as EmptyTitleProps, I as AvatarStyles, J as CardFooterProps, K as CardRootProps, L as AvatarImageProps, M as ToastDescriptionProps, N as ToastTitleProps, O as BadgeLabelProps, P as AvatarPrimitive, Q as SelectPrimitive, R as AvatarFallbackProps, S as TextareaPrimitiveBaseProps, St as FieldLabelProps, T as BadgePrimitive, U as EmptyMediaProps, V as EmptyStyles, W as EmptyDescriptionProps, X as CardTitleProps, Y as CardBodyProps, Z as CardHeaderProps, _ as DropdownMenuDividerProps, _t as FieldPrimitive, a as PopoverPortalProps, at as SelectOverlayProps, b as DropdownMenuTriggerProps, bt as FieldErrorProps, c as PopoverOverlayProps, ct as ButtonPrimitive, d as PopoverTriggerRef, dt as ButtonStyles, et as SelectRootBaseProps, f as DropdownMenuPrimitive, ft as ButtonPrimitiveLabelProps, g as DropdownMenuOverlayProps, gt as InputStyles, h as DropdownMenuStyles, ht as InputPrimitiveProps, i as PopoverCloseProps, it as SelectContentProps, j as ToastStyles, k as ToastPrimitive, l as PopoverContentProps, lt as ButtonPrimitiveRootProps, m as DropdownMenuRootProps, mt as InputPrimitiveBaseProps, n as PopoverContext, nt as SelectStyles, o as PopoverRootProps, ot as SelectValueProps, p as DropdownMenuPortalProps, pt as InputPrimitive, q as CardStyles, r as usePopover, rt as SelectOptionProps, st as SelectTriggerProps, t as PopoverPrimitive, tt as SelectRootProps, u as PopoverTriggerProps, ut as ButtonState, v as DropdownMenuButtonProps, vt as FieldPrimitiveRootProps, w as TextareaStyles, x as TextareaPrimitive, xt as FieldDescriptionProps, y as DropdownMenuContentProps, yt as FieldStyles, z as EmptyPrimitive } from "../index-
|
|
1
|
+
import { $ as SelectPortalProps, A as ToastRootProps, B as EmptyRootProps, C as TextareaPrimitiveProps, D as BadgeStyles, E as BadgeRootProps, F as AvatarRootProps, G as CardPrimitive, H as EmptyTitleProps, I as AvatarStyles, J as CardFooterProps, K as CardRootProps, L as AvatarImageProps, M as ToastDescriptionProps, N as ToastTitleProps, O as BadgeLabelProps, P as AvatarPrimitive, Q as SelectPrimitive, R as AvatarFallbackProps, S as TextareaPrimitiveBaseProps, St as FieldLabelProps, T as BadgePrimitive, U as EmptyMediaProps, V as EmptyStyles, W as EmptyDescriptionProps, X as CardTitleProps, Y as CardBodyProps, Z as CardHeaderProps, _ as DropdownMenuDividerProps, _t as FieldPrimitive, a as PopoverPortalProps, at as SelectOverlayProps, b as DropdownMenuTriggerProps, bt as FieldErrorProps, c as PopoverOverlayProps, ct as ButtonPrimitive, d as PopoverTriggerRef, dt as ButtonStyles, et as SelectRootBaseProps, f as DropdownMenuPrimitive, ft as ButtonPrimitiveLabelProps, g as DropdownMenuOverlayProps, gt as InputStyles, h as DropdownMenuStyles, ht as InputPrimitiveProps, i as PopoverCloseProps, it as SelectContentProps, j as ToastStyles, k as ToastPrimitive, l as PopoverContentProps, lt as ButtonPrimitiveRootProps, m as DropdownMenuRootProps, mt as InputPrimitiveBaseProps, n as PopoverContext, nt as SelectStyles, o as PopoverRootProps, ot as SelectValueProps, p as DropdownMenuPortalProps, pt as InputPrimitive, q as CardStyles, r as usePopover, rt as SelectOptionProps, st as SelectTriggerProps, t as PopoverPrimitive, tt as SelectRootProps, u as PopoverTriggerProps, ut as ButtonState, v as DropdownMenuButtonProps, vt as FieldPrimitiveRootProps, w as TextareaStyles, x as TextareaPrimitive, xt as FieldDescriptionProps, y as DropdownMenuContentProps, yt as FieldStyles, z as EmptyPrimitive } from "../index-pCM7YTs1.mjs";
|
|
2
|
+
import "../use-relative-position-DBzhrBU7.mjs";
|
|
2
3
|
export { AvatarFallbackProps, AvatarImageProps, AvatarPrimitive, AvatarRootProps, AvatarStyles, BadgeLabelProps, BadgePrimitive, BadgeRootProps, BadgeStyles, ButtonPrimitive, ButtonPrimitiveLabelProps, ButtonPrimitiveRootProps, ButtonState, ButtonStyles, CardBodyProps, CardFooterProps, CardHeaderProps, CardPrimitive, CardRootProps, CardStyles, CardTitleProps, DropdownMenuButtonProps, DropdownMenuContentProps, DropdownMenuDividerProps, DropdownMenuOverlayProps, DropdownMenuPortalProps, DropdownMenuPrimitive, DropdownMenuRootProps, DropdownMenuStyles, DropdownMenuTriggerProps, EmptyDescriptionProps, EmptyMediaProps, EmptyPrimitive, EmptyRootProps, EmptyStyles, EmptyTitleProps, FieldDescriptionProps, FieldErrorProps, FieldLabelProps, FieldPrimitive, FieldPrimitiveRootProps, FieldStyles, InputPrimitive, InputPrimitiveBaseProps, InputPrimitiveProps, InputStyles, PopoverCloseProps, PopoverContentProps, PopoverContext, PopoverOverlayProps, PopoverPortalProps, PopoverPrimitive, PopoverRootProps, PopoverTriggerProps, PopoverTriggerRef, SelectContentProps, SelectOptionProps, SelectOverlayProps, SelectPortalProps, SelectPrimitive, SelectRootBaseProps, SelectRootProps, SelectStyles, SelectTriggerProps, SelectValueProps, TextareaPrimitive, TextareaPrimitiveBaseProps, TextareaPrimitiveProps, TextareaStyles, ToastDescriptionProps, ToastPrimitive, ToastRootProps, ToastStyles, ToastTitleProps, usePopover };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import { a as BadgePrimitive, c as EmptyPrimitive, d as ButtonPrimitive, f as InputPrimitive, i as TextareaPrimitive, l as CardPrimitive, n as usePopover, o as ToastPrimitive, p as FieldPrimitive, r as DropdownMenuPrimitive, s as AvatarPrimitive, t as PopoverPrimitive, u as SelectPrimitive } from "../primitives-
|
|
1
|
+
import { a as BadgePrimitive, c as EmptyPrimitive, d as ButtonPrimitive, f as InputPrimitive, i as TextareaPrimitive, l as CardPrimitive, n as usePopover, o as ToastPrimitive, p as FieldPrimitive, r as DropdownMenuPrimitive, s as AvatarPrimitive, t as PopoverPrimitive, u as SelectPrimitive } from "../primitives-DNeYBN-3.mjs";
|
|
2
|
+
import "../use-relative-position-BTKEyT1F.mjs";
|
|
2
3
|
|
|
3
4
|
export { AvatarPrimitive, BadgePrimitive, ButtonPrimitive, CardPrimitive, DropdownMenuPrimitive, EmptyPrimitive, FieldPrimitive, InputPrimitive, PopoverPrimitive, SelectPrimitive, TextareaPrimitive, ToastPrimitive, usePopover };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import React, { createContext, forwardRef, useContext, useEffect, useImperativeHandle, useRef, useState, useSyncExternalStore } from "react";
|
|
3
|
-
import { ActivityIndicator, Image, Pressable, StyleSheet, Text, TextInput, View
|
|
1
|
+
import { n as DEFAULT_POSITION, r as useRelativePosition, t as DEFAULT_LAYOUT } from "./use-relative-position-BTKEyT1F.mjs";
|
|
2
|
+
import React, { createContext, forwardRef, useCallback, useContext, useEffect, useImperativeHandle, useRef, useState, useSyncExternalStore } from "react";
|
|
3
|
+
import { ActivityIndicator, Image, Pressable, StyleSheet, Text, TextInput, View } from "react-native";
|
|
4
4
|
import { Fragment, jsx } from "react/jsx-runtime";
|
|
5
5
|
|
|
6
6
|
//#region src/primitives/portal/portal.tsx
|
|
@@ -752,108 +752,6 @@ const useDropdownMenu = () => {
|
|
|
752
752
|
return context;
|
|
753
753
|
};
|
|
754
754
|
|
|
755
|
-
//#endregion
|
|
756
|
-
//#region src/hooks/useRelativePosition.ts
|
|
757
|
-
function useRelativePosition({ align, avoidCollisions, triggerPosition, contentLayout, alignOffset, insets, sideOffset, side }) {
|
|
758
|
-
const dimensions = useWindowDimensions();
|
|
759
|
-
return React$1.useMemo(() => {
|
|
760
|
-
if (!triggerPosition || !contentLayout) return {
|
|
761
|
-
position: "absolute",
|
|
762
|
-
opacity: 0,
|
|
763
|
-
top: dimensions.height,
|
|
764
|
-
zIndex: -9999999
|
|
765
|
-
};
|
|
766
|
-
return getContentStyle({
|
|
767
|
-
align,
|
|
768
|
-
avoidCollisions,
|
|
769
|
-
contentLayout,
|
|
770
|
-
side,
|
|
771
|
-
triggerPosition,
|
|
772
|
-
alignOffset,
|
|
773
|
-
insets,
|
|
774
|
-
sideOffset,
|
|
775
|
-
dimensions
|
|
776
|
-
});
|
|
777
|
-
}, [
|
|
778
|
-
align,
|
|
779
|
-
avoidCollisions,
|
|
780
|
-
side,
|
|
781
|
-
alignOffset,
|
|
782
|
-
insets,
|
|
783
|
-
triggerPosition,
|
|
784
|
-
contentLayout,
|
|
785
|
-
dimensions.width,
|
|
786
|
-
dimensions.height
|
|
787
|
-
]);
|
|
788
|
-
}
|
|
789
|
-
const DEFAULT_LAYOUT = {
|
|
790
|
-
x: 0,
|
|
791
|
-
y: 0,
|
|
792
|
-
width: 0,
|
|
793
|
-
height: 0
|
|
794
|
-
};
|
|
795
|
-
const DEFAULT_POSITION = {
|
|
796
|
-
height: 0,
|
|
797
|
-
width: 0,
|
|
798
|
-
pageX: 0,
|
|
799
|
-
pageY: 0
|
|
800
|
-
};
|
|
801
|
-
function getSidePosition({ side, triggerPosition, contentLayout, sideOffset, insets, avoidCollisions, dimensions }) {
|
|
802
|
-
const insetTop = insets?.top ?? 0;
|
|
803
|
-
const insetBottom = insets?.bottom ?? 0;
|
|
804
|
-
const positionTop = triggerPosition?.pageY - sideOffset - contentLayout.height;
|
|
805
|
-
const positionBottom = triggerPosition.pageY + triggerPosition.height + sideOffset;
|
|
806
|
-
if (!avoidCollisions) return { top: side === "top" ? positionTop : positionBottom };
|
|
807
|
-
if (side === "top") return { top: Math.min(Math.max(insetTop, positionTop), dimensions.height - insetBottom - contentLayout.height) };
|
|
808
|
-
return { top: Math.min(dimensions.height - insetBottom - contentLayout.height, positionBottom) };
|
|
809
|
-
}
|
|
810
|
-
function getAlignPosition({ align, avoidCollisions, contentLayout, triggerPosition, alignOffset, insets, dimensions }) {
|
|
811
|
-
const insetLeft = insets?.left ?? 0;
|
|
812
|
-
const insetRight = insets?.right ?? 0;
|
|
813
|
-
const maxContentWidth = dimensions.width - insetLeft - insetRight;
|
|
814
|
-
const contentWidth = Math.min(contentLayout.width, maxContentWidth);
|
|
815
|
-
let left = getLeftPosition(align, triggerPosition.pageX, triggerPosition.width, contentWidth, alignOffset, insetLeft, insetRight, dimensions);
|
|
816
|
-
if (avoidCollisions) {
|
|
817
|
-
if (left < insetLeft || left + contentWidth > dimensions.width - insetRight) {
|
|
818
|
-
const spaceLeft = left - insetLeft;
|
|
819
|
-
const spaceRight = dimensions.width - insetRight - (left + contentWidth);
|
|
820
|
-
if (spaceLeft > spaceRight && spaceLeft >= contentWidth) left = insetLeft;
|
|
821
|
-
else if (spaceRight >= contentWidth) left = dimensions.width - insetRight - contentWidth;
|
|
822
|
-
else left = Math.max(insetLeft, (dimensions.width - contentWidth - insetRight) / 2);
|
|
823
|
-
}
|
|
824
|
-
}
|
|
825
|
-
return {
|
|
826
|
-
left,
|
|
827
|
-
maxWidth: maxContentWidth
|
|
828
|
-
};
|
|
829
|
-
}
|
|
830
|
-
function getLeftPosition(align, triggerPageX, triggerWidth, contentWidth, alignOffset, insetLeft, insetRight, dimensions) {
|
|
831
|
-
let left = 0;
|
|
832
|
-
if (align === "start") left = triggerPageX;
|
|
833
|
-
if (align === "center") left = triggerPageX + triggerWidth / 2 - contentWidth / 2;
|
|
834
|
-
if (align === "end") left = triggerPageX + triggerWidth - contentWidth;
|
|
835
|
-
return Math.max(insetLeft, Math.min(left + alignOffset, dimensions.width - contentWidth - insetRight));
|
|
836
|
-
}
|
|
837
|
-
function getContentStyle({ align, avoidCollisions, contentLayout, side, triggerPosition, alignOffset, insets, sideOffset, dimensions }) {
|
|
838
|
-
return Object.assign({ position: "absolute" }, getSidePosition({
|
|
839
|
-
side,
|
|
840
|
-
triggerPosition,
|
|
841
|
-
contentLayout,
|
|
842
|
-
sideOffset,
|
|
843
|
-
insets,
|
|
844
|
-
avoidCollisions,
|
|
845
|
-
dimensions
|
|
846
|
-
}), getAlignPosition({
|
|
847
|
-
align,
|
|
848
|
-
avoidCollisions,
|
|
849
|
-
triggerPosition,
|
|
850
|
-
contentLayout,
|
|
851
|
-
alignOffset,
|
|
852
|
-
insets,
|
|
853
|
-
dimensions
|
|
854
|
-
}));
|
|
855
|
-
}
|
|
856
|
-
|
|
857
755
|
//#endregion
|
|
858
756
|
//#region src/primitives/dropdown-menu/dropdown-menu-root.tsx
|
|
859
757
|
function DropdownMenuRoot(props) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { o as ToastPrimitive } from "./primitives-
|
|
1
|
+
import { o as ToastPrimitive } from "./primitives-DNeYBN-3.mjs";
|
|
2
2
|
import React, { createContext, useContext, useEffect, useState, useSyncExternalStore } from "react";
|
|
3
3
|
import { StyleSheet, View, useColorScheme } from "react-native";
|
|
4
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//#region src/hooks/use-numeric-mask.d.ts
|
|
2
|
+
type NumericMaskFormat = "currency" | "decimal" | "integer" | "percentage";
|
|
3
|
+
interface UseNumericMaskOptions {
|
|
4
|
+
format?: NumericMaskFormat;
|
|
5
|
+
locale?: string;
|
|
6
|
+
currency?: string;
|
|
7
|
+
precision?: number;
|
|
8
|
+
min?: number;
|
|
9
|
+
max?: number;
|
|
10
|
+
allowNegative?: boolean;
|
|
11
|
+
onChange?: (value: number | null) => void;
|
|
12
|
+
}
|
|
13
|
+
interface UseNumericMaskReturn {
|
|
14
|
+
value: string;
|
|
15
|
+
numericValue: number | null;
|
|
16
|
+
onChangeText: (text: string) => void;
|
|
17
|
+
onBlur: () => void;
|
|
18
|
+
onFocus: () => void;
|
|
19
|
+
keyboardType: "numeric" | "decimal-pad" | "number-pad";
|
|
20
|
+
setValue: (value: number | null) => void;
|
|
21
|
+
}
|
|
22
|
+
declare function useNumericMask({
|
|
23
|
+
format,
|
|
24
|
+
locale,
|
|
25
|
+
currency,
|
|
26
|
+
precision,
|
|
27
|
+
min,
|
|
28
|
+
max,
|
|
29
|
+
allowNegative,
|
|
30
|
+
onChange
|
|
31
|
+
}?: UseNumericMaskOptions): UseNumericMaskReturn;
|
|
32
|
+
//#endregion
|
|
33
|
+
export { useNumericMask as i, UseNumericMaskOptions as n, UseNumericMaskReturn as r, NumericMaskFormat as t };
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { useCallback, useState } from "react";
|
|
2
|
+
|
|
3
|
+
//#region src/hooks/use-numeric-mask.ts
|
|
4
|
+
function useNumericMask({ format = "decimal", locale = "en-US", currency = "USD", precision = 2, min, max, allowNegative = true, onChange } = {}) {
|
|
5
|
+
const [numericValue, setNumericValue] = useState(null);
|
|
6
|
+
const [displayValue, setDisplayValue] = useState("");
|
|
7
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
8
|
+
const effectivePrecision = format === "integer" ? 0 : precision;
|
|
9
|
+
const formatValue = useCallback((num) => {
|
|
10
|
+
if (num === null || isNaN(num)) return "";
|
|
11
|
+
switch (format) {
|
|
12
|
+
case "currency": return new Intl.NumberFormat(locale, {
|
|
13
|
+
style: "currency",
|
|
14
|
+
currency,
|
|
15
|
+
minimumFractionDigits: effectivePrecision,
|
|
16
|
+
maximumFractionDigits: effectivePrecision
|
|
17
|
+
}).format(num);
|
|
18
|
+
case "percentage": return new Intl.NumberFormat(locale, {
|
|
19
|
+
style: "percent",
|
|
20
|
+
minimumFractionDigits: effectivePrecision,
|
|
21
|
+
maximumFractionDigits: effectivePrecision
|
|
22
|
+
}).format(num / 100);
|
|
23
|
+
case "integer": return new Intl.NumberFormat(locale, {
|
|
24
|
+
minimumFractionDigits: 0,
|
|
25
|
+
maximumFractionDigits: 0
|
|
26
|
+
}).format(num);
|
|
27
|
+
case "decimal":
|
|
28
|
+
default: return new Intl.NumberFormat(locale, {
|
|
29
|
+
minimumFractionDigits: effectivePrecision,
|
|
30
|
+
maximumFractionDigits: effectivePrecision
|
|
31
|
+
}).format(num);
|
|
32
|
+
}
|
|
33
|
+
}, [
|
|
34
|
+
format,
|
|
35
|
+
locale,
|
|
36
|
+
currency,
|
|
37
|
+
effectivePrecision
|
|
38
|
+
]);
|
|
39
|
+
const parseValue = useCallback((text) => {
|
|
40
|
+
let cleaned = text.replace(/[^\d.-]/g, "");
|
|
41
|
+
if (!allowNegative) cleaned = cleaned.replace(/-/g, "");
|
|
42
|
+
const parsed = parseFloat(cleaned);
|
|
43
|
+
if (isNaN(parsed) || cleaned === "" || cleaned === "-") return null;
|
|
44
|
+
let constrained = parsed;
|
|
45
|
+
if (min !== void 0 && constrained < min) constrained = min;
|
|
46
|
+
if (max !== void 0 && constrained > max) constrained = max;
|
|
47
|
+
return constrained;
|
|
48
|
+
}, [
|
|
49
|
+
min,
|
|
50
|
+
max,
|
|
51
|
+
allowNegative
|
|
52
|
+
]);
|
|
53
|
+
const handleChangeText = useCallback((text) => {
|
|
54
|
+
if (isFocused) {
|
|
55
|
+
let cleaned = text.replace(/[^\d.-]/g, "");
|
|
56
|
+
if (!allowNegative && cleaned.includes("-")) return;
|
|
57
|
+
if (allowNegative) {
|
|
58
|
+
if ((cleaned.match(/-/g) || []).length > 1 || cleaned.includes("-") && cleaned.indexOf("-") !== 0) return;
|
|
59
|
+
}
|
|
60
|
+
if (effectivePrecision >= 0) {
|
|
61
|
+
const decimalIndex = cleaned.indexOf(".");
|
|
62
|
+
if (decimalIndex !== -1) {
|
|
63
|
+
if (cleaned.substring(decimalIndex + 1).length > effectivePrecision) return;
|
|
64
|
+
}
|
|
65
|
+
if ((cleaned.match(/\./g) || []).length > 1) return;
|
|
66
|
+
if (format === "integer" && cleaned.includes(".")) return;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
setDisplayValue(text);
|
|
70
|
+
const value = parseValue(text);
|
|
71
|
+
setNumericValue(value);
|
|
72
|
+
onChange?.(value);
|
|
73
|
+
}, [
|
|
74
|
+
parseValue,
|
|
75
|
+
onChange,
|
|
76
|
+
isFocused,
|
|
77
|
+
effectivePrecision,
|
|
78
|
+
allowNegative,
|
|
79
|
+
format
|
|
80
|
+
]);
|
|
81
|
+
const handleBlur = useCallback(() => {
|
|
82
|
+
setIsFocused(false);
|
|
83
|
+
if (numericValue !== null) setDisplayValue(formatValue(numericValue));
|
|
84
|
+
else setDisplayValue("");
|
|
85
|
+
}, [numericValue, formatValue]);
|
|
86
|
+
const handleFocus = useCallback(() => {
|
|
87
|
+
setIsFocused(true);
|
|
88
|
+
if (numericValue !== null) setDisplayValue(numericValue.toString());
|
|
89
|
+
}, [numericValue]);
|
|
90
|
+
const setValue = useCallback((value) => {
|
|
91
|
+
setNumericValue(value);
|
|
92
|
+
if (value !== null) if (isFocused) setDisplayValue(value.toString());
|
|
93
|
+
else setDisplayValue(formatValue(value));
|
|
94
|
+
else setDisplayValue("");
|
|
95
|
+
onChange?.(value);
|
|
96
|
+
}, [
|
|
97
|
+
isFocused,
|
|
98
|
+
formatValue,
|
|
99
|
+
onChange
|
|
100
|
+
]);
|
|
101
|
+
return {
|
|
102
|
+
value: displayValue,
|
|
103
|
+
numericValue,
|
|
104
|
+
onChangeText: handleChangeText,
|
|
105
|
+
onBlur: handleBlur,
|
|
106
|
+
onFocus: handleFocus,
|
|
107
|
+
keyboardType: format === "integer" ? allowNegative ? "numeric" : "number-pad" : "decimal-pad",
|
|
108
|
+
setValue
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
//#endregion
|
|
113
|
+
export { useNumericMask as t };
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import * as React$1 from "react";
|
|
2
|
+
import { useWindowDimensions } from "react-native";
|
|
3
|
+
|
|
4
|
+
//#region src/hooks/use-relative-position.ts
|
|
5
|
+
function useRelativePosition({ align, avoidCollisions, triggerPosition, contentLayout, alignOffset, insets, sideOffset, side }) {
|
|
6
|
+
const dimensions = useWindowDimensions();
|
|
7
|
+
return React$1.useMemo(() => {
|
|
8
|
+
if (!triggerPosition || !contentLayout) return {
|
|
9
|
+
position: "absolute",
|
|
10
|
+
opacity: 0,
|
|
11
|
+
top: dimensions.height,
|
|
12
|
+
zIndex: -9999999
|
|
13
|
+
};
|
|
14
|
+
return getContentStyle({
|
|
15
|
+
align,
|
|
16
|
+
avoidCollisions,
|
|
17
|
+
contentLayout,
|
|
18
|
+
side,
|
|
19
|
+
triggerPosition,
|
|
20
|
+
alignOffset,
|
|
21
|
+
insets,
|
|
22
|
+
sideOffset,
|
|
23
|
+
dimensions
|
|
24
|
+
});
|
|
25
|
+
}, [
|
|
26
|
+
align,
|
|
27
|
+
avoidCollisions,
|
|
28
|
+
side,
|
|
29
|
+
alignOffset,
|
|
30
|
+
insets,
|
|
31
|
+
triggerPosition,
|
|
32
|
+
contentLayout,
|
|
33
|
+
dimensions.width,
|
|
34
|
+
dimensions.height
|
|
35
|
+
]);
|
|
36
|
+
}
|
|
37
|
+
const DEFAULT_LAYOUT = {
|
|
38
|
+
x: 0,
|
|
39
|
+
y: 0,
|
|
40
|
+
width: 0,
|
|
41
|
+
height: 0
|
|
42
|
+
};
|
|
43
|
+
const DEFAULT_POSITION = {
|
|
44
|
+
height: 0,
|
|
45
|
+
width: 0,
|
|
46
|
+
pageX: 0,
|
|
47
|
+
pageY: 0
|
|
48
|
+
};
|
|
49
|
+
function getSidePosition({ side, triggerPosition, contentLayout, sideOffset, insets, avoidCollisions, dimensions }) {
|
|
50
|
+
const insetTop = insets?.top ?? 0;
|
|
51
|
+
const insetBottom = insets?.bottom ?? 0;
|
|
52
|
+
const positionTop = triggerPosition?.pageY - sideOffset - contentLayout.height;
|
|
53
|
+
const positionBottom = triggerPosition.pageY + triggerPosition.height + sideOffset;
|
|
54
|
+
if (!avoidCollisions) return { top: side === "top" ? positionTop : positionBottom };
|
|
55
|
+
if (side === "top") return { top: Math.min(Math.max(insetTop, positionTop), dimensions.height - insetBottom - contentLayout.height) };
|
|
56
|
+
return { top: Math.min(dimensions.height - insetBottom - contentLayout.height, positionBottom) };
|
|
57
|
+
}
|
|
58
|
+
function getAlignPosition({ align, avoidCollisions, contentLayout, triggerPosition, alignOffset, insets, dimensions }) {
|
|
59
|
+
const insetLeft = insets?.left ?? 0;
|
|
60
|
+
const insetRight = insets?.right ?? 0;
|
|
61
|
+
const maxContentWidth = dimensions.width - insetLeft - insetRight;
|
|
62
|
+
const contentWidth = Math.min(contentLayout.width, maxContentWidth);
|
|
63
|
+
let left = getLeftPosition(align, triggerPosition.pageX, triggerPosition.width, contentWidth, alignOffset, insetLeft, insetRight, dimensions);
|
|
64
|
+
if (avoidCollisions) {
|
|
65
|
+
if (left < insetLeft || left + contentWidth > dimensions.width - insetRight) {
|
|
66
|
+
const spaceLeft = left - insetLeft;
|
|
67
|
+
const spaceRight = dimensions.width - insetRight - (left + contentWidth);
|
|
68
|
+
if (spaceLeft > spaceRight && spaceLeft >= contentWidth) left = insetLeft;
|
|
69
|
+
else if (spaceRight >= contentWidth) left = dimensions.width - insetRight - contentWidth;
|
|
70
|
+
else left = Math.max(insetLeft, (dimensions.width - contentWidth - insetRight) / 2);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
left,
|
|
75
|
+
maxWidth: maxContentWidth
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function getLeftPosition(align, triggerPageX, triggerWidth, contentWidth, alignOffset, insetLeft, insetRight, dimensions) {
|
|
79
|
+
let left = 0;
|
|
80
|
+
if (align === "start") left = triggerPageX;
|
|
81
|
+
if (align === "center") left = triggerPageX + triggerWidth / 2 - contentWidth / 2;
|
|
82
|
+
if (align === "end") left = triggerPageX + triggerWidth - contentWidth;
|
|
83
|
+
return Math.max(insetLeft, Math.min(left + alignOffset, dimensions.width - contentWidth - insetRight));
|
|
84
|
+
}
|
|
85
|
+
function getContentStyle({ align, avoidCollisions, contentLayout, side, triggerPosition, alignOffset, insets, sideOffset, dimensions }) {
|
|
86
|
+
return Object.assign({ position: "absolute" }, getSidePosition({
|
|
87
|
+
side,
|
|
88
|
+
triggerPosition,
|
|
89
|
+
contentLayout,
|
|
90
|
+
sideOffset,
|
|
91
|
+
insets,
|
|
92
|
+
avoidCollisions,
|
|
93
|
+
dimensions
|
|
94
|
+
}), getAlignPosition({
|
|
95
|
+
align,
|
|
96
|
+
avoidCollisions,
|
|
97
|
+
triggerPosition,
|
|
98
|
+
contentLayout,
|
|
99
|
+
alignOffset,
|
|
100
|
+
insets,
|
|
101
|
+
dimensions
|
|
102
|
+
}));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
//#endregion
|
|
106
|
+
export { DEFAULT_POSITION as n, useRelativePosition as r, DEFAULT_LAYOUT as t };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { LayoutRectangle, ScaledSize } from "react-native";
|
|
2
|
+
|
|
3
|
+
//#region src/hooks/use-relative-position.d.ts
|
|
4
|
+
interface Insets {
|
|
5
|
+
top?: number;
|
|
6
|
+
bottom?: number;
|
|
7
|
+
left?: number;
|
|
8
|
+
right?: number;
|
|
9
|
+
}
|
|
10
|
+
type UseRelativePositionArgs = Omit<GetContentStyleArgs, "triggerPosition" | "contentLayout" | "dimensions"> & {
|
|
11
|
+
triggerPosition: LayoutPosition | null;
|
|
12
|
+
contentLayout: LayoutRectangle | null;
|
|
13
|
+
};
|
|
14
|
+
declare function useRelativePosition({
|
|
15
|
+
align,
|
|
16
|
+
avoidCollisions,
|
|
17
|
+
triggerPosition,
|
|
18
|
+
contentLayout,
|
|
19
|
+
alignOffset,
|
|
20
|
+
insets,
|
|
21
|
+
sideOffset,
|
|
22
|
+
side
|
|
23
|
+
}: UseRelativePositionArgs): ({
|
|
24
|
+
readonly position: "absolute";
|
|
25
|
+
} & {
|
|
26
|
+
top: number;
|
|
27
|
+
} & {
|
|
28
|
+
left: number;
|
|
29
|
+
maxWidth: number;
|
|
30
|
+
}) | {
|
|
31
|
+
readonly position: "absolute";
|
|
32
|
+
readonly opacity: 0;
|
|
33
|
+
readonly top: number;
|
|
34
|
+
readonly zIndex: -9999999;
|
|
35
|
+
};
|
|
36
|
+
interface LayoutPosition {
|
|
37
|
+
pageY: number;
|
|
38
|
+
pageX: number;
|
|
39
|
+
width: number;
|
|
40
|
+
height: number;
|
|
41
|
+
}
|
|
42
|
+
interface GetPositionArgs {
|
|
43
|
+
dimensions: ScaledSize;
|
|
44
|
+
avoidCollisions: boolean;
|
|
45
|
+
triggerPosition: LayoutPosition;
|
|
46
|
+
contentLayout: LayoutRectangle;
|
|
47
|
+
insets?: Insets;
|
|
48
|
+
}
|
|
49
|
+
interface GetSidePositionArgs extends GetPositionArgs {
|
|
50
|
+
side: "top" | "bottom";
|
|
51
|
+
sideOffset: number;
|
|
52
|
+
}
|
|
53
|
+
declare const DEFAULT_LAYOUT: LayoutRectangle;
|
|
54
|
+
declare const DEFAULT_POSITION: LayoutPosition;
|
|
55
|
+
interface GetAlignPositionArgs extends GetPositionArgs {
|
|
56
|
+
align: "start" | "center" | "end";
|
|
57
|
+
alignOffset: number;
|
|
58
|
+
}
|
|
59
|
+
type GetContentStyleArgs = GetPositionArgs & GetSidePositionArgs & GetAlignPositionArgs;
|
|
60
|
+
//#endregion
|
|
61
|
+
export { useRelativePosition as i, DEFAULT_POSITION as n, LayoutPosition as r, DEFAULT_LAYOUT as t };
|
package/package.json
CHANGED
package/src/components/index.ts
CHANGED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import React, { useEffect } from "react";
|
|
2
|
+
import { Input } from "./input";
|
|
3
|
+
import { InputPrimitiveBaseProps } from "@/primitives";
|
|
4
|
+
import { useNumericMask, NumericMaskFormat } from "@/hooks/use-numeric-mask";
|
|
5
|
+
|
|
6
|
+
export interface NumericInputProps extends Omit<InputPrimitiveBaseProps, "value" | "onChange" | "keyboardType"> {
|
|
7
|
+
variant?: "default";
|
|
8
|
+
value?: number | null;
|
|
9
|
+
onChange?: (value: number | null) => void;
|
|
10
|
+
format?: NumericMaskFormat;
|
|
11
|
+
locale?: string;
|
|
12
|
+
currency?: string;
|
|
13
|
+
precision?: number;
|
|
14
|
+
min?: number;
|
|
15
|
+
max?: number;
|
|
16
|
+
allowNegative?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function NumericInput({
|
|
20
|
+
value,
|
|
21
|
+
onChange,
|
|
22
|
+
format = "decimal",
|
|
23
|
+
locale = "en-US",
|
|
24
|
+
currency = "USD",
|
|
25
|
+
precision = 2,
|
|
26
|
+
min,
|
|
27
|
+
max,
|
|
28
|
+
allowNegative = true,
|
|
29
|
+
variant = "default",
|
|
30
|
+
onBlur,
|
|
31
|
+
onFocus,
|
|
32
|
+
...props
|
|
33
|
+
}: NumericInputProps) {
|
|
34
|
+
const numericMask = useNumericMask({
|
|
35
|
+
format,
|
|
36
|
+
locale,
|
|
37
|
+
currency,
|
|
38
|
+
precision,
|
|
39
|
+
min,
|
|
40
|
+
max,
|
|
41
|
+
allowNegative,
|
|
42
|
+
onChange,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Sync external value changes with internal state
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
if (value !== numericMask.numericValue) {
|
|
48
|
+
numericMask.setValue(value ?? null);
|
|
49
|
+
}
|
|
50
|
+
}, [value]);
|
|
51
|
+
|
|
52
|
+
const handleBlur = (e: any) => {
|
|
53
|
+
numericMask.onBlur();
|
|
54
|
+
onBlur?.(e);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const handleFocus = (e: any) => {
|
|
58
|
+
numericMask.onFocus();
|
|
59
|
+
onFocus?.(e);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<Input
|
|
64
|
+
{...props}
|
|
65
|
+
variant={variant}
|
|
66
|
+
value={numericMask.value}
|
|
67
|
+
onChange={numericMask.onChangeText}
|
|
68
|
+
onBlur={handleBlur}
|
|
69
|
+
onFocus={handleFocus}
|
|
70
|
+
keyboardType={numericMask.keyboardType}
|
|
71
|
+
/>
|
|
72
|
+
);
|
|
73
|
+
}
|
package/src/hooks/index.ts
CHANGED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { useState, useCallback } from "react";
|
|
2
|
+
|
|
3
|
+
export interface UseCurrencyMaskOptions {
|
|
4
|
+
locale?: string;
|
|
5
|
+
currency?: string;
|
|
6
|
+
precision?: number;
|
|
7
|
+
min?: number;
|
|
8
|
+
max?: number;
|
|
9
|
+
onValueChange?: (value: number | null) => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface UseCurrencyMaskReturn {
|
|
13
|
+
value: string;
|
|
14
|
+
numericValue: number | null;
|
|
15
|
+
onChangeText: (text: string) => void;
|
|
16
|
+
onBlur: () => void;
|
|
17
|
+
onFocus: () => void;
|
|
18
|
+
keyboardType: "decimal-pad";
|
|
19
|
+
setValue: (value: number | null) => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function useCurrencyMask({
|
|
23
|
+
locale = "en-US",
|
|
24
|
+
currency = "USD",
|
|
25
|
+
precision = 2,
|
|
26
|
+
min,
|
|
27
|
+
max,
|
|
28
|
+
onValueChange,
|
|
29
|
+
}: UseCurrencyMaskOptions = {}): UseCurrencyMaskReturn {
|
|
30
|
+
const [numericValue, setNumericValue] = useState<number | null>(null);
|
|
31
|
+
const [displayValue, setDisplayValue] = useState("");
|
|
32
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
33
|
+
|
|
34
|
+
const formatCurrency = useCallback(
|
|
35
|
+
(num: number | null): string => {
|
|
36
|
+
if (num === null || isNaN(num)) return "";
|
|
37
|
+
|
|
38
|
+
return new Intl.NumberFormat(locale, {
|
|
39
|
+
style: "currency",
|
|
40
|
+
currency,
|
|
41
|
+
minimumFractionDigits: precision,
|
|
42
|
+
maximumFractionDigits: precision,
|
|
43
|
+
}).format(num);
|
|
44
|
+
},
|
|
45
|
+
[locale, currency, precision]
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
const parseCurrency = useCallback(
|
|
49
|
+
(text: string): number | null => {
|
|
50
|
+
// Remove currency symbols, spaces, and thousand separators
|
|
51
|
+
const cleaned = text.replace(/[^\d.-]/g, "");
|
|
52
|
+
const parsed = parseFloat(cleaned);
|
|
53
|
+
|
|
54
|
+
if (isNaN(parsed) || cleaned === "") return null;
|
|
55
|
+
|
|
56
|
+
// Apply min/max constraints
|
|
57
|
+
let constrained = parsed;
|
|
58
|
+
if (min !== undefined && constrained < min) constrained = min;
|
|
59
|
+
if (max !== undefined && constrained > max) constrained = max;
|
|
60
|
+
|
|
61
|
+
return constrained;
|
|
62
|
+
},
|
|
63
|
+
[min, max]
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
const handleChangeText = useCallback(
|
|
67
|
+
(text: string) => {
|
|
68
|
+
// When focused, validate decimal precision before allowing input
|
|
69
|
+
if (isFocused) {
|
|
70
|
+
// Remove currency symbols and thousand separators to get raw input
|
|
71
|
+
const cleaned = text.replace(/[^\d.-]/g, "");
|
|
72
|
+
|
|
73
|
+
// Check if input has a decimal point
|
|
74
|
+
const decimalIndex = cleaned.indexOf(".");
|
|
75
|
+
if (decimalIndex !== -1) {
|
|
76
|
+
const decimalPart = cleaned.substring(decimalIndex + 1);
|
|
77
|
+
|
|
78
|
+
// Prevent typing more decimals than allowed precision
|
|
79
|
+
if (decimalPart.length > precision) {
|
|
80
|
+
return; // Don't update state if exceeds precision
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Also prevent multiple decimal points
|
|
85
|
+
const decimalCount = (cleaned.match(/\./g) || []).length;
|
|
86
|
+
if (decimalCount > 1) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
setDisplayValue(text);
|
|
92
|
+
const value = parseCurrency(text);
|
|
93
|
+
setNumericValue(value);
|
|
94
|
+
onValueChange?.(value);
|
|
95
|
+
},
|
|
96
|
+
[parseCurrency, onValueChange, isFocused, precision]
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
const handleBlur = useCallback(() => {
|
|
100
|
+
setIsFocused(false);
|
|
101
|
+
if (numericValue !== null) {
|
|
102
|
+
setDisplayValue(formatCurrency(numericValue));
|
|
103
|
+
} else {
|
|
104
|
+
setDisplayValue("");
|
|
105
|
+
}
|
|
106
|
+
}, [numericValue, formatCurrency]);
|
|
107
|
+
|
|
108
|
+
const handleFocus = useCallback(() => {
|
|
109
|
+
setIsFocused(true);
|
|
110
|
+
if (numericValue !== null) {
|
|
111
|
+
setDisplayValue(numericValue.toString());
|
|
112
|
+
}
|
|
113
|
+
}, [numericValue]);
|
|
114
|
+
|
|
115
|
+
const setValue = useCallback(
|
|
116
|
+
(value: number | null) => {
|
|
117
|
+
setNumericValue(value);
|
|
118
|
+
if (value !== null) {
|
|
119
|
+
if (isFocused) {
|
|
120
|
+
setDisplayValue(value.toString());
|
|
121
|
+
} else {
|
|
122
|
+
setDisplayValue(formatCurrency(value));
|
|
123
|
+
}
|
|
124
|
+
} else {
|
|
125
|
+
setDisplayValue("");
|
|
126
|
+
}
|
|
127
|
+
onValueChange?.(value);
|
|
128
|
+
},
|
|
129
|
+
[isFocused, formatCurrency, onValueChange]
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
value: displayValue,
|
|
134
|
+
numericValue,
|
|
135
|
+
onChangeText: handleChangeText,
|
|
136
|
+
onBlur: handleBlur,
|
|
137
|
+
onFocus: handleFocus,
|
|
138
|
+
keyboardType: "decimal-pad",
|
|
139
|
+
setValue,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { useState, useCallback } from "react";
|
|
2
|
+
|
|
3
|
+
export type NumericMaskFormat = "currency" | "decimal" | "integer" | "percentage";
|
|
4
|
+
|
|
5
|
+
export interface UseNumericMaskOptions {
|
|
6
|
+
format?: NumericMaskFormat;
|
|
7
|
+
locale?: string;
|
|
8
|
+
currency?: string;
|
|
9
|
+
precision?: number;
|
|
10
|
+
min?: number;
|
|
11
|
+
max?: number;
|
|
12
|
+
allowNegative?: boolean;
|
|
13
|
+
onChange?: (value: number | null) => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface UseNumericMaskReturn {
|
|
17
|
+
value: string;
|
|
18
|
+
numericValue: number | null;
|
|
19
|
+
onChangeText: (text: string) => void;
|
|
20
|
+
onBlur: () => void;
|
|
21
|
+
onFocus: () => void;
|
|
22
|
+
keyboardType: "numeric" | "decimal-pad" | "number-pad";
|
|
23
|
+
setValue: (value: number | null) => void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function useNumericMask({
|
|
27
|
+
format = "decimal",
|
|
28
|
+
locale = "en-US",
|
|
29
|
+
currency = "USD",
|
|
30
|
+
precision = 2,
|
|
31
|
+
min,
|
|
32
|
+
max,
|
|
33
|
+
allowNegative = true,
|
|
34
|
+
onChange,
|
|
35
|
+
}: UseNumericMaskOptions = {}): UseNumericMaskReturn {
|
|
36
|
+
const [numericValue, setNumericValue] = useState<number | null>(null);
|
|
37
|
+
const [displayValue, setDisplayValue] = useState("");
|
|
38
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
39
|
+
|
|
40
|
+
// Determine actual precision based on format
|
|
41
|
+
const effectivePrecision = format === "integer" ? 0 : precision;
|
|
42
|
+
|
|
43
|
+
const formatValue = useCallback(
|
|
44
|
+
(num: number | null): string => {
|
|
45
|
+
if (num === null || isNaN(num)) return "";
|
|
46
|
+
|
|
47
|
+
switch (format) {
|
|
48
|
+
case "currency":
|
|
49
|
+
return new Intl.NumberFormat(locale, {
|
|
50
|
+
style: "currency",
|
|
51
|
+
currency,
|
|
52
|
+
minimumFractionDigits: effectivePrecision,
|
|
53
|
+
maximumFractionDigits: effectivePrecision,
|
|
54
|
+
}).format(num);
|
|
55
|
+
|
|
56
|
+
case "percentage":
|
|
57
|
+
return new Intl.NumberFormat(locale, {
|
|
58
|
+
style: "percent",
|
|
59
|
+
minimumFractionDigits: effectivePrecision,
|
|
60
|
+
maximumFractionDigits: effectivePrecision,
|
|
61
|
+
}).format(num / 100);
|
|
62
|
+
|
|
63
|
+
case "integer":
|
|
64
|
+
return new Intl.NumberFormat(locale, {
|
|
65
|
+
minimumFractionDigits: 0,
|
|
66
|
+
maximumFractionDigits: 0,
|
|
67
|
+
}).format(num);
|
|
68
|
+
|
|
69
|
+
case "decimal":
|
|
70
|
+
default:
|
|
71
|
+
return new Intl.NumberFormat(locale, {
|
|
72
|
+
minimumFractionDigits: effectivePrecision,
|
|
73
|
+
maximumFractionDigits: effectivePrecision,
|
|
74
|
+
}).format(num);
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
[format, locale, currency, effectivePrecision]
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
const parseValue = useCallback(
|
|
81
|
+
(text: string): number | null => {
|
|
82
|
+
// Remove currency symbols, spaces, thousand separators, and percentage signs
|
|
83
|
+
let cleaned = text.replace(/[^\d.-]/g, "");
|
|
84
|
+
|
|
85
|
+
// Handle negative sign
|
|
86
|
+
if (!allowNegative) {
|
|
87
|
+
cleaned = cleaned.replace(/-/g, "");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const parsed = parseFloat(cleaned);
|
|
91
|
+
|
|
92
|
+
if (isNaN(parsed) || cleaned === "" || cleaned === "-") return null;
|
|
93
|
+
|
|
94
|
+
// Apply min/max constraints
|
|
95
|
+
let constrained = parsed;
|
|
96
|
+
if (min !== undefined && constrained < min) constrained = min;
|
|
97
|
+
if (max !== undefined && constrained > max) constrained = max;
|
|
98
|
+
|
|
99
|
+
return constrained;
|
|
100
|
+
},
|
|
101
|
+
[min, max, allowNegative]
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
const handleChangeText = useCallback(
|
|
105
|
+
(text: string) => {
|
|
106
|
+
// When focused, validate input before allowing it
|
|
107
|
+
if (isFocused) {
|
|
108
|
+
// Remove formatting characters to get raw input
|
|
109
|
+
let cleaned = text.replace(/[^\d.-]/g, "");
|
|
110
|
+
|
|
111
|
+
// Validate negative sign
|
|
112
|
+
if (!allowNegative && cleaned.includes("-")) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Ensure negative sign is only at the start
|
|
117
|
+
if (allowNegative) {
|
|
118
|
+
const negativeCount = (cleaned.match(/-/g) || []).length;
|
|
119
|
+
if (negativeCount > 1 || (cleaned.includes("-") && cleaned.indexOf("-") !== 0)) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Check decimal precision (skip for integer format)
|
|
125
|
+
if (effectivePrecision >= 0) {
|
|
126
|
+
const decimalIndex = cleaned.indexOf(".");
|
|
127
|
+
if (decimalIndex !== -1) {
|
|
128
|
+
const decimalPart = cleaned.substring(decimalIndex + 1);
|
|
129
|
+
|
|
130
|
+
// Prevent typing more decimals than allowed precision
|
|
131
|
+
if (decimalPart.length > effectivePrecision) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Prevent multiple decimal points
|
|
137
|
+
const decimalCount = (cleaned.match(/\./g) || []).length;
|
|
138
|
+
if (decimalCount > 1) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Prevent decimal point for integer format
|
|
143
|
+
if (format === "integer" && cleaned.includes(".")) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
setDisplayValue(text);
|
|
150
|
+
const value = parseValue(text);
|
|
151
|
+
setNumericValue(value);
|
|
152
|
+
onChange?.(value);
|
|
153
|
+
},
|
|
154
|
+
[parseValue, onChange, isFocused, effectivePrecision, allowNegative, format]
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
const handleBlur = useCallback(() => {
|
|
158
|
+
setIsFocused(false);
|
|
159
|
+
if (numericValue !== null) {
|
|
160
|
+
setDisplayValue(formatValue(numericValue));
|
|
161
|
+
} else {
|
|
162
|
+
setDisplayValue("");
|
|
163
|
+
}
|
|
164
|
+
}, [numericValue, formatValue]);
|
|
165
|
+
|
|
166
|
+
const handleFocus = useCallback(() => {
|
|
167
|
+
setIsFocused(true);
|
|
168
|
+
if (numericValue !== null) {
|
|
169
|
+
setDisplayValue(numericValue.toString());
|
|
170
|
+
}
|
|
171
|
+
}, [numericValue]);
|
|
172
|
+
|
|
173
|
+
const setValue = useCallback(
|
|
174
|
+
(value: number | null) => {
|
|
175
|
+
setNumericValue(value);
|
|
176
|
+
if (value !== null) {
|
|
177
|
+
if (isFocused) {
|
|
178
|
+
setDisplayValue(value.toString());
|
|
179
|
+
} else {
|
|
180
|
+
setDisplayValue(formatValue(value));
|
|
181
|
+
}
|
|
182
|
+
} else {
|
|
183
|
+
setDisplayValue("");
|
|
184
|
+
}
|
|
185
|
+
onChange?.(value);
|
|
186
|
+
},
|
|
187
|
+
[isFocused, formatValue, onChange]
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
// Determine keyboard type based on format
|
|
191
|
+
const keyboardType = format === "integer" ? (allowNegative ? ("numeric" as const) : ("number-pad" as const)) : ("decimal-pad" as const);
|
|
192
|
+
|
|
193
|
+
return {
|
|
194
|
+
value: displayValue,
|
|
195
|
+
numericValue,
|
|
196
|
+
onChangeText: handleChangeText,
|
|
197
|
+
onBlur: handleBlur,
|
|
198
|
+
onFocus: handleFocus,
|
|
199
|
+
keyboardType,
|
|
200
|
+
setValue,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createContext, Dispatch, useContext } from "react";
|
|
2
2
|
import { LayoutRectangle } from "react-native";
|
|
3
3
|
import { DropdownMenuStyles } from "./types";
|
|
4
|
-
import { LayoutPosition } from "@/hooks/
|
|
4
|
+
import { LayoutPosition } from "@/hooks/use-relative-position";
|
|
5
5
|
|
|
6
6
|
export interface DropdownMenuContext {
|
|
7
7
|
isOpen: boolean;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { StyleProp, View, ViewStyle } from "react-native";
|
|
3
3
|
import { useDropdownMenu } from "./context";
|
|
4
|
-
import { useRelativePosition } from "@/hooks/
|
|
4
|
+
import { useRelativePosition } from "@/hooks/use-relative-position";
|
|
5
5
|
|
|
6
6
|
export interface DropdownMenuContentProps {
|
|
7
7
|
children?: React.ReactNode;
|
|
@@ -2,7 +2,7 @@ import React, { useState } from "react";
|
|
|
2
2
|
import { LayoutRectangle } from "react-native";
|
|
3
3
|
import { DropdownMenuStyles } from "./types";
|
|
4
4
|
import { DropdownMenuContext } from "./context";
|
|
5
|
-
import { DEFAULT_LAYOUT, DEFAULT_POSITION, LayoutPosition } from "@/hooks/
|
|
5
|
+
import { DEFAULT_LAYOUT, DEFAULT_POSITION, LayoutPosition } from "@/hooks/use-relative-position";
|
|
6
6
|
|
|
7
7
|
export interface DropdownMenuRootProps {
|
|
8
8
|
children?: React.ReactNode;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createContext, Dispatch, useContext } from "react";
|
|
2
2
|
import { PopoverStyles } from "./types";
|
|
3
3
|
import { LayoutRectangle } from "react-native";
|
|
4
|
-
import { LayoutPosition } from "@/hooks/
|
|
4
|
+
import { LayoutPosition } from "@/hooks/use-relative-position";
|
|
5
5
|
|
|
6
6
|
export interface PopoverContext {
|
|
7
7
|
isOpen: boolean;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { StyleProp, View, ViewStyle } from "react-native";
|
|
3
3
|
import { usePopover } from "./context";
|
|
4
|
-
import { useRelativePosition } from "@/hooks/
|
|
4
|
+
import { useRelativePosition } from "@/hooks/use-relative-position";
|
|
5
5
|
|
|
6
6
|
export interface PopoverContentProps {
|
|
7
7
|
children?: React.ReactNode;
|
|
@@ -2,7 +2,7 @@ import React, { useState } from "react";
|
|
|
2
2
|
import { PopoverContext } from "./context";
|
|
3
3
|
import { PopoverStyles } from "./types";
|
|
4
4
|
import { LayoutRectangle } from "react-native";
|
|
5
|
-
import { DEFAULT_LAYOUT, DEFAULT_POSITION, LayoutPosition } from "@/hooks/
|
|
5
|
+
import { DEFAULT_LAYOUT, DEFAULT_POSITION, LayoutPosition } from "@/hooks/use-relative-position";
|
|
6
6
|
|
|
7
7
|
export interface PopoverRootProps {
|
|
8
8
|
children?: React.ReactNode;
|
|
File without changes
|
|
File without changes
|