@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.
package/dist/index.cjs CHANGED
@@ -38,8 +38,14 @@ __export(src_exports, {
38
38
  AvatarGroup: () => AvatarGroup,
39
39
  Badge: () => Badge,
40
40
  BottomSheet: () => BottomSheet,
41
+ Chip: () => Chip,
42
+ ChipGroup: () => ChipGroup,
43
+ ChipItem: () => ChipItem,
41
44
  DatePicker: () => DatePicker,
42
45
  Divider: () => Divider,
46
+ Fab: () => Fab,
47
+ FabMenu: () => FabMenu,
48
+ FabMenuItem: () => FabMenuItem,
43
49
  Typography: () => Typography
44
50
  });
45
51
  module.exports = __toCommonJS(src_exports);
@@ -1442,7 +1448,7 @@ var useAutocompleteVariantStyles = (themeColor, variant, isInvalid) => {
1442
1448
  if ((variant === "outlined" || variant === "faded") && themeColor === "default") {
1443
1449
  borderColor = import_palette2.colors.gray[300];
1444
1450
  }
1445
- const styles13 = {
1451
+ const styles16 = {
1446
1452
  outlined: {
1447
1453
  backgroundColor: "transparent",
1448
1454
  borderWidth: theme.borderWidth.md,
@@ -1467,7 +1473,7 @@ var useAutocompleteVariantStyles = (themeColor, variant, isInvalid) => {
1467
1473
  borderColor
1468
1474
  }
1469
1475
  };
1470
- return styles13[variant];
1476
+ return styles16[variant];
1471
1477
  }, [variant, theme, colorScheme, isInvalid, themeColor]);
1472
1478
  };
1473
1479
  var useAutocompleteLabelStyle = (themeColor, isInvalid, labelSize) => {
@@ -4134,7 +4140,7 @@ var useTypographyVariantStyles = (variant) => {
4134
4140
  fontWeight: theme.fontWeights.normal
4135
4141
  };
4136
4142
  }
4137
- const styles13 = {
4143
+ const styles16 = {
4138
4144
  caption: {
4139
4145
  fontFamily: theme.fontFamilies.body,
4140
4146
  fontSize: theme.fontSizes.xs,
@@ -4186,7 +4192,7 @@ var useTypographyVariantStyles = (variant) => {
4186
4192
  fontWeight: theme.fontWeights.normal
4187
4193
  }
4188
4194
  };
4189
- return styles13[variant];
4195
+ return styles16[variant];
4190
4196
  }, [theme, variant]);
4191
4197
  return variantStyles;
4192
4198
  };
@@ -4226,17 +4232,517 @@ var Typography = ({
4226
4232
  );
4227
4233
  };
4228
4234
 
4229
- // src/components/bottom-sheet/bottom-sheet.tsx
4235
+ // src/components/chip/chip.tsx
4230
4236
  var import_react44 = __toESM(require("react"), 1);
4231
- var import_react_native41 = require("react-native");
4237
+ var import_react_native39 = require("react-native");
4232
4238
 
4233
- // src/components/bottom-sheet/bottom-sheet.hook.ts
4239
+ // src/components/chip/chip.style.ts
4240
+ var import_react_native38 = require("react-native");
4241
+ var styles12 = import_react_native38.StyleSheet.create({
4242
+ chip: {
4243
+ flexDirection: "row",
4244
+ alignItems: "center",
4245
+ alignSelf: "flex-start"
4246
+ },
4247
+ text: {
4248
+ fontWeight: "500",
4249
+ includeFontPadding: false,
4250
+ textAlignVertical: "center"
4251
+ },
4252
+ disabled: {
4253
+ opacity: 0.5
4254
+ },
4255
+ avatar: {
4256
+ marginRight: 4
4257
+ },
4258
+ startContent: {
4259
+ marginRight: 4
4260
+ },
4261
+ endContent: {
4262
+ marginLeft: 4
4263
+ },
4264
+ closeButton: {
4265
+ marginLeft: 4,
4266
+ alignItems: "center",
4267
+ justifyContent: "center"
4268
+ },
4269
+ dot: {
4270
+ borderRadius: 9999,
4271
+ marginRight: 6
4272
+ },
4273
+ groupContainer: {
4274
+ flexDirection: "row",
4275
+ flexWrap: "wrap"
4276
+ }
4277
+ });
4278
+
4279
+ // src/components/chip/chip.hook.ts
4234
4280
  var import_react43 = require("react");
