@xaui/native 0.0.30 → 0.0.32

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.
@@ -0,0 +1,151 @@
1
+ import React, { ReactNode } from 'react';
2
+ import { ModalProps, ViewStyle, TextStyle } from 'react-native';
3
+ import { R as Radius } from '../index-BOw6tbkc.js';
4
+
5
+ type DialogSize = 'sm' | 'md' | 'lg' | 'full';
6
+ type DialogPlacement = 'top' | 'center' | 'bottom';
7
+ type DialogBackdrop = 'transparent' | 'blurred' | 'opaque';
8
+ type DialogCustomAppearance = {
9
+ /**
10
+ * Custom style for the overlay backdrop.
11
+ */
12
+ backdrop?: ViewStyle;
13
+ /**
14
+ * Custom style for the dialog container.
15
+ */
16
+ container?: ViewStyle;
17
+ /**
18
+ * Custom style for the dialog header section.
19
+ */
20
+ header?: ViewStyle;
21
+ /**
22
+ * Custom style for the dialog body section.
23
+ */
24
+ body?: ViewStyle;
25
+ /**
26
+ * Custom style for the dialog footer section.
27
+ */
28
+ footer?: ViewStyle;
29
+ /**
30
+ * Custom style for the close button.
31
+ */
32
+ closeButton?: ViewStyle;
33
+ /**
34
+ * Custom style for default title text rendered in DialogHeader.
35
+ */
36
+ headerText?: TextStyle;
37
+ /**
38
+ * Custom style for default body text rendered in DialogBody.
39
+ */
40
+ bodyText?: TextStyle;
41
+ };
42
+ type DialogEvents = {
43
+ /**
44
+ * Called when the dialog requests to close.
45
+ */
46
+ onClose?: () => void;
47
+ /**
48
+ * Called whenever open state changes.
49
+ */
50
+ onOpenChange?: (isOpen: boolean) => void;
51
+ };
52
+ type DialogProps = {
53
+ /**
54
+ * Dialog content.
55
+ */
56
+ children: ReactNode;
57
+ /**
58
+ * Controls visibility.
59
+ * @default false
60
+ */
61
+ isOpen: boolean;
62
+ /**
63
+ * Dialog size preset.
64
+ * @default 'md'
65
+ */
66
+ size?: DialogSize;
67
+ /**
68
+ * Dialog placement on screen.
69
+ * @default 'center'
70
+ */
71
+ placement?: DialogPlacement;
72
+ /**
73
+ * Border radius of the dialog container.
74
+ * @default 'lg'
75
+ */
76
+ radius?: Radius;
77
+ /**
78
+ * Controls backdrop intensity.
79
+ * @default 'opaque'
80
+ */
81
+ backdrop?: DialogBackdrop;
82
+ /**
83
+ * If true, backdrop press closes the dialog.
84
+ * @default true
85
+ */
86
+ closeOnBackdropPress?: boolean;
87
+ /**
88
+ * Whether to hide the backdrop layer.
89
+ * @default false
90
+ */
91
+ hideBackdrop?: boolean;
92
+ /**
93
+ * Modal animation type.
94
+ * @default 'fade'
95
+ */
96
+ animationType?: ModalProps['animationType'];
97
+ /**
98
+ * Disable animation by forcing `animationType="none"`.
99
+ * @default false
100
+ */
101
+ disableAnimation?: boolean;
102
+ /**
103
+ * Extra style for the dialog container.
104
+ */
105
+ style?: ViewStyle;
106
+ /**
107
+ * Custom styles per section.
108
+ */
109
+ customAppearance?: DialogCustomAppearance;
110
+ } & DialogEvents;
111
+ type DialogHeaderProps = {
112
+ children?: ReactNode;
113
+ /**
114
+ * Whether to show a close button in header.
115
+ * @default false
116
+ */
117
+ isClosable?: boolean;
118
+ /**
119
+ * Custom close button element.
120
+ */
121
+ closeButton?: ReactNode;
122
+ /**
123
+ * Optional close callback override for this header.
124
+ */
125
+ onClose?: () => void;
126
+ /**
127
+ * Custom style for header container.
128
+ */
129
+ style?: ViewStyle;
130
+ };
131
+ type DialogBodyProps = {
132
+ children?: ReactNode;
133
+ /**
134
+ * Custom style for body container.
135
+ */
136
+ style?: ViewStyle;
137
+ };
138
+ type DialogFooterProps = {
139
+ children?: ReactNode;
140
+ /**
141
+ * Custom style for footer container.
142
+ */
143
+ style?: ViewStyle;
144
+ };
145
+
146
+ declare const Dialog: React.FC<DialogProps>;
147
+ declare const DialogHeader: React.FC<DialogHeaderProps>;
148
+ declare const DialogBody: React.FC<DialogBodyProps>;
149
+ declare const DialogFooter: React.FC<DialogFooterProps>;
150
+
151
+ export { Dialog, type DialogBackdrop, DialogBody, type DialogBodyProps, DialogFooter, type DialogFooterProps, DialogHeader, type DialogHeaderProps, type DialogPlacement, type DialogProps, type DialogSize };
@@ -0,0 +1,381 @@
1
+ import {
2
+ useBorderRadiusStyles,
3
+ useXUITheme
4
+ } from "../chunk-LTKYHG5V.js";
5
+
6
+ // src/components/dialog/dialog.tsx
7
+ import React, {
8
+ createContext,
9
+ useCallback,
10
+ useContext,
11
+ useEffect,
12
+ useMemo,
13
+ useRef,
14
+ useState
15
+ } from "react";
16
+ import { Modal, Pressable, Text, View } from "react-native";
17
+ import Animated, {
18
+ Easing,
19
+ runOnJS,
20
+ useAnimatedStyle,
21
+ useSharedValue,
22
+ withTiming
23
+ } from "react-native-reanimated";
24
+ import { withOpacity } from "@xaui/core";
25
+ import { CloseIcon } from "@xaui/icons";
26
+
27
+ // src/components/dialog/dialog.style.ts
28
+ import { StyleSheet } from "react-native";
29
+ var styles = StyleSheet.create({
30
+ root: {
31
+ flex: 1
32
+ },
33
+ backdrop: {
34
+ ...StyleSheet.absoluteFillObject
35
+ },
36
+ backdropTransparent: {
37
+ backgroundColor: "transparent"
38
+ },
39
+ backdropBlurred: {
40
+ backgroundColor: "rgba(15, 23, 42, 0.35)"
41
+ },
42
+ backdropOpaque: {
43
+ backgroundColor: "rgba(15, 23, 42, 0.55)"
44
+ },
45
+ placementBase: {
46
+ flex: 1,
47
+ paddingHorizontal: 16
48
+ },
49
+ placementTop: {
50
+ justifyContent: "flex-start",
51
+ paddingTop: 44,
52
+ paddingBottom: 16
53
+ },
54
+ placementCenter: {
55
+ justifyContent: "center",
56
+ paddingVertical: 16
57
+ },
58
+ placementBottom: {
59
+ justifyContent: "flex-end",
60
+ paddingTop: 16,
61
+ paddingBottom: 28
62
+ },
63
+ dialog: {
64
+ width: "100%",
65
+ alignSelf: "center",
66
+ overflow: "hidden",
67
+ borderWidth: 1
68
+ },
69
+ sizeSm: {
70
+ maxWidth: 360
71
+ },
72
+ sizeMd: {
73
+ maxWidth: 520
74
+ },
75
+ sizeLg: {
76
+ maxWidth: 700
77
+ },
78
+ sizeFull: {
79
+ maxWidth: "100%",
80
+ flex: 1
81
+ },
82
+ header: {
83
+ paddingTop: 18,
84
+ paddingBottom: 12,
85
+ paddingHorizontal: 20,
86
+ flexDirection: "row",
87
+ alignItems: "flex-start",
88
+ justifyContent: "space-between",
89
+ gap: 12
90
+ },
91
+ headerContent: {
92
+ flex: 1
93
+ },
94
+ headerText: {
95
+ fontSize: 20,
96
+ lineHeight: 26,
97
+ fontWeight: "700"
98
+ },
99
+ body: {
100
+ paddingHorizontal: 20,
101
+ paddingVertical: 12,
102
+ gap: 10
103
+ },
104
+ bodyText: {
105
+ fontSize: 15,
106
+ lineHeight: 22
107
+ },
108
+ footer: {
109
+ paddingTop: 8,
110
+ paddingBottom: 18,
111
+ paddingHorizontal: 20,
112
+ flexDirection: "row",
113
+ justifyContent: "flex-end",
114
+ alignItems: "center",
115
+ gap: 8
116
+ },
117
+ closeButton: {
118
+ padding: 4,
119
+ borderRadius: 999,
120
+ alignItems: "center",
121
+ justifyContent: "center"
122
+ }
123
+ });
124
+
125
+ // src/components/dialog/dialog.tsx
126
+ var DialogContext = createContext({});
127
+ var sizeStyles = {
128
+ sm: styles.sizeSm,
129
+ md: styles.sizeMd,
130
+ lg: styles.sizeLg,
131
+ full: styles.sizeFull
132
+ };
133
+ var placementStyles = {
134
+ top: styles.placementTop,
135
+ center: styles.placementCenter,
136
+ bottom: styles.placementBottom
137
+ };
138
+ var backdropStyles = {
139
+ transparent: styles.backdropTransparent,
140
+ blurred: styles.backdropBlurred,
141
+ opaque: styles.backdropOpaque
142
+ };
143
+ var ENTER_DURATION = 240;
144
+ var EXIT_DURATION = 180;
145
+ function getTranslateOffset(placement, animationType) {
146
+ if (animationType === "slide") {
147
+ if (placement === "top") return -28;
148
+ if (placement === "bottom") return 28;
149
+ return 18;
150
+ }
151
+ if (placement === "top") return -18;
152
+ if (placement === "bottom") return 18;
153
+ return 10;
154
+ }
155
+ var resolveChildrenContent = (content, textStyle) => {
156
+ if (content === void 0 || content === null) return null;
157
+ if (typeof content === "string" || typeof content === "number") {
158
+ return /* @__PURE__ */ React.createElement(Text, { style: textStyle }, content);
159
+ }
160
+ return content;
161
+ };
162
+ var Dialog = ({
163
+ children,
164
+ isOpen,
165
+ onClose,
166
+ onOpenChange,
167
+ size = "md",
168
+ placement = "center",
169
+ radius = "lg",
170
+ backdrop = "opaque",
171
+ closeOnBackdropPress = true,
172
+ hideBackdrop = false,
173
+ animationType = "fade",
174
+ disableAnimation = false,
175
+ style,
176
+ customAppearance
177
+ }) => {
178
+ const theme = useXUITheme();
179
+ const radiusStyles = useBorderRadiusStyles(radius);
180
+ const [shouldRender, setShouldRender] = useState(isOpen);
181
+ const openRef = useRef(isOpen);
182
+ const shouldAnimate = !disableAnimation && animationType !== "none";
183
+ const initialOffset = getTranslateOffset(placement, animationType);
184
+ const backdropOpacity = useSharedValue(isOpen ? 1 : 0);
185
+ const dialogOpacity = useSharedValue(isOpen ? 1 : 0);
186
+ const dialogTranslate = useSharedValue(isOpen ? 0 : initialOffset);
187
+ const dialogScale = useSharedValue(isOpen ? 1 : placement === "center" ? 0.98 : 1);
188
+ const requestClose = useCallback(() => {
189
+ onOpenChange?.(false);
190
+ onClose?.();
191
+ }, [onClose, onOpenChange]);
192
+ const handleBackdropPress = () => {
193
+ if (closeOnBackdropPress) {
194
+ requestClose();
195
+ }
196
+ };
197
+ const finishClosing = useCallback(() => {
198
+ if (!openRef.current) {
199
+ setShouldRender(false);
200
+ }
201
+ }, []);
202
+ useEffect(() => {
203
+ openRef.current = isOpen;
204
+ }, [isOpen]);
205
+ useEffect(() => {
206
+ if (isOpen && !shouldRender) {
207
+ setShouldRender(true);
208
+ }
209
+ }, [isOpen, shouldRender]);
210
+ useEffect(() => {
211
+ if (!shouldRender) return;
212
+ if (!shouldAnimate) {
213
+ backdropOpacity.value = isOpen ? 1 : 0;
214
+ dialogOpacity.value = isOpen ? 1 : 0;
215
+ dialogTranslate.value = 0;
216
+ dialogScale.value = 1;
217
+ if (!isOpen) {
218
+ setShouldRender(false);
219
+ }
220
+ return;
221
+ }
222
+ const offset = getTranslateOffset(placement, animationType);
223
+ if (isOpen) {
224
+ backdropOpacity.value = 0;
225
+ dialogOpacity.value = 0;
226
+ dialogTranslate.value = offset;
227
+ dialogScale.value = placement === "center" ? 0.98 : 1;
228
+ backdropOpacity.value = withTiming(1, {
229
+ duration: 210,
230
+ easing: Easing.out(Easing.quad)
231
+ });
232
+ dialogOpacity.value = withTiming(1, {
233
+ duration: 220,
234
+ easing: Easing.out(Easing.quad)
235
+ });
236
+ dialogTranslate.value = withTiming(0, {
237
+ duration: ENTER_DURATION,
238
+ easing: Easing.out(Easing.cubic)
239
+ });
240
+ dialogScale.value = withTiming(1, {
241
+ duration: 220,
242
+ easing: Easing.out(Easing.quad)
243
+ });
244
+ return;
245
+ }
246
+ backdropOpacity.value = withTiming(0, {
247
+ duration: 150,
248
+ easing: Easing.in(Easing.quad)
249
+ });
250
+ dialogTranslate.value = withTiming(offset, {
251
+ duration: EXIT_DURATION,
252
+ easing: Easing.in(Easing.cubic)
253
+ });
254
+ dialogScale.value = withTiming(placement === "center" ? 0.98 : 1, {
255
+ duration: 150,
256
+ easing: Easing.in(Easing.quad)
257
+ });
258
+ dialogOpacity.value = withTiming(
259
+ 0,
260
+ {
261
+ duration: EXIT_DURATION,
262
+ easing: Easing.in(Easing.quad)
263
+ },
264
+ (finished) => {
265
+ if (finished) {
266
+ runOnJS(finishClosing)();
267
+ }
268
+ }
269
+ );
270
+ }, [
271
+ animationType,
272
+ backdropOpacity,
273
+ dialogOpacity,
274
+ dialogScale,
275
+ dialogTranslate,
276
+ finishClosing,
277
+ isOpen,
278
+ placement,
279
+ shouldAnimate,
280
+ shouldRender
281
+ ]);
282
+ const backdropAnimatedStyle = useAnimatedStyle(() => ({
283
+ opacity: backdropOpacity.value
284
+ }));
285
+ const dialogAnimatedStyle = useAnimatedStyle(() => ({
286
+ opacity: dialogOpacity.value,
287
+ transform: [{ translateY: dialogTranslate.value }, { scale: dialogScale.value }]
288
+ }));
289
+ const dialogContextValue = useMemo(
290
+ () => ({
291
+ onClose: requestClose,
292
+ customAppearance
293
+ }),
294
+ [customAppearance, requestClose]
295
+ );
296
+ if (!shouldRender) return null;
297
+ return /* @__PURE__ */ React.createElement(
298
+ Modal,
299
+ {
300
+ visible: true,
301
+ transparent: true,
302
+ animationType: "none",
303
+ onRequestClose: requestClose
304
+ },
305
+ /* @__PURE__ */ React.createElement(View, { style: styles.root }, !hideBackdrop && /* @__PURE__ */ React.createElement(
306
+ AnimatedPressable,
307
+ {
308
+ style: [
309
+ styles.backdrop,
310
+ backdropStyles[backdrop],
311
+ backdropAnimatedStyle,
312
+ customAppearance?.backdrop
313
+ ],
314
+ onPress: handleBackdropPress
315
+ }
316
+ ), /* @__PURE__ */ React.createElement(View, { style: [styles.placementBase, placementStyles[placement]] }, /* @__PURE__ */ React.createElement(DialogContext.Provider, { value: dialogContextValue }, /* @__PURE__ */ React.createElement(Pressable, { onPress: (event) => event.stopPropagation() }, /* @__PURE__ */ React.createElement(
317
+ Animated.View,
318
+ {
319
+ style: [
320
+ styles.dialog,
321
+ sizeStyles[size],
322
+ radiusStyles,
323
+ dialogAnimatedStyle,
324
+ {
325
+ backgroundColor: theme.colors.background,
326
+ borderColor: withOpacity(theme.colors.foreground, 0.14)
327
+ },
328
+ theme.shadows.lg,
329
+ customAppearance?.container,
330
+ style
331
+ ]
332
+ },
333
+ children
334
+ )))))
335
+ );
336
+ };
337
+ var AnimatedPressable = Animated.createAnimatedComponent(Pressable);
338
+ var DialogHeader = ({
339
+ children,
340
+ isClosable = false,
341
+ closeButton,
342
+ onClose,
343
+ style
344
+ }) => {
345
+ const theme = useXUITheme();
346
+ const { onClose: contextClose, customAppearance } = useContext(DialogContext);
347
+ const close = onClose ?? contextClose;
348
+ return /* @__PURE__ */ React.createElement(View, { style: [styles.header, customAppearance?.header, style] }, /* @__PURE__ */ React.createElement(View, { style: styles.headerContent }, resolveChildrenContent(children, [
349
+ styles.headerText,
350
+ { color: theme.colors.foreground },
351
+ customAppearance?.headerText
352
+ ])), isClosable && /* @__PURE__ */ React.createElement(
353
+ Pressable,
354
+ {
355
+ accessibilityRole: "button",
356
+ accessibilityLabel: "Close dialog",
357
+ onPress: close,
358
+ style: [styles.closeButton, customAppearance?.closeButton]
359
+ },
360
+ closeButton ?? /* @__PURE__ */ React.createElement(CloseIcon, { size: 22, color: theme.colors.foreground })
361
+ ));
362
+ };
363
+ var DialogBody = ({ children, style }) => {
364
+ const theme = useXUITheme();
365
+ const { customAppearance } = useContext(DialogContext);
366
+ return /* @__PURE__ */ React.createElement(View, { style: [styles.body, customAppearance?.body, style] }, resolveChildrenContent(children, [
367
+ styles.bodyText,
368
+ { color: withOpacity(theme.colors.foreground, 0.9) },
369
+ customAppearance?.bodyText
370
+ ]));
371
+ };
372
+ var DialogFooter = ({ children, style }) => {
373
+ const { customAppearance } = useContext(DialogContext);
374
+ return /* @__PURE__ */ React.createElement(View, { style: [styles.footer, customAppearance?.footer, style] }, children);
375
+ };
376
+ export {
377
+ Dialog,
378
+ DialogBody,
379
+ DialogFooter,
380
+ DialogHeader
381
+ };
@@ -0,0 +1,4 @@
1
+ type ThemeColor = 'primary' | 'secondary' | 'tertiary' | 'danger' | 'warning' | 'success' | 'default';
2
+ type Radius = 'none' | 'sm' | 'md' | 'lg' | 'full';
3
+
4
+ export type { Radius as R, ThemeColor as T };
@@ -0,0 +1,4 @@
1
+ type ThemeColor = 'primary' | 'secondary' | 'tertiary' | 'danger' | 'warning' | 'success' | 'default';
2
+ type Radius = 'none' | 'sm' | 'md' | 'lg' | 'full';
3
+
4
+ export type { Radius as R, ThemeColor as T };
@@ -1,7 +1,6 @@
1
1
  import React, { ReactNode } from 'react';
2
2
  import { ViewStyle, TextStyle } from 'react-native';
3
-
4
- type ThemeColor = 'primary' | 'secondary' | 'tertiary' | 'danger' | 'warning' | 'success' | 'default';
3
+ import { T as ThemeColor } from '../index-DyU3sW3_.cjs';
5
4
 
6
5
  type SnackbarPosition = 'top' | 'bottom';
7
6
  type SnackbarCustomAppearance = {
@@ -1,7 +1,6 @@
1
1
  import React, { ReactNode } from 'react';
2
2
  import { ViewStyle, TextStyle } from 'react-native';
3
-
4
- type ThemeColor = 'primary' | 'secondary' | 'tertiary' | 'danger' | 'warning' | 'success' | 'default';
3
+ import { T as ThemeColor } from '../index-DyU3sW3_.js';
5
4
 
6
5
  type SnackbarPosition = 'top' | 'bottom';
7
6
  type SnackbarCustomAppearance = {