@xaui/native 0.0.13 → 0.0.15

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,470 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/components/bottom-sheet/index.ts
31
+ var bottom_sheet_exports = {};
32
+ __export(bottom_sheet_exports, {
33
+ BottomSheet: () => BottomSheet
34
+ });
35
+ module.exports = __toCommonJS(bottom_sheet_exports);
36
+
37
+ // src/components/bottom-sheet/bottom-sheet.tsx
38
+ var import_react7 = __toESM(require("react"), 1);
39
+ var import_react_native7 = require("react-native");
40
+
41
+ // src/core/portal/portal.tsx
42
+ var import_react2 = require("react");
43
+
44
+ // src/core/portal/portal-context.ts
45
+ var import_react = require("react");
46
+ var PortalContext = (0, import_react.createContext)(null);
47
+
48
+ // src/core/portal/portal.tsx
49
+ var portalId = 0;
50
+ var Portal = ({ children }) => {
51
+ const context = (0, import_react2.useContext)(PortalContext);
52
+ const keyRef = (0, import_react2.useRef)(`portal-${++portalId}`);
53
+ (0, import_react2.useLayoutEffect)(() => {
54
+ if (!context) return;
55
+ context.addPortal(keyRef.current, children);
56
+ }, [children, context]);
57
+ (0, import_react2.useEffect)(() => {
58
+ if (!context) return;
59
+ const key = keyRef.current;
60
+ return () => {
61
+ context.removePortal(key);
62
+ };
63
+ }, [context]);
64
+ return null;
65
+ };
66
+
67
+ // src/components/bottom-sheet/bottom-sheet.hook.ts
68
+ var import_react6 = require("react");
69
+ var import_react_native5 = require("react-native");
70
+
71
+ // src/core/theme-context.tsx
72
+ var import_react4 = __toESM(require("react"), 1);
73
+ var import_react_native2 = require("react-native");
74
+ var import_theme = require("@xaui/core/theme");
75
+ var import_palette = require("@xaui/core/palette");
76
+
77
+ // src/core/portal/portal-host.tsx
78
+ var import_react3 = __toESM(require("react"), 1);
79
+ var import_react_native = require("react-native");
80
+ var hostStyles = import_react_native.StyleSheet.create({
81
+ container: {
82
+ flex: 1
83
+ }
84
+ });
85
+
86
+ // src/core/theme-context.tsx
87
+ var XUIThemeContext = (0, import_react4.createContext)(null);
88
+
89
+ // src/core/theme-hooks.ts
90
+ var import_react5 = require("react");
91
+ var import_react_native3 = require("react-native");
92
+ function useXUITheme() {
93
+ const theme = (0, import_react5.useContext)(XUIThemeContext);
94
+ if (!theme) {
95
+ throw new Error("useXUITheme must be used within XUIProvider");
96
+ }
97
+ return theme;
98
+ }
99
+
100
+ // src/core/index.ts
101
+ var import_theme2 = require("@xaui/core/theme");
102
+
103
+ // src/components/bottom-sheet/bottom-sheet.hook.ts
104
+ var import_core2 = require("@xaui/core");
105
+
106
+ // src/components/bottom-sheet/bottom-sheet.animation.ts
107
+ var import_react_native4 = require("react-native");
108
+ var SPRING_CONFIG = {
109
+ useNativeDriver: true,
110
+ speed: 14,
111
+ bounciness: 4
112
+ };
113
+ var TIMING_CONFIG = {
114
+ duration: 280,
115
+ easing: import_react_native4.Easing.bezier(0.2, 0, 0, 1),
116
+ useNativeDriver: true
117
+ };
118
+ var runOpenAnimation = (translateY, backdropOpacity, targetTranslateY) => {
119
+ const animation = import_react_native4.Animated.parallel([
120
+ import_react_native4.Animated.spring(translateY, {
121
+ ...SPRING_CONFIG,
122
+ toValue: targetTranslateY
123
+ }),
124
+ import_react_native4.Animated.timing(backdropOpacity, {
125
+ ...TIMING_CONFIG,
126
+ toValue: 1
127
+ })
128
+ ]);
129
+ animation.start();
130
+ return animation;
131
+ };
132
+ var runCloseAnimation = (translateY, backdropOpacity, screenHeight, onComplete) => {
133
+ const animation = import_react_native4.Animated.parallel([
134
+ import_react_native4.Animated.timing(translateY, {
135
+ ...TIMING_CONFIG,
136
+ toValue: screenHeight
137
+ }),
138
+ import_react_native4.Animated.timing(backdropOpacity, {
139
+ ...TIMING_CONFIG,
140
+ toValue: 0
141
+ })
142
+ ]);
143
+ animation.start(({ finished }) => {
144
+ if (finished && onComplete) {
145
+ onComplete();
146
+ }
147
+ });
148
+ return animation;
149
+ };
150
+ var runSnapAnimation = (translateY, targetTranslateY) => {
151
+ const animation = import_react_native4.Animated.spring(translateY, {
152
+ ...SPRING_CONFIG,
153
+ toValue: targetTranslateY
154
+ });
155
+ animation.start();
156
+ return animation;
157
+ };
158
+
159
+ // src/components/bottom-sheet/bottom-sheet.hook.ts
160
+ var DISMISS_VELOCITY_THRESHOLD = 0.5;
161
+ var DISMISS_DISTANCE_FRACTION = 0.3;
162
+ var SCREEN_HEIGHT = import_react_native5.Dimensions.get("window").height;
163
+ var getTranslateYForSnap = (snapFraction) => SCREEN_HEIGHT * (1 - snapFraction);
164
+ var useBottomSheetAnimation = ({
165
+ isOpen,
166
+ snapPoints,
167
+ initialSnapIndex,
168
+ enableSwipeToDismiss,
169
+ disableAnimation,
170
+ onClose,
171
+ onSnapChange
172
+ }) => {
173
+ const [shouldRender, setShouldRender] = (0, import_react6.useState)(false);
174
+ const currentSnapIndex = (0, import_react6.useRef)(initialSnapIndex);
175
+ const animationRef = (0, import_react6.useRef)(null);
176
+ const translateY = (0, import_react6.useRef)(new import_react_native5.Animated.Value(SCREEN_HEIGHT)).current;
177
+ const backdropOpacity = (0, import_react6.useRef)(new import_react_native5.Animated.Value(0)).current;
178
+ const sortedSnapPoints = (0, import_react6.useMemo)(
179
+ () => [...snapPoints].sort((a, b) => a - b),
180
+ [snapPoints]
181
+ );
182
+ const snapTranslateValues = (0, import_react6.useMemo)(
183
+ () => sortedSnapPoints.map(getTranslateYForSnap),
184
+ [sortedSnapPoints]
185
+ );
186
+ const open = (0, import_react6.useCallback)(() => {
187
+ setShouldRender(true);
188
+ const targetIndex = Math.min(initialSnapIndex, sortedSnapPoints.length - 1);
189
+ currentSnapIndex.current = targetIndex;
190
+ if (disableAnimation) {
191
+ translateY.setValue(snapTranslateValues[targetIndex]);
192
+ backdropOpacity.setValue(1);
193
+ return;
194
+ }
195
+ translateY.setValue(SCREEN_HEIGHT);
196
+ backdropOpacity.setValue(0);
197
+ animationRef.current?.stop();
198
+ animationRef.current = runOpenAnimation(
199
+ translateY,
200
+ backdropOpacity,
201
+ snapTranslateValues[targetIndex]
202
+ );
203
+ }, [
204
+ initialSnapIndex,
205
+ sortedSnapPoints,
206
+ snapTranslateValues,
207
+ disableAnimation,
208
+ translateY,
209
+ backdropOpacity
210
+ ]);
211
+ const close = (0, import_react6.useCallback)(() => {
212
+ if (disableAnimation) {
213
+ translateY.setValue(SCREEN_HEIGHT);
214
+ backdropOpacity.setValue(0);
215
+ setShouldRender(false);
216
+ onClose?.();
217
+ return;
218
+ }
219
+ animationRef.current?.stop();
220
+ animationRef.current = runCloseAnimation(
221
+ translateY,
222
+ backdropOpacity,
223
+ SCREEN_HEIGHT,
224
+ () => {
225
+ setShouldRender(false);
226
+ onClose?.();
227
+ }
228
+ );
229
+ }, [disableAnimation, translateY, backdropOpacity, onClose]);
230
+ const snapTo = (0, import_react6.useCallback)(
231
+ (index) => {
232
+ const clampedIndex = Math.max(0, Math.min(index, sortedSnapPoints.length - 1));
233
+ currentSnapIndex.current = clampedIndex;
234
+ onSnapChange?.(clampedIndex);
235
+ if (disableAnimation) {
236
+ translateY.setValue(snapTranslateValues[clampedIndex]);
237
+ return;
238
+ }
239
+ animationRef.current?.stop();
240
+ animationRef.current = runSnapAnimation(
241
+ translateY,
242
+ snapTranslateValues[clampedIndex]
243
+ );
244
+ },
245
+ [sortedSnapPoints, snapTranslateValues, disableAnimation, translateY, onSnapChange]
246
+ );
247
+ (0, import_react6.useEffect)(() => {
248
+ if (isOpen) {
249
+ open();
250
+ } else if (shouldRender) {
251
+ close();
252
+ }
253
+ }, [isOpen]);
254
+ const panResponder = (0, import_react6.useMemo)(
255
+ () => import_react_native5.PanResponder.create({
256
+ onStartShouldSetPanResponder: () => true,
257
+ onMoveShouldSetPanResponder: (_, gestureState) => Math.abs(gestureState.dy) > 5,
258
+ onPanResponderMove: (_, gestureState) => {
259
+ const currentTranslate = snapTranslateValues[currentSnapIndex.current];
260
+ const newTranslateY = currentTranslate + gestureState.dy;
261
+ const maxExpanded = snapTranslateValues[snapTranslateValues.length - 1];
262
+ const clamped = Math.max(maxExpanded, newTranslateY);
263
+ translateY.setValue(clamped);
264
+ },
265
+ onPanResponderRelease: (_, gestureState) => {
266
+ const currentTranslate = snapTranslateValues[currentSnapIndex.current];
267
+ const finalPosition = currentTranslate + gestureState.dy;
268
+ if (enableSwipeToDismiss && (gestureState.vy > DISMISS_VELOCITY_THRESHOLD || finalPosition > SCREEN_HEIGHT * (1 - sortedSnapPoints[0] * DISMISS_DISTANCE_FRACTION))) {
269
+ close();
270
+ return;
271
+ }
272
+ if (gestureState.vy < -DISMISS_VELOCITY_THRESHOLD) {
273
+ const nextIndex = Math.min(
274
+ currentSnapIndex.current + 1,
275
+ sortedSnapPoints.length - 1
276
+ );
277
+ snapTo(nextIndex);
278
+ return;
279
+ }
280
+ if (gestureState.vy > DISMISS_VELOCITY_THRESHOLD) {
281
+ const prevIndex = Math.max(currentSnapIndex.current - 1, 0);
282
+ if (prevIndex === currentSnapIndex.current && enableSwipeToDismiss) {
283
+ close();
284
+ return;
285
+ }
286
+ snapTo(prevIndex);
287
+ return;
288
+ }
289
+ let closestIndex = 0;
290
+ let minDistance = Infinity;
291
+ snapTranslateValues.forEach((snapVal, index) => {
292
+ const distance = Math.abs(finalPosition - snapVal);
293
+ if (distance < minDistance) {
294
+ minDistance = distance;
295
+ closestIndex = index;
296
+ }
297
+ });
298
+ snapTo(closestIndex);
299
+ }
300
+ }),
301
+ [
302
+ snapTranslateValues,
303
+ sortedSnapPoints,
304
+ enableSwipeToDismiss,
305
+ translateY,
306
+ close,
307
+ snapTo
308
+ ]
309
+ );
310
+ return {
311
+ shouldRender,
312
+ translateY,
313
+ backdropOpacity,
314
+ panResponder,
315
+ close,
316
+ snapTo,
317
+ screenHeight: SCREEN_HEIGHT
318
+ };
319
+ };
320
+ var useBottomSheetStyles = (themeColor, radius) => {
321
+ const theme = useXUITheme();
322
+ const safeThemeColor = (0, import_core2.getSafeThemeColor)(themeColor);
323
+ const colorScheme = theme.colors[safeThemeColor];
324
+ const sheetStyles = (0, import_react6.useMemo)(
325
+ () => ({
326
+ backgroundColor: colorScheme.background ?? theme.colors.background ?? "#ffffff",
327
+ borderTopLeftRadius: theme.borderRadius[radius],
328
+ borderTopRightRadius: theme.borderRadius[radius]
329
+ }),
330
+ [theme, colorScheme, radius]
331
+ );
332
+ const handleIndicatorColor = (0, import_react6.useMemo)(
333
+ () => theme.mode === "dark" ? `${colorScheme.main}60` : `${colorScheme.main}40`,
334
+ [theme, colorScheme]
335
+ );
336
+ return { sheetStyles, handleIndicatorColor };
337
+ };
338
+
339
+ // src/components/bottom-sheet/bottom-sheet.style.ts
340
+ var import_react_native6 = require("react-native");
341
+ var styles = import_react_native6.StyleSheet.create({
342
+ backdrop: {
343
+ position: "absolute",
344
+ top: 0,
345
+ left: 0,
346
+ right: 0,
347
+ bottom: 0,
348
+ backgroundColor: "rgba(0, 0, 0, 0.5)"
349
+ },
350
+ container: {
351
+ position: "absolute",
352
+ left: 0,
353
+ right: 0,
354
+ bottom: 0
355
+ },
356
+ sheet: {
357
+ overflow: "hidden"
358
+ },
359
+ handle: {
360
+ alignItems: "center",
361
+ justifyContent: "center",
362
+ paddingVertical: 10
363
+ },
364
+ handleIndicator: {
365
+ width: 36,
366
+ height: 4,
367
+ borderRadius: 2
368
+ },
369
+ content: {
370
+ flex: 1
371
+ }
372
+ });
373
+
374
+ // src/components/bottom-sheet/bottom-sheet.tsx
375
+ var BottomSheet = ({
376
+ children,
377
+ isOpen,
378
+ snapPoints = [0.4, 0.9],
379
+ initialSnapIndex = 0,
380
+ themeColor = "default",
381
+ radius = "lg",
382
+ showBackdrop = true,
383
+ closeOnBackdropPress = true,
384
+ enableSwipeToDismiss = true,
385
+ showHandle = true,
386
+ disableAnimation = false,
387
+ style,
388
+ handleContent,
389
+ onClose,
390
+ onSnapChange
391
+ }) => {
392
+ const {
393
+ shouldRender,
394
+ translateY,
395
+ backdropOpacity,
396
+ panResponder,
397
+ close,
398
+ screenHeight
399
+ } = useBottomSheetAnimation({
400
+ isOpen,
401
+ snapPoints,
402
+ initialSnapIndex,
403
+ enableSwipeToDismiss,
404
+ disableAnimation,
405
+ onClose,
406
+ onSnapChange
407
+ });
408
+ const { sheetStyles, handleIndicatorColor } = useBottomSheetStyles(
409
+ themeColor,
410
+ radius
411
+ );
412
+ if (!shouldRender) {
413
+ return null;
414
+ }
415
+ const handleBackdropPress = () => {
416
+ if (closeOnBackdropPress) {
417
+ close();
418
+ }
419
+ };
420
+ return /* @__PURE__ */ import_react7.default.createElement(Portal, null, showBackdrop && /* @__PURE__ */ import_react7.default.createElement(
421
+ import_react_native7.Animated.View,
422
+ {
423
+ style: [styles.backdrop, { opacity: backdropOpacity }]
424
+ },
425
+ /* @__PURE__ */ import_react7.default.createElement(
426
+ import_react_native7.Pressable,
427
+ {
428
+ style: styles.backdrop,
429
+ onPress: handleBackdropPress
430
+ }
431
+ )
432
+ ), /* @__PURE__ */ import_react7.default.createElement(
433
+ import_react_native7.Animated.View,
434
+ {
435
+ style: [
436
+ styles.container,
437
+ {
438
+ height: screenHeight,
439
+ transform: [{ translateY }]
440
+ }
441
+ ]
442
+ },
443
+ /* @__PURE__ */ import_react7.default.createElement(
444
+ import_react_native7.View,
445
+ {
446
+ style: [
447
+ styles.sheet,
448
+ { height: screenHeight },
449
+ sheetStyles,
450
+ style
451
+ ],
452
+ ...panResponder.panHandlers
453
+ },
454
+ showHandle && /* @__PURE__ */ import_react7.default.createElement(import_react_native7.View, { style: styles.handle }, handleContent ?? /* @__PURE__ */ import_react7.default.createElement(
455
+ import_react_native7.View,
456
+ {
457
+ style: [
458
+ styles.handleIndicator,
459
+ { backgroundColor: handleIndicatorColor }
460
+ ]
461
+ }
462
+ )),
463
+ /* @__PURE__ */ import_react7.default.createElement(import_react_native7.View, { style: styles.content }, children)
464
+ )
465
+ ));
466
+ };
467
+ // Annotate the CommonJS export names for ESM import in node:
468
+ 0 && (module.exports = {
469
+ BottomSheet
470
+ });
@@ -0,0 +1,84 @@
1
+ import React, { ReactNode } from 'react';
2
+ import { ViewStyle } from 'react-native';
3
+ import { T as ThemeColor, R as Radius } from '../index-BOw6tbkc.cjs';
4
+
5
+ type BottomSheetSnapPoint = number | string;
6
+ type BottomSheetProps = {
7
+ /**
8
+ * Content to render inside the bottom sheet.
9
+ */
10
+ children: ReactNode;
11
+ /**
12
+ * Whether the bottom sheet is visible.
13
+ * @default false
14
+ */
15
+ isOpen: boolean;
16
+ /**
17
+ * Snap points as fractions of screen height (0 to 1).
18
+ * First value is the initial collapsed height, subsequent values are expanded heights.
19
+ * @default [0.4, 0.9]
20
+ */
21
+ snapPoints?: [number, ...number[]];
22
+ /**
23
+ * Index of the initial snap point when the sheet opens.
24
+ * @default 0
25
+ */
26
+ initialSnapIndex?: number;
27
+ /**
28
+ * Theme color for the handle bar indicator.
29
+ * @default 'default'
30
+ */
31
+ themeColor?: ThemeColor;
32
+ /**
33
+ * Border radius of the top corners.
34
+ * @default 'lg'
35
+ */
36
+ radius?: Radius;
37
+ /**
38
+ * Whether to show the backdrop overlay.
39
+ * @default true
40
+ */
41
+ showBackdrop?: boolean;
42
+ /**
43
+ * Whether to close the sheet when tapping the backdrop.
44
+ * @default true
45
+ */
46
+ closeOnBackdropPress?: boolean;
47
+ /**
48
+ * Whether the sheet can be dismissed by swiping down.
49
+ * @default true
50
+ */
51
+ enableSwipeToDismiss?: boolean;
52
+ /**
53
+ * Whether to show the drag handle indicator.
54
+ * @default true
55
+ */
56
+ showHandle?: boolean;
57
+ /**
58
+ * Disable all animations.
59
+ * @default false
60
+ */
61
+ disableAnimation?: boolean;
62
+ /**
63
+ * Custom style for the sheet container.
64
+ */
65
+ style?: ViewStyle;
66
+ /**
67
+ * Custom content to render as the handle.
68
+ */
69
+ handleContent?: ReactNode;
70
+ } & BottomSheetEvents;
71
+ type BottomSheetEvents = {
72
+ /**
73
+ * Called when the sheet is closed.
74
+ */
75
+ onClose?: () => void;
76
+ /**
77
+ * Called when the snap point changes.
78
+ */
79
+ onSnapChange?: (index: number) => void;
80
+ };
81
+
82
+ declare const BottomSheet: React.FC<BottomSheetProps>;
83
+
84
+ export { BottomSheet, type BottomSheetEvents, type BottomSheetProps, type BottomSheetSnapPoint };
@@ -0,0 +1,84 @@
1
+ import React, { ReactNode } from 'react';
2
+ import { ViewStyle } from 'react-native';
3
+ import { T as ThemeColor, R as Radius } from '../index-BOw6tbkc.js';
4
+
5
+ type BottomSheetSnapPoint = number | string;
6
+ type BottomSheetProps = {
7
+ /**
8
+ * Content to render inside the bottom sheet.
9
+ */
10
+ children: ReactNode;
11
+ /**
12
+ * Whether the bottom sheet is visible.
13
+ * @default false
14
+ */
15
+ isOpen: boolean;
16
+ /**
17
+ * Snap points as fractions of screen height (0 to 1).
18
+ * First value is the initial collapsed height, subsequent values are expanded heights.
19
+ * @default [0.4, 0.9]
20
+ */
21
+ snapPoints?: [number, ...number[]];
22
+ /**
23
+ * Index of the initial snap point when the sheet opens.
24
+ * @default 0
25
+ */
26
+ initialSnapIndex?: number;
27
+ /**
28
+ * Theme color for the handle bar indicator.
29
+ * @default 'default'
30
+ */
31
+ themeColor?: ThemeColor;
32
+ /**
33
+ * Border radius of the top corners.
34
+ * @default 'lg'
35
+ */
36
+ radius?: Radius;
37
+ /**
38
+ * Whether to show the backdrop overlay.
39
+ * @default true
40
+ */
41
+ showBackdrop?: boolean;
42
+ /**
43
+ * Whether to close the sheet when tapping the backdrop.
44
+ * @default true
45
+ */
46
+ closeOnBackdropPress?: boolean;
47
+ /**
48
+ * Whether the sheet can be dismissed by swiping down.
49
+ * @default true
50
+ */
51
+ enableSwipeToDismiss?: boolean;
52
+ /**
53
+ * Whether to show the drag handle indicator.
54
+ * @default true
55
+ */
56
+ showHandle?: boolean;
57
+ /**
58
+ * Disable all animations.
59
+ * @default false
60
+ */
61
+ disableAnimation?: boolean;
62
+ /**
63
+ * Custom style for the sheet container.
64
+ */
65
+ style?: ViewStyle;
66
+ /**
67
+ * Custom content to render as the handle.
68
+ */
69
+ handleContent?: ReactNode;
70
+ } & BottomSheetEvents;
71
+ type BottomSheetEvents = {
72
+ /**
73
+ * Called when the sheet is closed.
74
+ */
75
+ onClose?: () => void;
76
+ /**
77
+ * Called when the snap point changes.
78
+ */
79
+ onSnapChange?: (index: number) => void;
80
+ };
81
+
82
+ declare const BottomSheet: React.FC<BottomSheetProps>;
83
+
84
+ export { BottomSheet, type BottomSheetEvents, type BottomSheetProps, type BottomSheetSnapPoint };
@@ -0,0 +1,7 @@
1
+ import {
2
+ BottomSheet
3
+ } from "../chunk-GAOI4KIV.js";
4
+ import "../chunk-NBRASCX4.js";
5
+ export {
6
+ BottomSheet
7
+ };