4235
- var import_react_native39 = require("react-native");
4236
- var import_core32 = require("@xaui/core");
4281
+ var import_core31 = require("@xaui/core");
4282
+ var sizeMap3 = {
4283
+ sm: { height: 32, paddingH: 12, fontSize: 13 },
4284
+ md: { height: 40, paddingH: 16, fontSize: 15 },
4285
+ lg: { height: 44, paddingH: 18, fontSize: 17 }
4286
+ };
4287
+ var dotSizeMap = {
4288
+ sm: 8,
4289
+ md: 10,
4290
+ lg: 11
4291
+ };
4292
+ var closeSizeMap = {
4293
+ sm: 14,
4294
+ md: 16,
4295
+ lg: 17
4296
+ };
4297
+ function useChipSizeStyles(size) {
4298
+ return (0, import_react43.useMemo)(() => {
4299
+ const { height, paddingH, fontSize } = sizeMap3[size];
4300
+ return { height, paddingHorizontal: paddingH, fontSize };
4301
+ }, [size]);
4302
+ }
4303
+ function useChipDotSize(size) {
4304
+ return (0, import_react43.useMemo)(() => dotSizeMap[size], [size]);
4305
+ }
4306
+ function useChipCloseSize(size) {
4307
+ return (0, import_react43.useMemo)(() => closeSizeMap[size], [size]);
4308
+ }
4309
+ function useChipRadiusStyles(radius, height) {
4310
+ const theme = useXUITheme();
4311
+ return (0, import_react43.useMemo)(() => {
4312
+ if (radius === "full") {
4313
+ return { borderRadius: height / 2 };
4314
+ }
4315
+ return { borderRadius: theme.borderRadius[radius] };
4316
+ }, [height, radius, theme.borderRadius]);
4317
+ }
4318
+ function useChipVariantStyles(themeColor, variant) {
4319
+ const theme = useXUITheme();
4320
+ const safeColor = (0, import_core31.getSafeThemeColor)(themeColor);
4321
+ const colorScheme = theme.colors[safeColor];
4322
+ return (0, import_react43.useMemo)(() => {
4323
+ switch (variant) {
4324
+ case "bordered":
4325
+ return {
4326
+ backgroundColor: "transparent",
4327
+ color: colorScheme.main,
4328
+ borderWidth: 2,
4329
+ borderColor: colorScheme.main
4330
+ };
4331
+ case "light":
4332
+ return {
4333
+ backgroundColor: "transparent",
4334
+ color: colorScheme.main
4335
+ };
4336
+ case "flat":
4337
+ return {
4338
+ backgroundColor: colorScheme.background,
4339
+ color: colorScheme.main
4340
+ };
4341
+ case "faded":
4342
+ return {
4343
+ backgroundColor: (0, import_core31.withOpacity)(colorScheme.background, 0.7),
4344
+ color: colorScheme.main,
4345
+ borderWidth: 1,
4346
+ borderColor: (0, import_core31.withOpacity)(colorScheme.main, 0.3)
4347
+ };
4348
+ case "shadow":
4349
+ return {
4350
+ backgroundColor: colorScheme.main,
4351
+ color: colorScheme.foreground,
4352
+ shadow: theme.shadows.sm
4353
+ };
4354
+ case "dot":
4355
+ return {
4356
+ backgroundColor: colorScheme.background,
4357
+ color: colorScheme.main,
4358
+ dotColor: colorScheme.main
4359
+ };
4360
+ case "solid":
4361
+ default:
4362
+ return {
4363
+ backgroundColor: colorScheme.main,
4364
+ color: colorScheme.foreground
4365
+ };
4366
+ }
4367
+ }, [colorScheme, theme, variant]);
4368
+ }
4369
+
4370
+ // src/components/chip/chip.tsx
4371
+ var Chip = ({
4372
+ children,
4373
+ variant = "solid",
4374
+ themeColor = "default",
4375
+ size = "md",
4376
+ radius = "full",
4377
+ avatar,
4378
+ startContent,
4379
+ endContent,
4380
+ isDisabled = false,
4381
+ customAppearance,
4382
+ onClose,
4383
+ onPress
4384
+ }) => {
4385
+ const [isClosed, setIsClosed] = import_react44.default.useState(false);
4386
+ const [isClosing, setIsClosing] = import_react44.default.useState(false);
4387
+ const sizeStyles = useChipSizeStyles(size);
4388
+ const radiusStyles = useChipRadiusStyles(radius, sizeStyles.height);
4389
+ const variantStyles = useChipVariantStyles(themeColor, variant);
4390
+ const dotSize = useChipDotSize(size);
4391
+ const closeSize = useChipCloseSize(size);
4392
+ const isDotVariant = variant === "dot";
4393
+ const hasClose = onClose !== void 0;
4394
+ const isInteractive = onPress !== void 0 || hasClose;
4395
+ const scale = import_react44.default.useRef(new import_react_native39.Animated.Value(1)).current;
4396
+ const opacity = import_react44.default.useRef(new import_react_native39.Animated.Value(1)).current;
4397
+ const isClosingRef = import_react44.default.useRef(false);
4398
+ const colorProgress = import_react44.default.useRef(new import_react_native39.Animated.Value(1)).current;
4399
+ const targetBackgroundColor = variantStyles.backgroundColor ?? "transparent";
4400
+ const targetBorderColor = variantStyles.borderColor ?? "transparent";
4401
+ const targetTextColor = variantStyles.color ?? "#000000";
4402
+ const targetDotColor = variantStyles.dotColor ?? targetTextColor;
4403
+ const previousColorsRef = import_react44.default.useRef({
4404
+ backgroundColor: targetBackgroundColor,
4405
+ borderColor: targetBorderColor,
4406
+ textColor: targetTextColor,
4407
+ dotColor: targetDotColor
4408
+ });
4409
+ import_react44.default.useEffect(() => {
4410
+ if (previousColorsRef.current.backgroundColor === targetBackgroundColor && previousColorsRef.current.borderColor === targetBorderColor && previousColorsRef.current.textColor === targetTextColor && previousColorsRef.current.dotColor === targetDotColor) {
4411
+ return;
4412
+ }
4413
+ colorProgress.setValue(0);
4414
+ import_react_native39.Animated.timing(colorProgress, {
4415
+ toValue: 1,
4416
+ duration: 180,
4417
+ easing: import_react_native39.Easing.out(import_react_native39.Easing.cubic),
4418
+ useNativeDriver: false
4419
+ }).start(() => {
4420
+ previousColorsRef.current = {
4421
+ backgroundColor: targetBackgroundColor,
4422
+ borderColor: targetBorderColor,
4423
+ textColor: targetTextColor,
4424
+ dotColor: targetDotColor
4425
+ };
4426
+ });
4427
+ }, [
4428
+ colorProgress,
4429
+ targetBackgroundColor,
4430
+ targetBorderColor,
4431
+ targetTextColor,
4432
+ targetDotColor
4433
+ ]);
4434
+ const animatedBackgroundColor = colorProgress.interpolate({
4435
+ inputRange: [0, 1],
4436
+ outputRange: [
4437
+ previousColorsRef.current.backgroundColor,
4438
+ targetBackgroundColor
4439
+ ]
4440
+ });
4441
+ const animatedBorderColor = colorProgress.interpolate({
4442
+ inputRange: [0, 1],
4443
+ outputRange: [previousColorsRef.current.borderColor, targetBorderColor]
4444
+ });
4445
+ const animatedTextColor = colorProgress.interpolate({
4446
+ inputRange: [0, 1],
4447
+ outputRange: [previousColorsRef.current.textColor, targetTextColor]
4448
+ });
4449
+ const animatedDotColor = colorProgress.interpolate({
4450
+ inputRange: [0, 1],
4451
+ outputRange: [previousColorsRef.current.dotColor, targetDotColor]
4452
+ });
4453
+ const handlePressIn = import_react44.default.useCallback(() => {
4454
+ if (!isInteractive || isDisabled || isClosing || hasClose) return;
4455
+ import_react_native39.Animated.timing(scale, {
4456
+ toValue: 0.97,
4457
+ duration: 90,
4458
+ easing: import_react_native39.Easing.out(import_react_native39.Easing.cubic),
4459
+ useNativeDriver: true
4460
+ }).start();
4461
+ }, [hasClose, isInteractive, isClosing, isDisabled, scale]);
4462
+ const handlePressOut = import_react44.default.useCallback(() => {
4463
+ if (!isInteractive || isDisabled || isClosing || hasClose) return;
4464
+ import_react_native39.Animated.timing(scale, {
4465
+ toValue: 1,
4466
+ duration: 120,
4467
+ easing: import_react_native39.Easing.out(import_react_native39.Easing.cubic),
4468
+ useNativeDriver: true
4469
+ }).start();
4470
+ }, [hasClose, isInteractive, isClosing, isDisabled, scale]);
4471
+ const handleChipPress = import_react44.default.useCallback(() => {
4472
+ if (isDisabled || isClosing || isClosingRef.current) return;
4473
+ if (hasClose && onClose) {
4474
+ isClosingRef.current = true;
4475
+ setIsClosing(true);
4476
+ import_react_native39.Animated.parallel([
4477
+ import_react_native39.Animated.timing(opacity, {
4478
+ toValue: 0,
4479
+ duration: 180,
4480
+ easing: import_react_native39.Easing.in(import_react_native39.Easing.quad),
4481
+ useNativeDriver: true
4482
+ }),
4483
+ import_react_native39.Animated.timing(scale, {
4484
+ toValue: 0.88,
4485
+ duration: 180,
4486
+ easing: import_react_native39.Easing.in(import_react_native39.Easing.quad),
4487
+ useNativeDriver: true
4488
+ })
4489
+ ]).start(() => {
4490
+ setIsClosed(true);
4491
+ onClose();
4492
+ setIsClosing(false);
4493
+ isClosingRef.current = false;
4494
+ });
4495
+ return;
4496
+ }
4497
+ onPress?.();
4498
+ }, [hasClose, isClosing, isDisabled, onClose, onPress, opacity, scale]);
4499
+ if (isClosed) {
4500
+ return null;
4501
+ }
4502
+ const chipContent = /* @__PURE__ */ import_react44.default.createElement(import_react_native39.Animated.View, { style: { transform: [{ scale }], opacity } }, /* @__PURE__ */ import_react44.default.createElement(
4503
+ import_react_native39.Animated.View,
4504
+ {
4505
+ style: [
4506
+ styles12.chip,
4507
+ {
4508
+ height: sizeStyles.height,
4509
+ paddingHorizontal: sizeStyles.paddingHorizontal,
4510
+ backgroundColor: animatedBackgroundColor,
4511
+ borderWidth: variantStyles.borderWidth,
4512
+ borderColor: animatedBorderColor
4513
+ },
4514
+ radiusStyles,
4515
+ variantStyles.shadow,
4516
+ isDisabled && styles12.disabled,
4517
+ customAppearance?.container
4518
+ ],
4519
+ accessible: true,
4520
+ accessibilityRole: "text"
4521
+ },
4522
+ isDotVariant && /* @__PURE__ */ import_react44.default.createElement(
4523
+ import_react_native39.Animated.View,
4524
+ {
4525
+ style: [
4526
+ styles12.dot,
4527
+ {
4528
+ width: dotSize,
4529
+ height: dotSize,
4530
+ backgroundColor: animatedDotColor
4531
+ },
4532
+ customAppearance?.dot
4533
+ ]
4534
+ }
4535
+ ),
4536
+ avatar && /* @__PURE__ */ import_react44.default.createElement(import_react_native39.View, { style: styles12.avatar }, avatar),
4537
+ startContent && !avatar && /* @__PURE__ */ import_react44.default.createElement(import_react_native39.View, { style: styles12.startContent }, startContent),
4538
+ /* @__PURE__ */ import_react44.default.createElement(
4539
+ import_react_native39.Animated.Text,
4540
+ {
4541
+ style: [
4542
+ styles12.text,
4543
+ { fontSize: sizeStyles.fontSize, color: animatedTextColor },
4544
+ customAppearance?.text
4545
+ ]
4546
+ },
4547
+ children
4548
+ ),
4549
+ endContent && !hasClose && /* @__PURE__ */ import_react44.default.createElement(import_react_native39.View, { style: styles12.endContent }, endContent),
4550
+ hasClose && /* @__PURE__ */ import_react44.default.createElement(
4551
+ import_react_native39.View,
4552
+ {
4553
+ style: [
4554
+ styles12.closeButton,
4555
+ { width: closeSize, height: closeSize },
4556
+ customAppearance?.closeButton
4557
+ ]
4558
+ },
4559
+ /* @__PURE__ */ import_react44.default.createElement(
4560
+ import_react_native39.Animated.Text,
4561
+ {
4562
+ style: {
4563
+ fontSize: closeSize - 2,
4564
+ color: animatedTextColor,
4565
+ lineHeight: closeSize
4566
+ }
4567
+ },
4568
+ "\u2715"
4569
+ )
4570
+ )
4571
+ ));
4572
+ if (isInteractive) {
4573
+ return /* @__PURE__ */ import_react44.default.createElement(
4574
+ import_react_native39.Pressable,
4575
+ {
4576
+ onPress: isDisabled || isClosing ? void 0 : handleChipPress,
4577
+ onPressIn: handlePressIn,
4578
+ onPressOut: handlePressOut,
4579
+ disabled: isDisabled || isClosing
4580
+ },
4581
+ chipContent
4582
+ );
4583
+ }
4584
+ return chipContent;
4585
+ };
4586
+
4587
+ // src/components/chip/chip-group.tsx
4588
+ var import_react47 = __toESM(require("react"), 1);
4589
+ var import_react_native40 = require("react-native");
4590
+
4591
+ // src/components/chip/chip-context.ts
4592
+ var import_react45 = require("react");
4593
+ var ChipGroupContext = (0, import_react45.createContext)(null);
4594
+
4595
+ // src/components/chip/chip-group.hook.ts
4596
+ var import_react46 = require("react");
4597
+ function useChipGroupSelection(selectMode, selectedValues, defaultSelectedValues, onSelectionChange) {
4598
+ const [internalValues, setInternalValues] = (0, import_react46.useState)(
4599
+ defaultSelectedValues ?? []
4600
+ );
4601
+ const isControlled = selectedValues !== void 0;
4602
+ const currentValues = isControlled ? selectedValues : internalValues;
4603
+ const onToggle = (0, import_react46.useCallback)(
4604
+ (value) => {
4605
+ const isSelected = currentValues.includes(value);
4606
+ let nextValues;
4607
+ if (selectMode === "single") {
4608
+ nextValues = isSelected ? [] : [value];
4609
+ } else {
4610
+ nextValues = isSelected ? currentValues.filter((v) => v !== value) : [...currentValues, value];
4611
+ }
4612
+ if (!isControlled) {
4613
+ setInternalValues(nextValues);
4614
+ }
4615
+ onSelectionChange?.(nextValues);
4616
+ },
4617
+ [currentValues, isControlled, onSelectionChange, selectMode]
4618
+ );
4619
+ return (0, import_react46.useMemo)(
4620
+ () => ({ currentValues, onToggle }),
4621
+ [currentValues, onToggle]
4622
+ );
4623
+ }
4624
+
4625
+ // src/components/chip/chip-group.tsx
4626
+ var ChipGroup = ({
4627
+ children,
4628
+ isSelectable = false,
4629
+ selectMode = "single",
4630
+ variant = "solid",
4631
+ themeColor = "default",
4632
+ size = "md",
4633
+ radius = "full",
4634
+ isDisabled = false,
4635
+ selectedValues,
4636
+ defaultSelectedValues,
4637
+ onSelectionChange,
4638
+ spacing = 8,
4639
+ customAppearance
4640
+ }) => {
4641
+ const { currentValues, onToggle } = useChipGroupSelection(
4642
+ selectMode,
4643
+ selectedValues,
4644
+ defaultSelectedValues,
4645
+ onSelectionChange
4646
+ );
4647
+ const contextValue = import_react47.default.useMemo(
4648
+ () => ({
4649
+ variant,
4650
+ themeColor,
4651
+ size,
4652
+ radius,
4653
+ isDisabled,
4654
+ isSelectable,
4655
+ selectMode,
4656
+ selectedValues: currentValues,
4657
+ onToggle
4658
+ }),
4659
+ [
4660
+ variant,
4661
+ themeColor,
4662
+ size,
4663
+ radius,
4664
+ isDisabled,
4665
+ isSelectable,
4666
+ selectMode,
4667
+ currentValues,
4668
+ onToggle
4669
+ ]
4670
+ );
4671
+ return /* @__PURE__ */ import_react47.default.createElement(ChipGroupContext.Provider, { value: contextValue }, /* @__PURE__ */ import_react47.default.createElement(
4672
+ import_react_native40.View,
4673
+ {
4674
+ style: [
4675
+ styles12.groupContainer,
4676
+ { gap: spacing },
4677
+ customAppearance?.container
4678
+ ],
4679
+ accessible: true
4680
+ },
4681
+ children
4682
+ ));
4683
+ };
4684
+
4685
+ // src/components/chip/chip-item.tsx
4686
+ var import_react48 = __toESM(require("react"), 1);
4687
+ function getSelectableVariant(baseVariant, isSelected) {
4688
+ if (isSelected) {
4689
+ return baseVariant;
4690
+ }
4691
+ if (baseVariant === "solid" || baseVariant === "shadow") {
4692
+ return "bordered";
4693
+ }
4694
+ return "light";
4695
+ }
4696
+ var ChipItem = ({
4697
+ value,
4698
+ children,
4699
+ variant,
4700
+ themeColor,
4701
+ avatar,
4702
+ startContent,
4703
+ endContent,
4704
+ isDisabled,
4705
+ customAppearance
4706
+ }) => {
4707
+ const groupContext = (0, import_react48.useContext)(ChipGroupContext);
4708
+ if (!groupContext) {
4709
+ return null;
4710
+ }
4711
+ const resolvedVariant = variant ?? groupContext.variant;
4712
+ const resolvedColor = themeColor ?? groupContext.themeColor;
4713
+ const resolvedDisabled = isDisabled ?? groupContext.isDisabled;
4714
+ const isSelected = groupContext.selectedValues.includes(value);
4715
+ const chipVariant = groupContext.isSelectable ? getSelectableVariant(resolvedVariant, isSelected) : resolvedVariant;
4716
+ const handlePress = groupContext.isSelectable ? () => groupContext.onToggle(value) : void 0;
4717
+ return /* @__PURE__ */ import_react48.default.createElement(
4718
+ Chip,
4719
+ {
4720
+ variant: chipVariant,
4721
+ themeColor: resolvedColor,
4722
+ size: groupContext.size,
4723
+ radius: groupContext.radius,
4724
+ isDisabled: resolvedDisabled,
4725
+ avatar,
4726
+ startContent,
4727
+ endContent,
4728
+ customAppearance,
4729
+ onPress: handlePress
4730
+ },
4731
+ children
4732
+ );
4733
+ };
4734
+
4735
+ // src/components/bottom-sheet/bottom-sheet.tsx
4736
+ var import_react50 = __toESM(require("react"), 1);
4737
+ var import_react_native44 = require("react-native");
4738
+
4739
+ // src/components/bottom-sheet/bottom-sheet.hook.ts
4740
+ var import_react49 = require("react");
4741
+ var import_react_native42 = require("react-native");
4742
+ var import_core34 = require("@xaui/core");
4237
4743
 
