@xaui/native 0.0.14 → 0.0.16

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,1072 @@
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/fab-menu/index.ts
31
+ var fab_menu_exports = {};
32
+ __export(fab_menu_exports, {
33
+ FabMenu: () => FabMenu,
34
+ FabMenuItem: () => FabMenuItem
35
+ });
36
+ module.exports = __toCommonJS(fab_menu_exports);
37
+
38
+ // src/components/fab-menu/fab-menu.tsx
39
+ var import_react13 = __toESM(require("react"), 1);
40
+ var import_react_native13 = require("react-native");
41
+
42
+ // src/components/fab/fab.tsx
43
+ var import_react11 = __toESM(require("react"), 1);
44
+ var import_react_native10 = require("react-native");
45
+
46
+ // src/components/indicator/indicator.tsx
47
+ var import_react9 = __toESM(require("react"), 1);
48
+ var import_react_native7 = require("react-native");
49
+
50
+ // src/core/theme-context.tsx
51
+ var import_react4 = __toESM(require("react"), 1);
52
+ var import_react_native2 = require("react-native");
53
+ var import_theme = require("@xaui/core/theme");
54
+ var import_palette = require("@xaui/core/palette");
55
+
56
+ // src/core/portal/portal.tsx
57
+ var import_react2 = require("react");
58
+
59
+ // src/core/portal/portal-context.ts
60
+ var import_react = require("react");
61
+ var PortalContext = (0, import_react.createContext)(null);
62
+
63
+ // src/core/portal/portal.tsx
64
+ var portalId = 0;
65
+ var Portal = ({ children }) => {
66
+ const context = (0, import_react2.useContext)(PortalContext);
67
+ const keyRef = (0, import_react2.useRef)(`portal-${++portalId}`);
68
+ (0, import_react2.useLayoutEffect)(() => {
69
+ if (!context) return;
70
+ context.addPortal(keyRef.current, children);
71
+ }, [children, context]);
72
+ (0, import_react2.useEffect)(() => {
73
+ if (!context) return;
74
+ const key = keyRef.current;
75
+ return () => {
76
+ context.removePortal(key);
77
+ };
78
+ }, [context]);
79
+ return null;
80
+ };
81
+
82
+ // src/core/portal/portal-host.tsx
83
+ var import_react3 = __toESM(require("react"), 1);
84
+ var import_react_native = require("react-native");
85
+ var hostStyles = import_react_native.StyleSheet.create({
86
+ container: {
87
+ flex: 1
88
+ }
89
+ });
90
+
91
+ // src/core/theme-context.tsx
92
+ var XUIThemeContext = (0, import_react4.createContext)(null);
93
+
94
+ // src/core/theme-hooks.ts
95
+ var import_react5 = require("react");
96
+ var import_react_native3 = require("react-native");
97
+ function useXUITheme() {
98
+ const theme = (0, import_react5.useContext)(XUIThemeContext);
99
+ if (!theme) {
100
+ throw new Error("useXUITheme must be used within XUIProvider");
101
+ }
102
+ return theme;
103
+ }
104
+
105
+ // src/core/index.ts
106
+ var import_theme2 = require("@xaui/core/theme");
107
+
108
+ // src/components/indicator/circular-activity-indicator.tsx
109
+ var import_react6 = __toESM(require("react"), 1);
110
+ var import_react_native5 = require("react-native");
111
+
112
+ // src/components/indicator/indicator.style.ts
113
+ var import_react_native4 = require("react-native");
114
+ var styles = import_react_native4.StyleSheet.create({
115
+ container: {
116
+ flexShrink: 1,
117
+ flexBasis: "auto",
118
+ width: "100%",
119
+ justifyContent: "center"
120
+ },
121
+ layer: {
122
+ ...import_react_native4.StyleSheet.absoluteFillObject,
123
+ justifyContent: "center",
124
+ alignItems: "center"
125
+ },
126
+ track: {
127
+ width: "100%",
128
+ overflow: "hidden"
129
+ },
130
+ progress: {
131
+ height: "100%"
132
+ }
133
+ });
134
+
135
+ // src/components/indicator/circular-activity-indicator.tsx
136
+ var import_core2 = require("@xaui/core");
137
+ var DURATION = 1800;
138
+ var CircularActivityIndicator = ({
139
+ size = 40,
140
+ themeColor = "primary",
141
+ color,
142
+ backgroundColor,
143
+ disableAnimation = false,
144
+ showTrack = true
145
+ }) => {
146
+ const theme = useXUITheme();
147
+ const { current: timer } = (0, import_react6.useRef)(new import_react_native5.Animated.Value(0));
148
+ const rotation = (0, import_react6.useRef)(void 0);
149
+ const startRotation = import_react6.default.useCallback(() => {
150
+ if (rotation.current) {
151
+ timer.setValue(0);
152
+ import_react_native5.Animated.loop(rotation.current).start();
153
+ }
154
+ }, [timer]);
155
+ const stopRotation = () => {
156
+ if (rotation.current) rotation.current.stop();
157
+ };
158
+ (0, import_react6.useEffect)(() => {
159
+ if (rotation.current === void 0) {
160
+ rotation.current = import_react_native5.Animated.timing(timer, {
161
+ duration: DURATION,
162
+ easing: import_react_native5.Easing.linear,
163
+ useNativeDriver: import_react_native5.Platform.OS !== "web",
164
+ toValue: 1
165
+ });
166
+ }
167
+ if (!disableAnimation) startRotation();
168
+ else stopRotation();
169
+ }, [disableAnimation, startRotation, timer]);
170
+ const safeThemeColor = (0, import_core2.getSafeThemeColor)(themeColor);
171
+ const colorScheme = theme.colors[safeThemeColor];
172
+ const mainColor = color || colorScheme.main;
173
+ const trackColor = showTrack ? backgroundColor ?? colorScheme.background : "transparent";
174
+ const strokeWidth = size * 0.1;
175
+ const frames = 60 * DURATION / 1e3;
176
+ const easing = import_react_native5.Easing.bezier(0.4, 0, 0.7, 1);
177
+ const containerStyle = {
178
+ width: size,
179
+ height: size / 2,
180
+ overflow: "hidden"
181
+ };
182
+ return /* @__PURE__ */ import_react6.default.createElement(import_react_native5.View, { style: [styles.container, { width: size, height: size }] }, /* @__PURE__ */ import_react6.default.createElement(
183
+ import_react_native5.View,
184
+ {
185
+ style: {
186
+ width: size,
187
+ height: size,
188
+ borderRadius: size / 2,
189
+ borderWidth: strokeWidth,
190
+ borderColor: trackColor
191
+ }
192
+ }
193
+ ), /* @__PURE__ */ import_react6.default.createElement(
194
+ import_react_native5.View,
195
+ {
196
+ style: {
197
+ width: size,
198
+ height: size,
199
+ position: "absolute"
200
+ }
201
+ },
202
+ [0, 1].map((index) => {
203
+ const inputRange = Array.from(
204
+ new Array(frames),
205
+ (_, frameIndex) => frameIndex / (frames - 1)
206
+ );
207
+ const outputRange = Array.from(new Array(frames), (_, frameIndex) => {
208
+ let progress = 2 * frameIndex / (frames - 1);
209
+ const rotationValue = index ? +(360 - 15) : -(180 - 15);
210
+ if (progress > 1) {
211
+ progress = 2 - progress;
212
+ }
213
+ const direction = index ? -1 : 1;
214
+ return `${direction * (180 - 30) * easing(progress) + rotationValue}deg`;
215
+ });
216
+ const layerStyle = {
217
+ width: size,
218
+ height: size,
219
+ transform: [
220
+ {
221
+ rotate: timer.interpolate({
222
+ inputRange: [0, 1],
223
+ outputRange: [`${0 + 30 + 15}deg`, `${2 * 360 + 30 + 15}deg`]
224
+ })
225
+ }
226
+ ]
227
+ };
228
+ const viewportStyle = {
229
+ width: size,
230
+ height: size,
231
+ transform: [
232
+ { translateY: index ? -size / 2 : 0 },
233
+ {
234
+ rotate: timer.interpolate({ inputRange, outputRange })
235
+ }
236
+ ]
237
+ };
238
+ const offsetStyle = index ? { top: size / 2 } : null;
239
+ const lineStyle = {
240
+ width: size,
241
+ height: size,
242
+ borderColor: mainColor,
243
+ borderWidth: strokeWidth,
244
+ borderRadius: size / 2
245
+ };
246
+ return /* @__PURE__ */ import_react6.default.createElement(import_react_native5.Animated.View, { key: index, style: [styles.layer] }, /* @__PURE__ */ import_react6.default.createElement(import_react_native5.Animated.View, { style: layerStyle }, /* @__PURE__ */ import_react6.default.createElement(
247
+ import_react_native5.Animated.View,
248
+ {
249
+ style: [containerStyle, offsetStyle],
250
+ collapsable: false
251
+ },
252
+ /* @__PURE__ */ import_react6.default.createElement(import_react_native5.Animated.View, { style: viewportStyle }, /* @__PURE__ */ import_react6.default.createElement(import_react_native5.Animated.View, { style: containerStyle, collapsable: false }, /* @__PURE__ */ import_react6.default.createElement(import_react_native5.Animated.View, { style: lineStyle })))
253
+ )));
254
+ })
255
+ ));
256
+ };
257
+
258
+ // src/components/indicator/linear-activity-indicator.tsx
259
+ var import_react8 = __toESM(require("react"), 1);
260
+ var import_react_native6 = require("react-native");
261
+ var import_react_native_reanimated2 = __toESM(require("react-native-reanimated"), 1);
262
+
263
+ // src/components/indicator/indicator.hook.ts
264
+ var import_react7 = require("react");
265
+ var import_react_native_reanimated = require("react-native-reanimated");
266
+ var useLinearActivityIndicatorAnimation = (disableAnimation) => {
267
+ const primaryTranslateX = (0, import_react_native_reanimated.useSharedValue)(0);
268
+ const primaryScaleX = (0, import_react_native_reanimated.useSharedValue)(0.08);
269
+ const secondaryTranslateX = (0, import_react_native_reanimated.useSharedValue)(0);
270
+ const secondaryScaleX = (0, import_react_native_reanimated.useSharedValue)(0.08);
271
+ (0, import_react7.useEffect)(() => {
272
+ if (disableAnimation) {
273
+ (0, import_react_native_reanimated.cancelAnimation)(primaryTranslateX);
274
+ (0, import_react_native_reanimated.cancelAnimation)(primaryScaleX);
275
+ (0, import_react_native_reanimated.cancelAnimation)(secondaryTranslateX);
276
+ (0, import_react_native_reanimated.cancelAnimation)(secondaryScaleX);
277
+ return;
278
+ }
279
+ primaryTranslateX.value = (0, import_react_native_reanimated.withRepeat)(
280
+ (0, import_react_native_reanimated.withSequence)(
281
+ (0, import_react_native_reanimated.withTiming)(0, { duration: 0 }),
282
+ (0, import_react_native_reanimated.withTiming)(0, { duration: 400, easing: import_react_native_reanimated.Easing.linear }),
283
+ (0, import_react_native_reanimated.withTiming)(0.836714, {
284
+ duration: 783,
285
+ easing: import_react_native_reanimated.Easing.bezier(0.5, 0, 0.701732, 0.495819)
286
+ }),
287
+ (0, import_react_native_reanimated.withTiming)(2.00611, {
288
+ duration: 817,
289
+ easing: import_react_native_reanimated.Easing.bezier(0.302435, 0.381352, 0.55, 0.956352)
290
+ })
291
+ ),
292
+ -1,
293
+ false
294
+ );
295
+ primaryScaleX.value = (0, import_react_native_reanimated.withRepeat)(
296
+ (0, import_react_native_reanimated.withSequence)(
297
+ (0, import_react_native_reanimated.withTiming)(0.08, { duration: 0 }),
298
+ (0, import_react_native_reanimated.withTiming)(0.08, { duration: 733, easing: import_react_native_reanimated.Easing.linear }),
299
+ (0, import_react_native_reanimated.withTiming)(0.661479, {
300
+ duration: 650,
301
+ easing: import_react_native_reanimated.Easing.bezier(0.334731, 0.12482, 0.785844, 1)
302
+ }),
303
+ (0, import_react_native_reanimated.withTiming)(0.08, {
304
+ duration: 617,
305
+ easing: import_react_native_reanimated.Easing.bezier(0.06, 0.11, 0.6, 1)
306
+ })
307
+ ),
308
+ -1,
309
+ false
310
+ );
311
+ secondaryTranslateX.value = (0, import_react_native_reanimated.withRepeat)(
312
+ (0, import_react_native_reanimated.withSequence)(
313
+ (0, import_react_native_reanimated.withTiming)(0, { duration: 0 }),
314
+ (0, import_react_native_reanimated.withTiming)(0.376519, {
315
+ duration: 500,
316
+ easing: import_react_native_reanimated.Easing.bezier(0.15, 0, 0.515058, 0.409685)
317
+ }),
318
+ (0, import_react_native_reanimated.withTiming)(0.843862, {
319
+ duration: 467,
320
+ easing: import_react_native_reanimated.Easing.bezier(0.31033, 0.284058, 0.8, 0.733712)
321
+ }),
322
+ (0, import_react_native_reanimated.withTiming)(1.60278, {
323
+ duration: 1033,
324
+ easing: import_react_native_reanimated.Easing.bezier(0.4, 0.627035, 0.6, 0.902026)
325
+ })
326
+ ),
327
+ -1,
328
+ false
329
+ );
330
+ secondaryScaleX.value = (0, import_react_native_reanimated.withRepeat)(
331
+ (0, import_react_native_reanimated.withSequence)(
332
+ (0, import_react_native_reanimated.withTiming)(0.08, { duration: 0 }),
333
+ (0, import_react_native_reanimated.withTiming)(0.457104, {
334
+ duration: 383,
335
+ easing: import_react_native_reanimated.Easing.bezier(0.205028, 0.057051, 0.57661, 0.453971)
336
+ }),
337
+ (0, import_react_native_reanimated.withTiming)(0.72796, {
338
+ duration: 500,
339
+ easing: import_react_native_reanimated.Easing.bezier(0.152313, 0.196432, 0.648374, 1.00432)
340
+ }),
341
+ (0, import_react_native_reanimated.withTiming)(0.08, {
342
+ duration: 1117,
343
+ easing: import_react_native_reanimated.Easing.bezier(0.257759, -3163e-6, 0.211762, 1.38179)
344
+ })
345
+ ),
346
+ -1,
347
+ false
348
+ );
349
+ return () => {
350
+ (0, import_react_native_reanimated.cancelAnimation)(primaryTranslateX);
351
+ (0, import_react_native_reanimated.cancelAnimation)(primaryScaleX);
352
+ (0, import_react_native_reanimated.cancelAnimation)(secondaryTranslateX);
353
+ (0, import_react_native_reanimated.cancelAnimation)(secondaryScaleX);
354
+ };
355
+ }, [disableAnimation]);
356
+ return {
357
+ primaryTranslateX,
358
+ primaryScaleX,
359
+ secondaryTranslateX,
360
+ secondaryScaleX
361
+ };
362
+ };
363
+
364
+ // src/components/indicator/linear-activity-indicator.tsx
365
+ var LinearActivityIndicator = ({
366
+ size = 4,
367
+ themeColor = "primary",
368
+ color,
369
+ backgroundColor,
370
+ disableAnimation = false,
371
+ borderRadius = 0,
372
+ showTrack = true
373
+ }) => {
374
+ const theme = useXUITheme();
375
+ const { primaryTranslateX, primaryScaleX, secondaryTranslateX, secondaryScaleX } = useLinearActivityIndicatorAnimation(disableAnimation);
376
+ const colorScheme = theme.colors[themeColor];
377
+ const mainColor = color || colorScheme.main;
378
+ const trackColor = showTrack ? backgroundColor ?? colorScheme.background : "transparent";
379
+ const barStyle = {
380
+ ...import_react_native6.StyleSheet.absoluteFillObject,
381
+ backgroundColor: mainColor,
382
+ borderRadius
383
+ };
384
+ const primaryStyle = (0, import_react_native_reanimated2.useAnimatedStyle)(() => ({
385
+ transform: [
386
+ { translateX: `${(primaryTranslateX.value - 1.45167) * 100}%` },
387
+ { scaleX: primaryScaleX.value }
388
+ ]
389
+ }));
390
+ const secondaryStyle = (0, import_react_native_reanimated2.useAnimatedStyle)(() => ({
391
+ transform: [
392
+ { translateX: `${(secondaryTranslateX.value - 0.548889) * 100}%` },
393
+ { scaleX: secondaryScaleX.value }
394
+ ]
395
+ }));
396
+ return /* @__PURE__ */ import_react8.default.createElement(
397
+ import_react_native6.View,
398
+ {
399
+ style: {
400
+ height: size,
401
+ width: "100%",
402
+ borderRadius,
403
+ backgroundColor: trackColor,
404
+ overflow: "hidden"
405
+ }
406
+ },
407
+ /* @__PURE__ */ import_react8.default.createElement(import_react_native_reanimated2.default.View, { style: [barStyle, primaryStyle] }),
408
+ /* @__PURE__ */ import_react8.default.createElement(import_react_native_reanimated2.default.View, { style: [barStyle, secondaryStyle] })
409
+ );
410
+ };
411
+
412
+ // src/components/indicator/indicator.tsx
413
+ var ActivityIndicator = (props) => {
414
+ const {
415
+ variant = "circular",
416
+ themeColor = "primary",
417
+ color,
418
+ backgroundColor,
419
+ size,
420
+ disableAnimation = false,
421
+ borderRadius,
422
+ showTrack
423
+ } = props;
424
+ const theme = useXUITheme();
425
+ const colorScheme = theme.colors[themeColor];
426
+ const mainColor = color ?? colorScheme.main;
427
+ const trackColor = backgroundColor ?? (showTrack ? colorScheme.background : "transparent");
428
+ if (variant === "circular") {
429
+ const circleSize = size ?? 40;
430
+ return /* @__PURE__ */ import_react9.default.createElement(
431
+ import_react_native7.View,
432
+ {
433
+ style: [styles.container, { width: circleSize, height: circleSize }],
434
+ accessible: true,
435
+ accessibilityRole: "progressbar",
436
+ accessibilityLabel: "Loading"
437
+ },
438
+ /* @__PURE__ */ import_react9.default.createElement(
439
+ CircularActivityIndicator,
440
+ {
441
+ size: circleSize,
442
+ themeColor,
443
+ color: mainColor,
444
+ backgroundColor: trackColor,
445
+ disableAnimation
446
+ }
447
+ )
448
+ );
449
+ }
450
+ const linearSize = size ?? 4;
451
+ return /* @__PURE__ */ import_react9.default.createElement(
452
+ import_react_native7.View,
453
+ {
454
+ style: styles.container,
455
+ accessible: true,
456
+ accessibilityRole: "progressbar",
457
+ accessibilityLabel: "Loading"
458
+ },
459
+ /* @__PURE__ */ import_react9.default.createElement(
460
+ LinearActivityIndicator,
461
+ {
462
+ size: linearSize,
463
+ themeColor,
464
+ color: mainColor,
465
+ backgroundColor: trackColor,
466
+ disableAnimation,
467
+ borderRadius,
468
+ showTrack
469
+ }
470
+ )
471
+ );
472
+ };
473
+
474
+ // src/components/fab/fab.style.ts
475
+ var import_react_native8 = require("react-native");
476
+ var styles2 = import_react_native8.StyleSheet.create({
477
+ container: {
478
+ alignSelf: "flex-start"
479
+ },
480
+ fab: {
481
+ flexDirection: "row",
482
+ alignItems: "center",
483
+ justifyContent: "center",
484
+ overflow: "hidden"
485
+ },
486
+ contentContainer: {
487
+ flexDirection: "row",
488
+ alignItems: "center",
489
+ justifyContent: "center",
490
+ gap: 12
491
+ },
492
+ label: {
493
+ fontWeight: "500"
494
+ },
495
+ disabled: {
496
+ opacity: 0.5
497
+ }
498
+ });
499
+
500
+ // src/components/fab/fab.hook.ts
501
+ var import_react10 = require("react");
502
+ var import_core6 = require("@xaui/core");
503
+ function useFabSizeStyles(size) {
504
+ const theme = useXUITheme();
505
+ const sizeStyles = (0, import_react10.useMemo)(() => {
506
+ const sizes = {
507
+ sm: {
508
+ width: 40,
509
+ height: 40,
510
+ borderRadius: theme.borderRadius.lg,
511
+ iconSize: 24,
512
+ fontSize: theme.fontSizes.sm
513
+ },
514
+ md: {
515
+ width: 56,
516
+ height: 56,
517
+ borderRadius: theme.borderRadius.xl,
518
+ iconSize: 24,
519
+ fontSize: theme.fontSizes.md
520
+ },
521
+ lg: {
522
+ width: 96,
523
+ height: 96,
524
+ borderRadius: theme.borderRadius["2xl"],
525
+ iconSize: 36,
526
+ fontSize: theme.fontSizes.lg
527
+ }
528
+ };
529
+ return sizes[size];
530
+ }, [size, theme]);
531
+ const extendedSizeStyles = (0, import_react10.useMemo)(() => {
532
+ const sizes = {
533
+ sm: {
534
+ height: 40,
535
+ borderRadius: theme.borderRadius.lg,
536
+ paddingHorizontal: theme.spacing.md,
537
+ iconSize: 20,
538
+ fontSize: theme.fontSizes.sm
539
+ },
540
+ md: {
541
+ height: 56,
542
+ borderRadius: theme.borderRadius.xl,
543
+ paddingHorizontal: theme.spacing.lg,
544
+ iconSize: 24,
545
+ fontSize: theme.fontSizes.md
546
+ },
547
+ lg: {
548
+ height: 80,
549
+ borderRadius: theme.borderRadius["2xl"],
550
+ paddingHorizontal: theme.spacing.xl,
551
+ iconSize: 28,
552
+ fontSize: theme.fontSizes.lg
553
+ }
554
+ };
555
+ return sizes[size];
556
+ }, [size, theme]);
557
+ return { sizeStyles, extendedSizeStyles };
558
+ }
559
+ function useFabVariantStyles(themeColor, variant, elevation = 0) {
560
+ const theme = useXUITheme();
561
+ const safeThemeColor = (0, import_core6.getSafeThemeColor)(themeColor);
562
+ const colorScheme = theme.colors[safeThemeColor];
563
+ const variantStyles = (0, import_react10.useMemo)(() => {
564
+ const variantMap = {
565
+ solid: {
566
+ backgroundColor: colorScheme.main,
567
+ borderWidth: 0
568
+ },
569
+ flat: {
570
+ backgroundColor: colorScheme.background,
571
+ borderWidth: 0
572
+ },
573
+ outlined: {
574
+ backgroundColor: "transparent",
575
+ borderWidth: theme.borderWidth.md,
576
+ borderColor: colorScheme.main
577
+ }
578
+ };
579
+ const baseStyle = variantMap[variant];
580
+ const shouldApplyElevation = variant !== "outlined";
581
+ const shadowStyles = elevation === 0 ? {} : elevation === 1 ? theme.shadows.sm : elevation === 2 ? theme.shadows.md : elevation === 3 ? theme.shadows.lg : theme.shadows.xl;
582
+ return {
583
+ ...baseStyle,
584
+ ...shouldApplyElevation ? shadowStyles : {},
585
+ ...shouldApplyElevation && elevation > 0 ? { elevation } : {}
586
+ };
587
+ }, [variant, colorScheme, theme, elevation]);
588
+ return variantStyles;
589
+ }
590
+ function useFabIconColor(themeColor, variant) {
591
+ const theme = useXUITheme();
592
+ const safeThemeColor = (0, import_core6.getSafeThemeColor)(themeColor);
593
+ const colorScheme = theme.colors[safeThemeColor];
594
+ const iconColor = (0, import_react10.useMemo)(() => {
595
+ if (variant === "solid") {
596
+ return colorScheme.foreground;
597
+ }
598
+ return colorScheme.main;
599
+ }, [variant, colorScheme]);
600
+ return { iconColor };
601
+ }
602
+ function useFabRadiusValue(radius, fallback) {
603
+ const theme = useXUITheme();
604
+ return (0, import_react10.useMemo)(() => {
605
+ if (!radius) return fallback;
606
+ const radiusMap = {
607
+ none: theme.borderRadius.none,
608
+ sm: theme.borderRadius.sm,
609
+ md: theme.borderRadius.md,
610
+ lg: theme.borderRadius.lg,
611
+ full: theme.borderRadius.full
612
+ };
613
+ return radiusMap[radius];
614
+ }, [fallback, radius, theme]);
615
+ }
616
+
617
+ // src/components/fab/fab.animation.ts
618
+ var import_react_native9 = require("react-native");
619
+ var runFabPressInAnimation = (animatedScale, animatedOpacity) => {
620
+ import_react_native9.Animated.parallel([
621
+ import_react_native9.Animated.spring(animatedScale, {
622
+ toValue: 0.92,
623
+ useNativeDriver: true,
624
+ speed: 50,
625
+ bounciness: 0
626
+ }),
627
+ import_react_native9.Animated.timing(animatedOpacity, {
628
+ toValue: 0.85,
629
+ duration: 100,
630
+ useNativeDriver: true
631
+ })
632
+ ]).start();
633
+ };
634
+ var runFabPressOutAnimation = (animatedScale, animatedOpacity) => {
635
+ import_react_native9.Animated.parallel([
636
+ import_react_native9.Animated.spring(animatedScale, {
637
+ toValue: 1,
638
+ useNativeDriver: true,
639
+ speed: 50,
640
+ bounciness: 0
641
+ }),
642
+ import_react_native9.Animated.timing(animatedOpacity, {
643
+ toValue: 1,
644
+ duration: 100,
645
+ useNativeDriver: true
646
+ })
647
+ ]).start();
648
+ };
649
+
650
+ // src/components/fab/fab.tsx
651
+ var Fab = ({
652
+ icon,
653
+ label,
654
+ themeColor = "primary",
655
+ variant = "solid",
656
+ size = "md",
657
+ radius,
658
+ isDisabled = false,
659
+ isLoading = false,
660
+ elevation = 0,
661
+ customAppearance,
662
+ onPress,
663
+ onLongPress,
664
+ onPressIn,
665
+ onPressOut
666
+ }) => {
667
+ const animatedScale = import_react11.default.useRef(new import_react_native10.Animated.Value(1)).current;
668
+ const animatedOpacity = import_react11.default.useRef(new import_react_native10.Animated.Value(1)).current;
669
+ const { sizeStyles, extendedSizeStyles } = useFabSizeStyles(size);
670
+ const variantStyles = useFabVariantStyles(themeColor, variant, elevation);
671
+ const { iconColor } = useFabIconColor(themeColor, variant);
672
+ const isExtended = !!label;
673
+ const resolvedRadius = useFabRadiusValue(
674
+ radius,
675
+ isExtended ? extendedSizeStyles.borderRadius : sizeStyles.borderRadius
676
+ );
677
+ const handlePressIn = (event) => {
678
+ if (!isDisabled && !isLoading) {
679
+ runFabPressInAnimation(animatedScale, animatedOpacity);
680
+ }
681
+ onPressIn?.(event);
682
+ };
683
+ const handlePressOut = (event) => {
684
+ if (!isDisabled && !isLoading) {
685
+ runFabPressOutAnimation(animatedScale, animatedOpacity);
686
+ }
687
+ onPressOut?.(event);
688
+ };
689
+ const fabDimensionStyles = isExtended ? {
690
+ height: extendedSizeStyles.height,
691
+ borderRadius: resolvedRadius,
692
+ paddingHorizontal: extendedSizeStyles.paddingHorizontal
693
+ } : {
694
+ width: sizeStyles.width,
695
+ height: sizeStyles.height,
696
+ borderRadius: resolvedRadius
697
+ };
698
+ return /* @__PURE__ */ import_react11.default.createElement(import_react_native10.View, { style: [styles2.container, customAppearance?.container] }, /* @__PURE__ */ import_react11.default.createElement(
699
+ import_react_native10.Pressable,
700
+ {
701
+ onPress: isDisabled || isLoading ? void 0 : onPress,
702
+ onLongPress: isDisabled || isLoading ? void 0 : onLongPress,
703
+ onPressIn: handlePressIn,
704
+ onPressOut: handlePressOut,
705
+ disabled: isDisabled || isLoading
706
+ },
707
+ /* @__PURE__ */ import_react11.default.createElement(
708
+ import_react_native10.Animated.View,
709
+ {
710
+ style: [
711
+ styles2.fab,
712
+ fabDimensionStyles,
713
+ variantStyles,
714
+ isDisabled && styles2.disabled,
715
+ {
716
+ transform: [{ scale: animatedScale }],
717
+ opacity: animatedOpacity
718
+ },
719
+ customAppearance?.fab
720
+ ]
721
+ },
722
+ isLoading ? /* @__PURE__ */ import_react11.default.createElement(
723
+ ActivityIndicator,
724
+ {
725
+ variant: "circular",
726
+ themeColor: variant === "solid" ? void 0 : themeColor,
727
+ color: variant === "solid" ? iconColor : void 0,
728
+ size: isExtended ? extendedSizeStyles.iconSize : sizeStyles.iconSize
729
+ }
730
+ ) : /* @__PURE__ */ import_react11.default.createElement(import_react_native10.View, { style: styles2.contentContainer }, icon, isExtended && /* @__PURE__ */ import_react11.default.createElement(
731
+ import_react_native10.Text,
732
+ {
733
+ style: [
734
+ styles2.label,
735
+ {
736
+ fontSize: isExtended ? extendedSizeStyles.fontSize : sizeStyles.fontSize,
737
+ color: iconColor
738
+ }
739
+ ]
740
+ },
741
+ label
742
+ ))
743
+ )
744
+ ));
745
+ };
746
+
747
+ // src/components/fab-menu/fab-menu.style.ts
748
+ var import_react_native11 = require("react-native");
749
+ var styles3 = import_react_native11.StyleSheet.create({
750
+ container: {
751
+ position: "relative",
752
+ alignItems: "flex-end"
753
+ },
754
+ portalRoot: {
755
+ ...import_react_native11.StyleSheet.absoluteFillObject
756
+ },
757
+ overlay: {
758
+ ...import_react_native11.StyleSheet.absoluteFillObject
759
+ },
760
+ overlayPressable: {
761
+ flex: 1
762
+ },
763
+ portalContent: {
764
+ ...import_react_native11.StyleSheet.absoluteFillObject,
765
+ justifyContent: "flex-end",
766
+ alignItems: "flex-end",
767
+ padding: 16
768
+ },
769
+ menuContainer: {
770
+ alignItems: "flex-end",
771
+ marginBottom: 16
772
+ },
773
+ menuItem: {
774
+ marginBottom: 12
775
+ },
776
+ menuItemChip: {
777
+ flexDirection: "row",
778
+ alignItems: "center",
779
+ paddingVertical: 12,
780
+ paddingLeft: 16,
781
+ paddingRight: 20,
782
+ gap: 8
783
+ },
784
+ menuItemLabel: {
785
+ fontWeight: "500"
786
+ },
787
+ disabled: {
788
+ opacity: 0.5
789
+ }
790
+ });
791
+
792
+ // src/components/fab-menu/fab-menu.hook.ts
793
+ var import_react12 = require("react");
794
+ var import_core8 = require("@xaui/core");
795
+ function useFabMenuState(controlledExpanded, onToggle) {
796
+ const [internalExpanded, setInternalExpanded] = (0, import_react12.useState)(false);
797
+ const isControlled = controlledExpanded !== void 0;
798
+ const expanded = isControlled ? controlledExpanded : internalExpanded;
799
+ const toggle = (0, import_react12.useCallback)(() => {
800
+ const next = !expanded;
801
+ if (!isControlled) {
802
+ setInternalExpanded(next);
803
+ }
804
+ onToggle?.(next);
805
+ }, [expanded, isControlled, onToggle]);
806
+ const close = (0, import_react12.useCallback)(() => {
807
+ if (!isControlled) {
808
+ setInternalExpanded(false);
809
+ }
810
+ onToggle?.(false);
811
+ }, [isControlled, onToggle]);
812
+ return { expanded, toggle, close };
813
+ }
814
+ function useFabMenuItemStyles(themeColor) {
815
+ const theme = useXUITheme();
816
+ const safeThemeColor = (0, import_core8.getSafeThemeColor)(themeColor);
817
+ const colorScheme = theme.colors[safeThemeColor];
818
+ const itemStyles = (0, import_react12.useMemo)(() => {
819
+ const chipStyles = {
820
+ backgroundColor: colorScheme.background,
821
+ borderRadius: theme.borderRadius.full,
822
+ color: colorScheme.main,
823
+ fontSize: theme.fontSizes.md
824
+ };
825
+ const iconColor = colorScheme.main;
826
+ return { chipStyles, iconColor };
827
+ }, [colorScheme, theme]);
828
+ return itemStyles;
829
+ }
830
+ function useFabMenuOverlayColor() {
831
+ const theme = useXUITheme();
832
+ return (0, import_react12.useMemo)(() => {
833
+ return theme.mode === "dark" ? "rgba(0, 0, 0, 0.5)" : "rgba(0, 0, 0, 0.3)";
834
+ }, [theme.mode]);
835
+ }
836
+
837
+ // src/components/fab-menu/fab-menu.animation.ts
838
+ var import_react_native12 = require("react-native");
839
+ var runMenuExpandAnimation = (overlayOpacity, itemAnimations) => {
840
+ const itemSequence = itemAnimations.map(
841
+ (anim, index) => import_react_native12.Animated.timing(anim, {
842
+ toValue: 1,
843
+ duration: 150,
844
+ delay: index * 50,
845
+ useNativeDriver: true
846
+ })
847
+ );
848
+ import_react_native12.Animated.parallel([
849
+ import_react_native12.Animated.timing(overlayOpacity, {
850
+ toValue: 1,
851
+ duration: 200,
852
+ useNativeDriver: true
853
+ }),
854
+ import_react_native12.Animated.stagger(50, itemSequence)
855
+ ]).start();
856
+ };
857
+ var runMenuCollapseAnimation = (overlayOpacity, itemAnimations, onComplete) => {
858
+ const reversed = [...itemAnimations].reverse();
859
+ const itemSequence = reversed.map(
860
+ (anim, index) => import_react_native12.Animated.timing(anim, {
861
+ toValue: 0,
862
+ duration: 120,
863
+ delay: index * 30,
864
+ useNativeDriver: true
865
+ })
866
+ );
867
+ import_react_native12.Animated.parallel([
868
+ import_react_native12.Animated.timing(overlayOpacity, {
869
+ toValue: 0,
870
+ duration: 200,
871
+ useNativeDriver: true
872
+ }),
873
+ import_react_native12.Animated.stagger(30, itemSequence)
874
+ ]).start(onComplete);
875
+ };
876
+ var runFabRotateAnimation = (rotateValue, toExpanded) => {
877
+ import_react_native12.Animated.spring(rotateValue, {
878
+ toValue: toExpanded ? 1 : 0,
879
+ useNativeDriver: true,
880
+ speed: 20,
881
+ bounciness: 0
882
+ }).start();
883
+ };
884
+
885
+ // src/components/fab-menu/fab-menu.tsx
886
+ var FabMenu = ({
887
+ icon,
888
+ label,
889
+ expandedIcon,
890
+ children,
891
+ themeColor = "primary",
892
+ variant = "solid",
893
+ size = "md",
894
+ radius,
895
+ elevation = 0,
896
+ isExpanded: controlledExpanded,
897
+ onToggle,
898
+ showOverlay = true,
899
+ customAppearance
900
+ }) => {
901
+ const { expanded, toggle, close } = useFabMenuState(
902
+ controlledExpanded,
903
+ onToggle
904
+ );
905
+ const overlayColor = useFabMenuOverlayColor();
906
+ const [isPortalVisible, setIsPortalVisible] = import_react13.default.useState(expanded);
907
+ const childArray = import_react13.default.Children.toArray(children);
908
+ const overlayOpacity = import_react13.default.useRef(
909
+ new import_react_native13.Animated.Value(expanded ? 1 : 0)
910
+ ).current;
911
+ const rotateValue = import_react13.default.useRef(
912
+ new import_react_native13.Animated.Value(expanded ? 1 : 0)
913
+ ).current;
914
+ const itemAnimationsRef = import_react13.default.useRef(
915
+ childArray.map(() => new import_react_native13.Animated.Value(0))
916
+ );
917
+ const itemAnimations = itemAnimationsRef.current;
918
+ const prevExpanded = import_react13.default.useRef(expanded);
919
+ import_react13.default.useEffect(() => {
920
+ if (itemAnimations.length === childArray.length) return;
921
+ itemAnimationsRef.current = childArray.map(
922
+ (_, index) => itemAnimations[index] ?? new import_react_native13.Animated.Value(expanded ? 1 : 0)
923
+ );
924
+ }, [expanded, itemAnimations, childArray]);
925
+ import_react13.default.useEffect(() => {
926
+ if (prevExpanded.current === expanded) return;
927
+ prevExpanded.current = expanded;
928
+ if (expanded) {
929
+ setIsPortalVisible(true);
930
+ runMenuExpandAnimation(overlayOpacity, itemAnimations);
931
+ runFabRotateAnimation(rotateValue, true);
932
+ } else {
933
+ runMenuCollapseAnimation(overlayOpacity, itemAnimations, () => {
934
+ setIsPortalVisible(false);
935
+ });
936
+ runFabRotateAnimation(rotateValue, false);
937
+ }
938
+ }, [expanded, overlayOpacity, itemAnimations, rotateValue]);
939
+ const rotation = rotateValue.interpolate({
940
+ inputRange: [0, 1],
941
+ outputRange: ["0deg", "45deg"]
942
+ });
943
+ const currentIcon = expanded && expandedIcon ? expandedIcon : icon;
944
+ const renderFabToggle = () => /* @__PURE__ */ import_react13.default.createElement(
945
+ import_react_native13.Animated.View,
946
+ {
947
+ style: {
948
+ alignSelf: "flex-end",
949
+ transform: [{ rotate: expandedIcon ? "0deg" : rotation }]
950
+ }
951
+ },
952
+ /* @__PURE__ */ import_react13.default.createElement(
953
+ Fab,
954
+ {
955
+ icon: currentIcon,
956
+ label,
957
+ themeColor,
958
+ variant,
959
+ size,
960
+ radius,
961
+ elevation,
962
+ onPress: toggle,
963
+ customAppearance: { fab: customAppearance?.fab }
964
+ }
965
+ )
966
+ );
967
+ const renderMenuItems = () => /* @__PURE__ */ import_react13.default.createElement(import_react_native13.View, { style: [styles3.menuContainer, customAppearance?.menuContainer] }, childArray.map((child, index) => {
968
+ const childElement = child;
969
+ const isDisabled = childElement.props?.isDisabled;
970
+ return /* @__PURE__ */ import_react13.default.createElement(
971
+ import_react_native13.Animated.View,
972
+ {
973
+ key: childElement.key ?? index,
974
+ style: [
975
+ styles3.menuItem,
976
+ isDisabled && styles3.disabled,
977
+ {
978
+ opacity: itemAnimations[index],
979
+ transform: [
980
+ {
981
+ translateY: itemAnimations[index].interpolate({
982
+ inputRange: [0, 1],
983
+ outputRange: [20, 0]
984
+ })
985
+ },
986
+ {
987
+ scale: itemAnimations[index].interpolate({
988
+ inputRange: [0, 1],
989
+ outputRange: [0.8, 1]
990
+ })
991
+ }
992
+ ]
993
+ },
994
+ customAppearance?.menuItem
995
+ ]
996
+ },
997
+ import_react13.default.cloneElement(childElement, {
998
+ _onClose: close,
999
+ themeColor: childElement.props?.themeColor ?? themeColor
1000
+ })
1001
+ );
1002
+ }));
1003
+ return /* @__PURE__ */ import_react13.default.createElement(import_react_native13.View, { style: [styles3.container, customAppearance?.container] }, isPortalVisible && /* @__PURE__ */ import_react13.default.createElement(Portal, null, /* @__PURE__ */ import_react13.default.createElement(import_react_native13.View, { style: styles3.portalRoot }, showOverlay && /* @__PURE__ */ import_react13.default.createElement(
1004
+ import_react_native13.Animated.View,
1005
+ {
1006
+ style: [
1007
+ styles3.overlay,
1008
+ { backgroundColor: overlayColor, opacity: overlayOpacity },
1009
+ customAppearance?.overlay
1010
+ ]
1011
+ },
1012
+ /* @__PURE__ */ import_react13.default.createElement(import_react_native13.Pressable, { style: styles3.overlayPressable, onPress: close })
1013
+ ), /* @__PURE__ */ import_react13.default.createElement(import_react_native13.View, { style: styles3.portalContent }, renderMenuItems(), renderFabToggle()))), !isPortalVisible && renderFabToggle());
1014
+ };
1015
+
1016
+ // src/components/fab-menu/fab-menu-item.tsx
1017
+ var import_react14 = __toESM(require("react"), 1);
1018
+ var import_react_native14 = require("react-native");
1019
+ var FabMenuItem = ({
1020
+ icon,
1021
+ label,
1022
+ themeColor = "primary",
1023
+ onPress,
1024
+ isDisabled,
1025
+ _onClose
1026
+ }) => {
1027
+ const itemStyles = useFabMenuItemStyles(themeColor);
1028
+ const renderIcon = (menuIcon) => {
1029
+ if (!import_react14.default.isValidElement(menuIcon)) return menuIcon;
1030
+ return import_react14.default.cloneElement(
1031
+ menuIcon,
1032
+ { color: itemStyles.iconColor }
1033
+ );
1034
+ };
1035
+ return /* @__PURE__ */ import_react14.default.createElement(
1036
+ import_react_native14.Pressable,
1037
+ {
1038
+ style: [
1039
+ styles3.menuItemChip,
1040
+ {
1041
+ backgroundColor: itemStyles.chipStyles.backgroundColor,
1042
+ borderRadius: itemStyles.chipStyles.borderRadius
1043
+ }
1044
+ ],
1045
+ onPress: (event) => {
1046
+ if (isDisabled) return;
1047
+ onPress?.(event);
1048
+ _onClose?.();
1049
+ },
1050
+ disabled: isDisabled
1051
+ },
1052
+ renderIcon(icon),
1053
+ /* @__PURE__ */ import_react14.default.createElement(
1054
+ import_react_native14.Text,
1055
+ {
1056
+ style: [
1057
+ styles3.menuItemLabel,
1058
+ {
1059
+ color: itemStyles.chipStyles.color,
1060
+ fontSize: itemStyles.chipStyles.fontSize
1061
+ }
1062
+ ]
1063
+ },
1064
+ label
1065
+ )
1066
+ );
1067
+ };
1068
+ // Annotate the CommonJS export names for ESM import in node:
1069
+ 0 && (module.exports = {
1070
+ FabMenu,
1071
+ FabMenuItem
1072
+ });