4238
4744
  // src/components/bottom-sheet/bottom-sheet.animation.ts
4239
- var import_react_native38 = require("react-native");
4745
+ var import_react_native41 = require("react-native");
4240
4746
  var SPRING_CONFIG = {
4241
4747
  useNativeDriver: true,
4242
4748
  speed: 14,
@@ -4244,16 +4750,16 @@ var SPRING_CONFIG = {
4244
4750
  };
4245
4751
  var TIMING_CONFIG = {
4246
4752
  duration: 280,
4247
- easing: import_react_native38.Easing.bezier(0.2, 0, 0, 1),
4753
+ easing: import_react_native41.Easing.bezier(0.2, 0, 0, 1),
4248
4754
  useNativeDriver: true
4249
4755
  };
4250
4756
  var runOpenAnimation = (translateY, backdropOpacity, targetTranslateY) => {
4251
- const animation = import_react_native38.Animated.parallel([
4252
- import_react_native38.Animated.spring(translateY, {
4757
+ const animation = import_react_native41.Animated.parallel([
4758
+ import_react_native41.Animated.spring(translateY, {
4253
4759
  ...SPRING_CONFIG,
4254
4760
  toValue: targetTranslateY
4255
4761
  }),
4256
- import_react_native38.Animated.timing(backdropOpacity, {
4762
+ import_react_native41.Animated.timing(backdropOpacity, {
4257
4763
  ...TIMING_CONFIG,
4258
4764
  toValue: 1
4259
4765
  })
@@ -4262,12 +4768,12 @@ var runOpenAnimation = (translateY, backdropOpacity, targetTranslateY) => {
4262
4768
  return animation;
4263
4769
  };
4264
4770
  var runCloseAnimation = (translateY, backdropOpacity, screenHeight, onComplete) => {
4265
- const animation = import_react_native38.Animated.parallel([
4266
- import_react_native38.Animated.timing(translateY, {
4771
+ const animation = import_react_native41.Animated.parallel([
4772
+ import_react_native41.Animated.timing(translateY, {
4267
4773
  ...TIMING_CONFIG,
4268
4774
  toValue: screenHeight
4269
4775
  }),
4270
- import_react_native38.Animated.timing(backdropOpacity, {
4776
+ import_react_native41.Animated.timing(backdropOpacity, {
4271
4777
  ...TIMING_CONFIG,
4272
4778
  toValue: 0
4273
4779
  })
@@ -4280,7 +4786,7 @@ var runCloseAnimation = (translateY, backdropOpacity, screenHeight, onComplete)
4280
4786
  return animation;
4281
4787
  };
4282
4788
  var runSnapAnimation = (translateY, targetTranslateY) => {
4283
- const animation = import_react_native38.Animated.spring(translateY, {
4789
+ const animation = import_react_native41.Animated.spring(translateY, {
4284
4790
  ...SPRING_CONFIG,
4285
4791
  toValue: targetTranslateY
4286
4792
  });
@@ -4291,7 +4797,7 @@ var runSnapAnimation = (translateY, targetTranslateY) => {
4291
4797
  // src/components/bottom-sheet/bottom-sheet.hook.ts
4292
4798
  var DISMISS_VELOCITY_THRESHOLD = 0.5;
4293
4799
  var DISMISS_DISTANCE_FRACTION = 0.3;
4294
- var SCREEN_HEIGHT = import_react_native39.Dimensions.get("window").height;
4800
+ var SCREEN_HEIGHT = import_react_native42.Dimensions.get("window").height;
4295
4801
  var getTranslateYForSnap = (snapFraction) => SCREEN_HEIGHT * (1 - snapFraction);
4296
4802
  var useBottomSheetAnimation = ({
4297
4803
  isOpen,
@@ -4302,20 +4808,20 @@ var useBottomSheetAnimation = ({
4302
4808
  onClose,
4303
4809
  onSnapChange
4304
4810
  }) => {
4305
- const [shouldRender, setShouldRender] = (0, import_react43.useState)(false);
4306
- const currentSnapIndex = (0, import_react43.useRef)(initialSnapIndex);
4307
- const animationRef = (0, import_react43.useRef)(null);
4308
- const translateY = (0, import_react43.useRef)(new import_react_native39.Animated.Value(SCREEN_HEIGHT)).current;
4309
- const backdropOpacity = (0, import_react43.useRef)(new import_react_native39.Animated.Value(0)).current;
4310
- const sortedSnapPoints = (0, import_react43.useMemo)(
4811
+ const [shouldRender, setShouldRender] = (0, import_react49.useState)(false);
4812
+ const currentSnapIndex = (0, import_react49.useRef)(initialSnapIndex);
4813
+ const animationRef = (0, import_react49.useRef)(null);
4814
+ const translateY = (0, import_react49.useRef)(new import_react_native42.Animated.Value(SCREEN_HEIGHT)).current;
4815
+ const backdropOpacity = (0, import_react49.useRef)(new import_react_native42.Animated.Value(0)).current;
4816
+ const sortedSnapPoints = (0, import_react49.useMemo)(
4311
4817
  () => [...snapPoints].sort((a, b) => a - b),
4312
4818
  [snapPoints]
4313
4819
  );
4314
- const snapTranslateValues = (0, import_react43.useMemo)(
4820
+ const snapTranslateValues = (0, import_react49.useMemo)(
4315
4821
  () => sortedSnapPoints.map(getTranslateYForSnap),
4316
4822
  [sortedSnapPoints]
4317
4823
  );
4318
- const open = (0, import_react43.useCallback)(() => {
4824
+ const open = (0, import_react49.useCallback)(() => {
4319
4825
  setShouldRender(true);
4320
4826
  const targetIndex = Math.min(initialSnapIndex, sortedSnapPoints.length - 1);
4321
4827
  currentSnapIndex.current = targetIndex;
@@ -4340,7 +4846,7 @@ var useBottomSheetAnimation = ({
4340
4846
  translateY,
4341
4847
  backdropOpacity
4342
4848
  ]);
4343
- const close = (0, import_react43.useCallback)(() => {
4849
+ const close = (0, import_react49.useCallback)(() => {
4344
4850
  if (disableAnimation) {
4345
4851
  translateY.setValue(SCREEN_HEIGHT);
4346
4852
  backdropOpacity.setValue(0);
@@ -4359,7 +4865,7 @@ var useBottomSheetAnimation = ({
4359
4865
  }
4360
4866
  );
4361
4867
  }, [disableAnimation, translateY, backdropOpacity, onClose]);
4362
- const snapTo = (0, import_react43.useCallback)(
4868
+ const snapTo = (0, import_react49.useCallback)(
4363
4869
  (index) => {
4364
4870
  const clampedIndex = Math.max(0, Math.min(index, sortedSnapPoints.length - 1));
4365
4871
  currentSnapIndex.current = clampedIndex;
@@ -4376,15 +4882,15 @@ var useBottomSheetAnimation = ({
4376
4882
  },
4377
4883
  [sortedSnapPoints, snapTranslateValues, disableAnimation, translateY, onSnapChange]
4378
4884
  );
4379
- (0, import_react43.useEffect)(() => {
4885
+ (0, import_react49.useEffect)(() => {
4380
4886
  if (isOpen) {
4381
4887
  open();
4382
4888
  } else if (shouldRender) {
4383
4889
  close();
4384
4890
  }
4385
4891
  }, [isOpen]);
4386
- const panResponder = (0, import_react43.useMemo)(
4387
- () => import_react_native39.PanResponder.create({
4892
+ const panResponder = (0, import_react49.useMemo)(
4893
+ () => import_react_native42.PanResponder.create({
4388
4894
  onStartShouldSetPanResponder: () => true,
4389
4895
  onMoveShouldSetPanResponder: (_, gestureState) => Math.abs(gestureState.dy) > 5,
4390
4896
  onPanResponderMove: (_, gestureState) => {
@@ -4451,9 +4957,9 @@ var useBottomSheetAnimation = ({
4451
4957
  };
4452
4958
  var useBottomSheetStyles = (themeColor, radius) => {
4453
4959
  const theme = useXUITheme();
4454
- const safeThemeColor = (0, import_core32.getSafeThemeColor)(themeColor);
4960
+ const safeThemeColor = (0, import_core34.getSafeThemeColor)(themeColor);
4455
4961
  const colorScheme = theme.colors[safeThemeColor];
4456
- const sheetStyles = (0, import_react43.useMemo)(
4962
+ const sheetStyles = (0, import_react49.useMemo)(
4457
4963
  () => ({
4458
4964
  backgroundColor: colorScheme.background ?? theme.colors.background ?? "#ffffff",
4459
4965
  borderTopLeftRadius: theme.borderRadius[radius],
@@ -4461,7 +4967,7 @@ var useBottomSheetStyles = (themeColor, radius) => {
4461
4967
  }),
4462
4968
  [theme, colorScheme, radius]
4463
4969
  );
4464
- const handleIndicatorColor = (0, import_react43.useMemo)(
4970
+ const handleIndicatorColor = (0, import_react49.useMemo)(
4465
4971
  () => theme.mode === "dark" ? `${colorScheme.main}60` : `${colorScheme.main}40`,
4466
4972
  [theme, colorScheme]
4467
4973
  );
@@ -4469,8 +4975,8 @@ var useBottomSheetStyles = (themeColor, radius) => {
4469
4975
  };
4470
4976
 
4471
4977
  // src/components/bottom-sheet/bottom-sheet.style.ts
4472
- var import_react_native40 = require("react-native");
4473
- var styles12 = import_react_native40.StyleSheet.create({
4978
+ var import_react_native43 = require("react-native");
4979
+ var styles13 = import_react_native43.StyleSheet.create({
4474
4980
  backdrop: {
4475
4981
  position: "absolute",
4476
4982
  top: 0,
@@ -4549,53 +5055,656 @@ var BottomSheet = ({
4549
5055
  close();
4550
5056
  }
4551
5057
  };
4552
- return /* @__PURE__ */ import_react44.default.createElement(Portal, null, showBackdrop && /* @__PURE__ */ import_react44.default.createElement(
4553
- import_react_native41.Animated.View,
5058
+ return /* @__PURE__ */ import_react50.default.createElement(Portal, null, showBackdrop && /* @__PURE__ */ import_react50.default.createElement(
5059
+ import_react_native44.Animated.View,
4554
5060
  {
4555
- style: [styles12.backdrop, { opacity: backdropOpacity }]
5061
+ style: [styles13.backdrop, { opacity: backdropOpacity }]
4556
5062
  },
4557
- /* @__PURE__ */ import_react44.default.createElement(
4558
- import_react_native41.Pressable,
5063
+ /* @__PURE__ */ import_react50.default.createElement(
5064
+ import_react_native44.Pressable,
4559
5065
  {
4560
- style: styles12.backdrop,
5066
+ style: styles13.backdrop,
4561
5067
  onPress: handleBackdropPress
4562
5068
  }
4563
5069
  )
4564
- ), /* @__PURE__ */ import_react44.default.createElement(
4565
- import_react_native41.Animated.View,
5070
+ ), /* @__PURE__ */ import_react50.default.createElement(
5071
+ import_react_native44.Animated.View,
4566
5072
  {
4567
5073
  style: [
4568
- styles12.container,
5074
+ styles13.container,
4569
5075
  {
4570
5076
  height: screenHeight,
4571
5077
  transform: [{ translateY }]
4572
5078
  }
4573
5079
  ]
4574
5080
  },
4575
- /* @__PURE__ */ import_react44.default.createElement(
4576
- import_react_native41.View,
5081
+ /* @__PURE__ */ import_react50.default.createElement(
5082
+ import_react_native44.View,
4577
5083
  {
4578
5084
  style: [
4579
- styles12.sheet,
5085
+ styles13.sheet,
4580
5086
  { height: screenHeight },
4581
5087
  sheetStyles,
4582
5088
  style
4583
5089
  ],
4584
5090
  ...panResponder.panHandlers
4585
5091
  },
4586
- showHandle && /* @__PURE__ */ import_react44.default.createElement(import_react_native41.View, { style: styles12.handle }, handleContent ?? /* @__PURE__ */ import_react44.default.createElement(
4587
- import_react_native41.View,
5092
+ showHandle && /* @__PURE__ */ import_react50.default.createElement(import_react_native44.View, { style: styles13.handle }, handleContent ?? /* @__PURE__ */ import_react50.default.createElement(
5093
+ import_react_native44.View,
4588
5094
  {
4589
5095
  style: [
4590
- styles12.handleIndicator,
5096
+ styles13.handleIndicator,
4591
5097
  { backgroundColor: handleIndicatorColor }
4592
5098
  ]
4593
5099
  }
4594
5100
  )),
4595
- /* @__PURE__ */ import_react44.default.createElement(import_react_native41.View, { style: styles12.content }, children)
5101
+ /* @__PURE__ */ import_react50.default.createElement(import_react_native44.View, { style: styles13.content }, children)
5102
+ )
5103
+ ));
5104
+ };
5105
+
5106
+ // src/components/fab/fab.tsx
5107
+ var import_react52 = __toESM(require("react"), 1);
5108
+ var import_react_native47 = require("react-native");
5109
+
5110
+ // src/components/fab/fab.style.ts
5111
+ var import_react_native45 = require("react-native");
5112
+ var styles14 = import_react_native45.StyleSheet.create({
5113
+ container: {
5114
+ alignSelf: "flex-start"
5115
+ },
5116
+ fab: {
5117
+ flexDirection: "row",
5118
+ alignItems: "center",
5119
+ justifyContent: "center",
5120
+ overflow: "hidden"
5121
+ },
5122
+ contentContainer: {
5123
+ flexDirection: "row",
5124
+ alignItems: "center",
5125
+ justifyContent: "center",
5126
+ gap: 12
5127
+ },
5128
+ label: {
5129
+ fontWeight: "500"
5130
+ },
5131
+ disabled: {
5132
+ opacity: 0.5
5133
+ }
5134
+ });
5135
+
5136
+ // src/components/fab/fab.hook.ts
5137
+ var import_react51 = require("react");
5138
+ var import_core36 = require("@xaui/core");
5139
+ function useFabSizeStyles(size) {
5140
+ const theme = useXUITheme();
5141
+ const sizeStyles = (0, import_react51.useMemo)(() => {
5142
+ const sizes = {
5143
+ sm: {
5144
+ width: 40,
5145
+ height: 40,
5146
+ borderRadius: theme.borderRadius.lg,
5147
+ iconSize: 24,
5148
+ fontSize: theme.fontSizes.sm
5149
+ },
5150
+ md: {
5151
+ width: 56,
5152
+ height: 56,
5153
+ borderRadius: theme.borderRadius.xl,
5154
+ iconSize: 24,
5155
+ fontSize: theme.fontSizes.md
5156
+ },
5157
+ lg: {
5158
+ width: 96,
5159
+ height: 96,
5160
+ borderRadius: theme.borderRadius["2xl"],
5161
+ iconSize: 36,
5162
+ fontSize: theme.fontSizes.lg
5163
+ }
5164
+ };
5165
+ return sizes[size];
5166
+ }, [size, theme]);
5167
+ const extendedSizeStyles = (0, import_react51.useMemo)(() => {
5168
+ const sizes = {
5169
+ sm: {
5170
+ height: 40,
5171
+ borderRadius: theme.borderRadius.lg,
5172
+ paddingHorizontal: theme.spacing.md,
5173
+ iconSize: 20,
5174
+ fontSize: theme.fontSizes.sm
5175
+ },
5176
+ md: {
5177
+ height: 56,
5178
+ borderRadius: theme.borderRadius.xl,
5179
+ paddingHorizontal: theme.spacing.lg,
5180
+ iconSize: 24,
5181
+ fontSize: theme.fontSizes.md
5182
+ },
5183
+ lg: {
5184
+ height: 80,
5185
+ borderRadius: theme.borderRadius["2xl"],
5186
+ paddingHorizontal: theme.spacing.xl,
5187
+ iconSize: 28,
5188
+ fontSize: theme.fontSizes.lg
5189
+ }
5190
+ };
5191
+ return sizes[size];
5192
+ }, [size, theme]);
5193
+ return { sizeStyles, extendedSizeStyles };
5194
+ }
5195
+ function useFabVariantStyles(themeColor, variant, elevation = 0) {
5196
+ const theme = useXUITheme();
5197
+ const safeThemeColor = (0, import_core36.getSafeThemeColor)(themeColor);
5198
+ const colorScheme = theme.colors[safeThemeColor];
5199
+ const variantStyles = (0, import_react51.useMemo)(() => {
5200
+ const variantMap = {
5201
+ solid: {
5202
+ backgroundColor: colorScheme.main,
5203
+ borderWidth: 0
5204
+ },
5205
+ flat: {
5206
+ backgroundColor: colorScheme.background,
5207
+ borderWidth: 0
5208
+ },
5209
+ outlined: {
5210
+ backgroundColor: "transparent",
5211
+ borderWidth: theme.borderWidth.md,
5212
+ borderColor: colorScheme.main
5213
+ }
5214
+ };
5215
+ const baseStyle = variantMap[variant];
5216
+ const shouldApplyElevation = variant !== "outlined";
5217
+ const shadowStyles = elevation === 0 ? {} : elevation === 1 ? theme.shadows.sm : elevation === 2 ? theme.shadows.md : elevation === 3 ? theme.shadows.lg : theme.shadows.xl;
5218
+ return {
5219
+ ...baseStyle,
5220
+ ...shouldApplyElevation ? shadowStyles : {},
5221
+ ...shouldApplyElevation && elevation > 0 ? { elevation } : {}
5222
+ };
5223
+ }, [variant, colorScheme, theme, elevation]);
5224
+ return variantStyles;
5225
+ }
5226
+ function useFabIconColor(themeColor, variant) {
5227
+ const theme = useXUITheme();
5228
+ const safeThemeColor = (0, import_core36.getSafeThemeColor)(themeColor);
5229
+ const colorScheme = theme.colors[safeThemeColor];
5230
+ const iconColor = (0, import_react51.useMemo)(() => {
5231
+ if (variant === "solid") {
5232
+ return colorScheme.foreground;
5233
+ }
5234
+ return colorScheme.main;
5235
+ }, [variant, colorScheme]);
5236
+ return { iconColor };
5237
+ }
5238
+ function useFabRadiusValue(radius, fallback) {
5239
+ const theme = useXUITheme();
5240
+ return (0, import_react51.useMemo)(() => {
5241
+ if (!radius) return fallback;
5242
+ const radiusMap = {
5243
+ none: theme.borderRadius.none,
5244
+ sm: theme.borderRadius.sm,
5245
+ md: theme.borderRadius.md,
5246
+ lg: theme.borderRadius.lg,
5247
+ full: theme.borderRadius.full
5248
+ };
5249
+ return radiusMap[radius];
5250
+ }, [fallback, radius, theme]);
5251
+ }
5252
+
5253
+ // src/components/fab/fab.animation.ts
5254
+ var import_react_native46 = require("react-native");
5255
+ var runFabPressInAnimation = (animatedScale, animatedOpacity) => {
5256
+ import_react_native46.Animated.parallel([
5257
+ import_react_native46.Animated.spring(animatedScale, {
5258
+ toValue: 0.92,
5259
+ useNativeDriver: true,
5260
+ speed: 50,
5261
+ bounciness: 0
5262
+ }),
5263
+ import_react_native46.Animated.timing(animatedOpacity, {
5264
+ toValue: 0.85,
5265
+ duration: 100,
5266
+ useNativeDriver: true
5267
+ })
5268
+ ]).start();
5269
+ };
5270
+ var runFabPressOutAnimation = (animatedScale, animatedOpacity) => {
5271
+ import_react_native46.Animated.parallel([
5272
+ import_react_native46.Animated.spring(animatedScale, {
5273
+ toValue: 1,
5274
+ useNativeDriver: true,
5275
+ speed: 50,
5276
+ bounciness: 0
5277
+ }),
5278
+ import_react_native46.Animated.timing(animatedOpacity, {
5279
+ toValue: 1,
5280
+ duration: 100,
5281
+ useNativeDriver: true
5282
+ })
5283
+ ]).start();
5284
+ };
5285
+
5286
+ // src/components/fab/fab.tsx
5287
+ var Fab = ({
5288
+ icon,
5289
+ label,
5290
+ themeColor = "primary",
5291
+ variant = "solid",
5292
+ size = "md",
5293
+ radius,
5294
+ isDisabled = false,
5295
+ isLoading = false,
5296
+ elevation = 0,
5297
+ customAppearance,
5298
+ onPress,
5299
+ onLongPress,
5300
+ onPressIn,
5301
+ onPressOut
5302
+ }) => {
5303
+ const animatedScale = import_react52.default.useRef(new import_react_native47.Animated.Value(1)).current;
5304
+ const animatedOpacity = import_react52.default.useRef(new import_react_native47.Animated.Value(1)).current;
5305
+ const { sizeStyles, extendedSizeStyles } = useFabSizeStyles(size);
5306
+ const variantStyles = useFabVariantStyles(themeColor, variant, elevation);
5307
+ const { iconColor } = useFabIconColor(themeColor, variant);
5308
+ const isExtended = !!label;
5309
+ const resolvedRadius = useFabRadiusValue(
5310
+ radius,
5311
+ isExtended ? extendedSizeStyles.borderRadius : sizeStyles.borderRadius
5312
+ );
5313
+ const handlePressIn = (event) => {
5314
+ if (!isDisabled && !isLoading) {
5315
+ runFabPressInAnimation(animatedScale, animatedOpacity);
5316
+ }
5317
+ onPressIn?.(event);
5318
+ };
5319
+ const handlePressOut = (event) => {
5320
+ if (!isDisabled && !isLoading) {
5321
+ runFabPressOutAnimation(animatedScale, animatedOpacity);
5322
+ }
5323
+ onPressOut?.(event);
5324
+ };
5325
+ const fabDimensionStyles = isExtended ? {
5326
+ height: extendedSizeStyles.height,
5327
+ borderRadius: resolvedRadius,
5328
+ paddingHorizontal: extendedSizeStyles.paddingHorizontal
5329
+ } : {
5330
+ width: sizeStyles.width,
5331
+ height: sizeStyles.height,
5332
+ borderRadius: resolvedRadius
5333
+ };
5334
+ return /* @__PURE__ */ import_react52.default.createElement(import_react_native47.View, { style: [styles14.container, customAppearance?.container] }, /* @__PURE__ */ import_react52.default.createElement(
5335
+ import_react_native47.Pressable,
5336
+ {
5337
+ onPress: isDisabled || isLoading ? void 0 : onPress,
5338
+ onLongPress: isDisabled || isLoading ? void 0 : onLongPress,
5339
+ onPressIn: handlePressIn,
5340
+ onPressOut: handlePressOut,
5341
+ disabled: isDisabled || isLoading
5342
+ },
5343
+ /* @__PURE__ */ import_react52.default.createElement(
5344
+ import_react_native47.Animated.View,
5345
+ {
5346
+ style: [
5347
+ styles14.fab,
5348
+ fabDimensionStyles,
5349
+ variantStyles,
5350
+ isDisabled && styles14.disabled,
5351
+ {
5352
+ transform: [{ scale: animatedScale }],
5353
+ opacity: animatedOpacity
5354
+ },
5355
+ customAppearance?.fab
5356
+ ]
5357
+ },
5358
+ isLoading ? /* @__PURE__ */ import_react52.default.createElement(
5359
+ ActivityIndicator,
5360
+ {
5361
+ variant: "circular",
5362
+ themeColor: variant === "solid" ? void 0 : themeColor,
5363
+ color: variant === "solid" ? iconColor : void 0,
5364
+ size: isExtended ? extendedSizeStyles.iconSize : sizeStyles.iconSize
5365
+ }
5366
+ ) : /* @__PURE__ */ import_react52.default.createElement(import_react_native47.View, { style: styles14.contentContainer }, icon, isExtended && /* @__PURE__ */ import_react52.default.createElement(
5367
+ import_react_native47.Text,
5368
+ {
5369
+ style: [
5370
+ styles14.label,
5371
+ {
5372
+ fontSize: isExtended ? extendedSizeStyles.fontSize : sizeStyles.fontSize,
5373
+ color: iconColor
5374
+ }
5375
+ ]
5376
+ },
5377
+ label
5378
+ ))
4596
5379
  )
4597
5380
  ));
4598
5381
  };
5382
+
5383
+ // src/components/fab-menu/fab-menu.tsx
5384
+ var import_react54 = __toESM(require("react"), 1);
5385
+ var import_react_native50 = require("react-native");
5386
+
5387
+ // src/components/fab-menu/fab-menu.style.ts
5388
+ var import_react_native48 = require("react-native");
5389
+ var styles15 = import_react_native48.StyleSheet.create({
5390
+ container: {
5391
+ position: "relative",
5392
+ alignItems: "flex-end"
5393
+ },
5394
+ portalRoot: {
5395
+ ...import_react_native48.StyleSheet.absoluteFillObject
5396
+ },
5397
+ overlay: {
5398
+ ...import_react_native48.StyleSheet.absoluteFillObject
5399
+ },
5400
+ overlayPressable: {
5401
+ flex: 1
5402
+ },
5403
+ portalContent: {
5404
+ ...import_react_native48.StyleSheet.absoluteFillObject,
5405
+ justifyContent: "flex-end",
5406
+ alignItems: "flex-end",
5407
+ padding: 16
5408
+ },
5409
+ menuContainer: {
5410
+ alignItems: "flex-end",
5411
+ marginBottom: 16
5412
+ },
5413
+ menuItem: {
5414
+ marginBottom: 12
5415
+ },
5416
+ menuItemChip: {
5417
+ flexDirection: "row",
5418
+ alignItems: "center",
5419
+ paddingVertical: 12,
5420
+ paddingLeft: 16,
5421
+ paddingRight: 20,
5422
+ gap: 8
5423
+ },
5424
+ menuItemLabel: {
5425
+ fontWeight: "500"
5426
+ },
5427
+ disabled: {
5428
+ opacity: 0.5
5429
+ }
5430
+ });
5431
+
5432
+ // src/components/fab-menu/fab-menu.hook.ts
5433
+ var import_react53 = require("react");
5434
+ var import_core38 = require("@xaui/core");
5435
+ function useFabMenuState(controlledExpanded, onToggle) {
5436
+ const [internalExpanded, setInternalExpanded] = (0, import_react53.useState)(false);
5437
+ const isControlled = controlledExpanded !== void 0;
5438
+ const expanded = isControlled ? controlledExpanded : internalExpanded;
5439
+ const toggle = (0, import_react53.useCallback)(() => {
5440
+ const next = !expanded;
5441
+ if (!isControlled) {
5442
+ setInternalExpanded(next);
5443
+ }
5444
+ onToggle?.(next);
5445
+ }, [expanded, isControlled, onToggle]);
5446
+ const close = (0, import_react53.useCallback)(() => {
5447
+ if (!isControlled) {
5448
+ setInternalExpanded(false);
5449
+ }
5450
+ onToggle?.(false);
5451
+ }, [isControlled, onToggle]);
5452
+ return { expanded, toggle, close };
5453
+ }
5454
+ function useFabMenuItemStyles(themeColor) {
5455
+ const theme = useXUITheme();
5456
+ const safeThemeColor = (0, import_core38.getSafeThemeColor)(themeColor);
5457
+ const colorScheme = theme.colors[safeThemeColor];
5458
+ const itemStyles = (0, import_react53.useMemo)(() => {
5459
+ const chipStyles = {
5460
+ backgroundColor: colorScheme.background,
5461
+ borderRadius: theme.borderRadius.full,
5462
+ color: colorScheme.main,
5463
+ fontSize: theme.fontSizes.md
5464
+ };
5465
+ const iconColor = colorScheme.main;
5466
+ return { chipStyles, iconColor };
5467
+ }, [colorScheme, theme]);
5468
+ return itemStyles;
5469
+ }
5470
+ function useFabMenuOverlayColor() {
5471
+ const theme = useXUITheme();
5472
+ return (0, import_react53.useMemo)(() => {
5473
+ return theme.mode === "dark" ? "rgba(0, 0, 0, 0.5)" : "rgba(0, 0, 0, 0.3)";
5474
+ }, [theme.mode]);
5475
+ }
5476
+
5477
+ // src/components/fab-menu/fab-menu.animation.ts
5478
+ var import_react_native49 = require("react-native");
5479
+ var runMenuExpandAnimation = (overlayOpacity, itemAnimations) => {
5480
+ const itemSequence = itemAnimations.map(
5481
+ (anim, index) => import_react_native49.Animated.timing(anim, {
5482
+ toValue: 1,
5483
+ duration: 150,
5484
+ delay: index * 50,
5485
+ useNativeDriver: true
5486
+ })
5487
+ );
5488
+ import_react_native49.Animated.parallel([
5489
+ import_react_native49.Animated.timing(overlayOpacity, {
5490
+ toValue: 1,
5491
+ duration: 200,
5492
+ useNativeDriver: true
5493
+ }),
5494
+ import_react_native49.Animated.stagger(50, itemSequence)
5495
+ ]).start();
5496
+ };
5497
+ var runMenuCollapseAnimation = (overlayOpacity, itemAnimations, onComplete) => {
5498
+ const reversed = [...itemAnimations].reverse();
5499
+ const itemSequence = reversed.map(
5500
+ (anim, index) => import_react_native49.Animated.timing(anim, {
5501
+ toValue: 0,
5502
+ duration: 120,
5503
+ delay: index * 30,
5504
+ useNativeDriver: true
5505
+ })
5506
+ );
5507
+ import_react_native49.Animated.parallel([
5508
+ import_react_native49.Animated.timing(overlayOpacity, {
5509
+ toValue: 0,
5510
+ duration: 200,
5511
+ useNativeDriver: true
5512
+ }),
5513
+ import_react_native49.Animated.stagger(30, itemSequence)
5514
+ ]).start(onComplete);
5515
+ };
5516
+ var runFabRotateAnimation = (rotateValue, toExpanded) => {
5517
+ import_react_native49.Animated.spring(rotateValue, {
5518
+ toValue: toExpanded ? 1 : 0,
5519
+ useNativeDriver: true,
5520
+ speed: 20,
5521
+ bounciness: 0
5522
+ }).start();
5523
+ };
5524
+
5525
+ // src/components/fab-menu/fab-menu.tsx
5526
+ var FabMenu = ({
5527
+ icon,
5528
+ label,
5529
+ expandedIcon,
5530
+ children,
5531
+ themeColor = "primary",
5532
+ variant = "solid",
5533
+ size = "md",
5534
+ radius,
5535
+ elevation = 0,
5536
+ isExpanded: controlledExpanded,
5537
+ onToggle,
5538
+ showOverlay = true,
5539
+ customAppearance
5540
+ }) => {
5541
+ const { expanded, toggle, close } = useFabMenuState(
5542
+ controlledExpanded,
5543
+ onToggle
5544
+ );
5545
+ const overlayColor = useFabMenuOverlayColor();
5546
+ const [isPortalVisible, setIsPortalVisible] = import_react54.default.useState(expanded);
5547
+ const childArray = import_react54.default.Children.toArray(children);
5548
+ const overlayOpacity = import_react54.default.useRef(
5549
+ new import_react_native50.Animated.Value(expanded ? 1 : 0)
5550
+ ).current;
5551
+ const rotateValue = import_react54.default.useRef(
5552
+ new import_react_native50.Animated.Value(expanded ? 1 : 0)
5553
+ ).current;
5554
+ const itemAnimationsRef = import_react54.default.useRef(
5555
+ childArray.map(() => new import_react_native50.Animated.Value(0))
5556
+ );
5557
+ const itemAnimations = itemAnimationsRef.current;
5558
+ const prevExpanded = import_react54.default.useRef(expanded);
5559
+ import_react54.default.useEffect(() => {
5560
+ if (itemAnimations.length === childArray.length) return;
5561
+ itemAnimationsRef.current = childArray.map(
5562
+ (_, index) => itemAnimations[index] ?? new import_react_native50.Animated.Value(expanded ? 1 : 0)
5563
+ );
5564
+ }, [expanded, itemAnimations, childArray]);
5565
+ import_react54.default.useEffect(() => {
5566
+ if (prevExpanded.current === expanded) return;
5567
+ prevExpanded.current = expanded;
5568
+ if (expanded) {
5569
+ setIsPortalVisible(true);
5570
+ runMenuExpandAnimation(overlayOpacity, itemAnimations);
5571
+ runFabRotateAnimation(rotateValue, true);
5572
+ } else {
5573
+ runMenuCollapseAnimation(overlayOpacity, itemAnimations, () => {
5574
+ setIsPortalVisible(false);
5575
+ });
5576
+ runFabRotateAnimation(rotateValue, false);
5577
+ }
5578
+ }, [expanded, overlayOpacity, itemAnimations, rotateValue]);
5579
+ const rotation = rotateValue.interpolate({
5580
+ inputRange: [0, 1],
5581
+ outputRange: ["0deg", "45deg"]
5582
+ });
5583
+ const currentIcon = expanded && expandedIcon ? expandedIcon : icon;
5584
+ const renderFabToggle = () => /* @__PURE__ */ import_react54.default.createElement(
5585
+ import_react_native50.Animated.View,
5586
+ {
5587
+ style: {
5588
+ alignSelf: "flex-end",
5589
+ transform: [{ rotate: expandedIcon ? "0deg" : rotation }]
5590
+ }
5591
+ },
5592
+ /* @__PURE__ */ import_react54.default.createElement(
5593
+ Fab,
5594
+ {
5595
+ icon: currentIcon,
5596
+ label,
5597
+ themeColor,
5598
+ variant,
5599
+ size,
5600
+ radius,
5601
+ elevation,
5602
+ onPress: toggle,
5603
+ customAppearance: { fab: customAppearance?.fab }
5604
+ }
5605
+ )
5606
+ );
5607
+ const renderMenuItems = () => /* @__PURE__ */ import_react54.default.createElement(import_react_native50.View, { style: [styles15.menuContainer, customAppearance?.menuContainer] }, childArray.map((child, index) => {
5608
+ const childElement = child;
5609
+ const isDisabled = childElement.props?.isDisabled;
5610
+ return /* @__PURE__ */ import_react54.default.createElement(
5611
+ import_react_native50.Animated.View,
5612
+ {
5613
+ key: childElement.key ?? index,
5614
+ style: [
5615
+ styles15.menuItem,
5616
+ isDisabled && styles15.disabled,
5617
+ {
5618
+ opacity: itemAnimations[index],
5619
+ transform: [
5620
+ {
5621
+ translateY: itemAnimations[index].interpolate({
5622
+ inputRange: [0, 1],
5623
+ outputRange: [20, 0]
5624
+ })
5625
+ },
5626
+ {
5627
+ scale: itemAnimations[index].interpolate({
5628
+ inputRange: [0, 1],
5629
+ outputRange: [0.8, 1]
5630
+ })
5631
+ }
5632
+ ]
5633
+ },
5634
+ customAppearance?.menuItem
5635
+ ]
5636
+ },
5637
+ import_react54.default.cloneElement(childElement, {
5638
+ _onClose: close,
5639
+ themeColor: childElement.props?.themeColor ?? themeColor
5640
+ })
5641
+ );
5642
+ }));
5643
+ return /* @__PURE__ */ import_react54.default.createElement(import_react_native50.View, { style: [styles15.container, customAppearance?.container] }, isPortalVisible && /* @__PURE__ */ import_react54.default.createElement(Portal, null, /* @__PURE__ */ import_react54.default.createElement(import_react_native50.View, { style: styles15.portalRoot }, showOverlay && /* @__PURE__ */ import_react54.default.createElement(
5644
+ import_react_native50.Animated.View,
5645
+ {
5646
+ style: [
5647
+ styles15.overlay,
5648
+ { backgroundColor: overlayColor, opacity: overlayOpacity },
5649
+ customAppearance?.overlay
5650
+ ]
5651
+ },
5652
+ /* @__PURE__ */ import_react54.default.createElement(import_react_native50.Pressable, { style: styles15.overlayPressable, onPress: close })
5653
+ ), /* @__PURE__ */ import_react54.default.createElement(import_react_native50.View, { style: styles15.portalContent }, renderMenuItems(), renderFabToggle()))), !isPortalVisible && renderFabToggle());
5654
+ };
5655
+
5656
+ // src/components/fab-menu/fab-menu-item.tsx
5657
+ var import_react55 = __toESM(require("react"), 1);
5658
+ var import_react_native51 = require("react-native");
5659
+ var FabMenuItem = ({
5660
+ icon,
5661
+ label,
5662
+ themeColor = "primary",
5663
+ onPress,
5664
+ isDisabled,
5665
+ _onClose
5666
+ }) => {
5667
+ const itemStyles = useFabMenuItemStyles(themeColor);
5668
+ const renderIcon = (menuIcon) => {
5669
+ if (!import_react55.default.isValidElement(menuIcon)) return menuIcon;
5670
+ return import_react55.default.cloneElement(
5671
+ menuIcon,
5672
+ { color: itemStyles.iconColor }
5673
+ );
5674
+ };
5675
+ return /* @__PURE__ */ import_react55.default.createElement(
5676
+ import_react_native51.Pressable,
5677
+ {
5678
+ style: [
5679
+ styles15.menuItemChip,
5680
+ {
5681
+ backgroundColor: itemStyles.chipStyles.backgroundColor,
5682
+ borderRadius: itemStyles.chipStyles.borderRadius
5683
+ }
5684
+ ],
5685
+ onPress: (event) => {
5686
+ if (isDisabled) return;
5687
+ onPress?.(event);
5688
+ _onClose?.();
5689
+ },
5690
+ disabled: isDisabled
5691
+ },
5692
+ renderIcon(icon),
5693
+ /* @__PURE__ */ import_react55.default.createElement(
5694
+ import_react_native51.Text,
5695
+ {
5696
+ style: [
5697
+ styles15.menuItemLabel,
5698
+ {
5699
+ color: itemStyles.chipStyles.color,
5700
+ fontSize: itemStyles.chipStyles.fontSize
5701
+ }
5702
+ ]
5703
+ },
5704
+ label
5705
+ )
5706
+ );
5707
+ };
4599
5708
  // Annotate the CommonJS export names for ESM import in node:
4600
5709
  0 && (module.exports = {
4601
5710
  ActivityIndicator,
@@ -4606,7 +5715,13 @@ var BottomSheet = ({
4606
5715
  AvatarGroup,
4607
5716
  Badge,
4608
5717
  BottomSheet,
5718
+ Chip,
5719
+ ChipGroup,
5720
+ ChipItem,
4609
5721
  DatePicker,
4610
5722
  Divider,
5723
+ Fab,
5724
+ FabMenu,
5725
+ FabMenuItem,
4611
5726
  Typography
4612
5727
  });