@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.
package/dist/index.cjs CHANGED
@@ -37,6 +37,10 @@ __export(src_exports, {
37
37
  Avatar: () => Avatar,
38
38
  AvatarGroup: () => AvatarGroup,
39
39
  Badge: () => Badge,
40
+ BottomSheet: () => BottomSheet,
41
+ Chip: () => Chip,
42
+ ChipGroup: () => ChipGroup,
43
+ ChipItem: () => ChipItem,
40
44
  DatePicker: () => DatePicker,
41
45
  Divider: () => Divider,
42
46
  Typography: () => Typography
@@ -1441,7 +1445,7 @@ var useAutocompleteVariantStyles = (themeColor, variant, isInvalid) => {
1441
1445
  if ((variant === "outlined" || variant === "faded") && themeColor === "default") {
1442
1446
  borderColor = import_palette2.colors.gray[300];
1443
1447
  }
1444
- const styles12 = {
1448
+ const styles14 = {
1445
1449
  outlined: {
1446
1450
  backgroundColor: "transparent",
1447
1451
  borderWidth: theme.borderWidth.md,
@@ -1466,7 +1470,7 @@ var useAutocompleteVariantStyles = (themeColor, variant, isInvalid) => {
1466
1470
  borderColor
1467
1471
  }
1468
1472
  };
1469
- return styles12[variant];
1473
+ return styles14[variant];
1470
1474
  }, [variant, theme, colorScheme, isInvalid, themeColor]);
1471
1475
  };
1472
1476
  var useAutocompleteLabelStyle = (themeColor, isInvalid, labelSize) => {
@@ -4133,7 +4137,7 @@ var useTypographyVariantStyles = (variant) => {
4133
4137
  fontWeight: theme.fontWeights.normal
4134
4138
  };
4135
4139
  }
4136
- const styles12 = {
4140
+ const styles14 = {
4137
4141
  caption: {
4138
4142
  fontFamily: theme.fontFamilies.body,
4139
4143
  fontSize: theme.fontSizes.xs,
@@ -4185,7 +4189,7 @@ var useTypographyVariantStyles = (variant) => {
4185
4189
  fontWeight: theme.fontWeights.normal
4186
4190
  }
4187
4191
  };
4188
- return styles12[variant];
4192
+ return styles14[variant];
4189
4193
  }, [theme, variant]);
4190
4194
  return variantStyles;
4191
4195
  };
@@ -4224,6 +4228,877 @@ var Typography = ({
4224
4228
  children
4225
4229
  );
4226
4230
  };
4231
+
4232
+ // src/components/chip/chip.tsx
4233
+ var import_react44 = __toESM(require("react"), 1);
4234
+ var import_react_native39 = require("react-native");
4235
+
4236
+ // src/components/chip/chip.style.ts
4237
+ var import_react_native38 = require("react-native");
4238
+ var styles12 = import_react_native38.StyleSheet.create({
4239
+ chip: {
4240
+ flexDirection: "row",
4241
+ alignItems: "center",
4242
+ alignSelf: "flex-start"
4243
+ },
4244
+ text: {
4245
+ fontWeight: "500",
4246
+ includeFontPadding: false,
4247
+ textAlignVertical: "center"
4248
+ },
4249
+ disabled: {
4250
+ opacity: 0.5
4251
+ },
4252
+ avatar: {
4253
+ marginRight: 4
4254
+ },
4255
+ startContent: {
4256
+ marginRight: 4
4257
+ },
4258
+ endContent: {
4259
+ marginLeft: 4
4260
+ },
4261
+ closeButton: {
4262
+ marginLeft: 4,
4263
+ alignItems: "center",
4264
+ justifyContent: "center"
4265
+ },
4266
+ dot: {
4267
+ borderRadius: 9999,
4268
+ marginRight: 6
4269
+ },
4270
+ groupContainer: {
4271
+ flexDirection: "row",
4272
+ flexWrap: "wrap"
4273
+ }
4274
+ });
4275
+
4276
+ // src/components/chip/chip.hook.ts
4277
+ var import_react43 = require("react");
4278
+ var import_core31 = require("@xaui/core");
4279
+ var sizeMap3 = {
4280
+ sm: { height: 32, paddingH: 12, fontSize: 13 },
4281
+ md: { height: 40, paddingH: 16, fontSize: 15 },
4282
+ lg: { height: 44, paddingH: 18, fontSize: 17 }
4283
+ };
4284
+ var dotSizeMap = {
4285
+ sm: 8,
4286
+ md: 10,
4287
+ lg: 11
4288
+ };
4289
+ var closeSizeMap = {
4290
+ sm: 14,
4291
+ md: 16,
4292
+ lg: 17
4293
+ };
4294
+ function useChipSizeStyles(size) {
4295
+ return (0, import_react43.useMemo)(() => {
4296
+ const { height, paddingH, fontSize } = sizeMap3[size];
4297
+ return { height, paddingHorizontal: paddingH, fontSize };
4298
+ }, [size]);
4299
+ }
4300
+ function useChipDotSize(size) {
4301
+ return (0, import_react43.useMemo)(() => dotSizeMap[size], [size]);
4302
+ }
4303
+ function useChipCloseSize(size) {
4304
+ return (0, import_react43.useMemo)(() => closeSizeMap[size], [size]);
4305
+ }
4306
+ function useChipRadiusStyles(radius, height) {
4307
+ const theme = useXUITheme();
4308
+ return (0, import_react43.useMemo)(() => {
4309
+ if (radius === "full") {
4310
+ return { borderRadius: height / 2 };
4311
+ }
4312
+ return { borderRadius: theme.borderRadius[radius] };
4313
+ }, [height, radius, theme.borderRadius]);
4314
+ }
4315
+ function useChipVariantStyles(themeColor, variant) {
4316
+ const theme = useXUITheme();
4317
+ const safeColor = (0, import_core31.getSafeThemeColor)(themeColor);
4318
+ const colorScheme = theme.colors[safeColor];
4319
+ return (0, import_react43.useMemo)(() => {
4320
+ switch (variant) {
4321
+ case "bordered":
4322
+ return {
4323
+ backgroundColor: "transparent",
4324
+ color: colorScheme.main,
4325
+ borderWidth: 2,
4326
+ borderColor: colorScheme.main
4327
+ };
4328
+ case "light":
4329
+ return {
4330
+ backgroundColor: "transparent",
4331
+ color: colorScheme.main
4332
+ };
4333
+ case "flat":
4334
+ return {
4335
+ backgroundColor: colorScheme.background,
4336
+ color: colorScheme.main
4337
+ };
4338
+ case "faded":
4339
+ return {
4340
+ backgroundColor: (0, import_core31.withOpacity)(colorScheme.background, 0.7),
4341
+ color: colorScheme.main,
4342
+ borderWidth: 1,
4343
+ borderColor: (0, import_core31.withOpacity)(colorScheme.main, 0.3)
4344
+ };
4345
+ case "shadow":
4346
+ return {
4347
+ backgroundColor: colorScheme.main,
4348
+ color: colorScheme.foreground,
4349
+ shadow: theme.shadows.sm
4350
+ };
4351
+ case "dot":
4352
+ return {
4353
+ backgroundColor: colorScheme.background,
4354
+ color: colorScheme.main,
4355
+ dotColor: colorScheme.main
4356
+ };
4357
+ case "solid":
4358
+ default:
4359
+ return {
4360
+ backgroundColor: colorScheme.main,
4361
+ color: colorScheme.foreground
4362
+ };
4363
+ }
4364
+ }, [colorScheme, theme, variant]);
4365
+ }
4366
+
4367
+ // src/components/chip/chip.tsx
4368
+ var Chip = ({
4369
+ children,
4370
+ variant = "solid",
4371
+ themeColor = "default",
4372
+ size = "md",
4373
+ radius = "full",
4374
+ avatar,
4375
+ startContent,
4376
+ endContent,
4377
+ isDisabled = false,
4378
+ customAppearance,
4379
+ onClose,
4380
+ onPress
4381
+ }) => {
4382
+ const [isClosed, setIsClosed] = import_react44.default.useState(false);
4383
+ const [isClosing, setIsClosing] = import_react44.default.useState(false);
4384
+ const sizeStyles = useChipSizeStyles(size);
4385
+ const radiusStyles = useChipRadiusStyles(radius, sizeStyles.height);
4386
+ const variantStyles = useChipVariantStyles(themeColor, variant);
4387
+ const dotSize = useChipDotSize(size);
4388
+ const closeSize = useChipCloseSize(size);
4389
+ const isDotVariant = variant === "dot";
4390
+ const hasClose = onClose !== void 0;
4391
+ const isInteractive = onPress !== void 0 || hasClose;
4392
+ const scale = import_react44.default.useRef(new import_react_native39.Animated.Value(1)).current;
4393
+ const opacity = import_react44.default.useRef(new import_react_native39.Animated.Value(1)).current;
4394
+ const isClosingRef = import_react44.default.useRef(false);
4395
+ const colorProgress = import_react44.default.useRef(new import_react_native39.Animated.Value(1)).current;
4396
+ const targetBackgroundColor = variantStyles.backgroundColor ?? "transparent";
4397
+ const targetBorderColor = variantStyles.borderColor ?? "transparent";
4398
+ const targetTextColor = variantStyles.color ?? "#000000";
4399
+ const targetDotColor = variantStyles.dotColor ?? targetTextColor;
4400
+ const previousColorsRef = import_react44.default.useRef({
4401
+ backgroundColor: targetBackgroundColor,
4402
+ borderColor: targetBorderColor,
4403
+ textColor: targetTextColor,
4404
+ dotColor: targetDotColor
4405
+ });
4406
+ import_react44.default.useEffect(() => {
4407
+ if (previousColorsRef.current.backgroundColor === targetBackgroundColor && previousColorsRef.current.borderColor === targetBorderColor && previousColorsRef.current.textColor === targetTextColor && previousColorsRef.current.dotColor === targetDotColor) {
4408
+ return;
4409
+ }
4410
+ colorProgress.setValue(0);
4411
+ import_react_native39.Animated.timing(colorProgress, {
4412
+ toValue: 1,
4413
+ duration: 180,
4414
+ easing: import_react_native39.Easing.out(import_react_native39.Easing.cubic),
4415
+ useNativeDriver: false
4416
+ }).start(() => {
4417
+ previousColorsRef.current = {
4418
+ backgroundColor: targetBackgroundColor,
4419
+ borderColor: targetBorderColor,
4420
+ textColor: targetTextColor,
4421
+ dotColor: targetDotColor
4422
+ };
4423
+ });
4424
+ }, [
4425
+ colorProgress,
4426
+ targetBackgroundColor,
4427
+ targetBorderColor,
4428
+ targetTextColor,
4429
+ targetDotColor
4430
+ ]);
4431
+ const animatedBackgroundColor = colorProgress.interpolate({
4432
+ inputRange: [0, 1],
4433
+ outputRange: [
4434
+ previousColorsRef.current.backgroundColor,
4435
+ targetBackgroundColor
4436
+ ]
4437
+ });
4438
+ const animatedBorderColor = colorProgress.interpolate({
4439
+ inputRange: [0, 1],
4440
+ outputRange: [previousColorsRef.current.borderColor, targetBorderColor]
4441
+ });
4442
+ const animatedTextColor = colorProgress.interpolate({
4443
+ inputRange: [0, 1],
4444
+ outputRange: [previousColorsRef.current.textColor, targetTextColor]
4445
+ });
4446
+ const animatedDotColor = colorProgress.interpolate({
4447
+ inputRange: [0, 1],
4448
+ outputRange: [previousColorsRef.current.dotColor, targetDotColor]
4449
+ });
4450
+ const handlePressIn = import_react44.default.useCallback(() => {
4451
+ if (!isInteractive || isDisabled || isClosing || hasClose) return;
4452
+ import_react_native39.Animated.timing(scale, {
4453
+ toValue: 0.97,
4454
+ duration: 90,
4455
+ easing: import_react_native39.Easing.out(import_react_native39.Easing.cubic),
4456
+ useNativeDriver: true
4457
+ }).start();
4458
+ }, [hasClose, isInteractive, isClosing, isDisabled, scale]);
4459
+ const handlePressOut = import_react44.default.useCallback(() => {
4460
+ if (!isInteractive || isDisabled || isClosing || hasClose) return;
4461
+ import_react_native39.Animated.timing(scale, {
4462
+ toValue: 1,
4463
+ duration: 120,
4464
+ easing: import_react_native39.Easing.out(import_react_native39.Easing.cubic),
4465
+ useNativeDriver: true
4466
+ }).start();
4467
+ }, [hasClose, isInteractive, isClosing, isDisabled, scale]);
4468
+ const handleChipPress = import_react44.default.useCallback(() => {
4469
+ if (isDisabled || isClosing || isClosingRef.current) return;
4470
+ if (hasClose && onClose) {
4471
+ isClosingRef.current = true;
4472
+ setIsClosing(true);
4473
+ import_react_native39.Animated.parallel([
4474
+ import_react_native39.Animated.timing(opacity, {
4475
+ toValue: 0,
4476
+ duration: 180,
4477
+ easing: import_react_native39.Easing.in(import_react_native39.Easing.quad),
4478
+ useNativeDriver: true
4479
+ }),
4480
+ import_react_native39.Animated.timing(scale, {
4481
+ toValue: 0.88,
4482
+ duration: 180,
4483
+ easing: import_react_native39.Easing.in(import_react_native39.Easing.quad),
4484
+ useNativeDriver: true
4485
+ })
4486
+ ]).start(() => {
4487
+ setIsClosed(true);
4488
+ onClose();
4489
+ setIsClosing(false);
4490
+ isClosingRef.current = false;
4491
+ });
4492
+ return;
4493
+ }
4494
+ onPress?.();
4495
+ }, [hasClose, isClosing, isDisabled, onClose, onPress, opacity, scale]);
4496
+ if (isClosed) {
4497
+ return null;
4498
+ }
4499
+ const chipContent = /* @__PURE__ */ import_react44.default.createElement(import_react_native39.Animated.View, { style: { transform: [{ scale }], opacity } }, /* @__PURE__ */ import_react44.default.createElement(
4500
+ import_react_native39.Animated.View,
4501
+ {
4502
+ style: [
4503
+ styles12.chip,
4504
+ {
4505
+ height: sizeStyles.height,
4506
+ paddingHorizontal: sizeStyles.paddingHorizontal,
4507
+ backgroundColor: animatedBackgroundColor,
4508
+ borderWidth: variantStyles.borderWidth,
4509
+ borderColor: animatedBorderColor
4510
+ },
4511
+ radiusStyles,
4512
+ variantStyles.shadow,
4513
+ isDisabled && styles12.disabled,
4514
+ customAppearance?.container
4515
+ ],
4516
+ accessible: true,
4517
+ accessibilityRole: "text"
4518
+ },
4519
+ isDotVariant && /* @__PURE__ */ import_react44.default.createElement(
4520
+ import_react_native39.Animated.View,
4521
+ {
4522
+ style: [
4523
+ styles12.dot,
4524
+ {
4525
+ width: dotSize,
4526
+ height: dotSize,
4527
+ backgroundColor: animatedDotColor
4528
+ },
4529
+ customAppearance?.dot
4530
+ ]
4531
+ }
4532
+ ),
4533
+ avatar && /* @__PURE__ */ import_react44.default.createElement(import_react_native39.View, { style: styles12.avatar }, avatar),
4534
+ startContent && !avatar && /* @__PURE__ */ import_react44.default.createElement(import_react_native39.View, { style: styles12.startContent }, startContent),
4535
+ /* @__PURE__ */ import_react44.default.createElement(
4536
+ import_react_native39.Animated.Text,
4537
+ {
4538
+ style: [
4539
+ styles12.text,
4540
+ { fontSize: sizeStyles.fontSize, color: animatedTextColor },
4541
+ customAppearance?.text
4542
+ ]
4543
+ },
4544
+ children
4545
+ ),
4546
+ endContent && !hasClose && /* @__PURE__ */ import_react44.default.createElement(import_react_native39.View, { style: styles12.endContent }, endContent),
4547
+ hasClose && /* @__PURE__ */ import_react44.default.createElement(
4548
+ import_react_native39.View,
4549
+ {
4550
+ style: [
4551
+ styles12.closeButton,
4552
+ { width: closeSize, height: closeSize },
4553
+ customAppearance?.closeButton
4554
+ ]
4555
+ },
4556
+ /* @__PURE__ */ import_react44.default.createElement(
4557
+ import_react_native39.Animated.Text,
4558
+ {
4559
+ style: {
4560
+ fontSize: closeSize - 2,
4561
+ color: animatedTextColor,
4562
+ lineHeight: closeSize
4563
+ }
4564
+ },
4565
+ "\u2715"
4566
+ )
4567
+ )
4568
+ ));
4569
+ if (isInteractive) {
4570
+ return /* @__PURE__ */ import_react44.default.createElement(
4571
+ import_react_native39.Pressable,
4572
+ {
4573
+ onPress: isDisabled || isClosing ? void 0 : handleChipPress,
4574
+ onPressIn: handlePressIn,
4575
+ onPressOut: handlePressOut,
4576
+ disabled: isDisabled || isClosing
4577
+ },
4578
+ chipContent
4579
+ );
4580
+ }
4581
+ return chipContent;
4582
+ };
4583
+
4584
+ // src/components/chip/chip-group.tsx
4585
+ var import_react47 = __toESM(require("react"), 1);
4586
+ var import_react_native40 = require("react-native");
4587
+
4588
+ // src/components/chip/chip-context.ts
4589
+ var import_react45 = require("react");
4590
+ var ChipGroupContext = (0, import_react45.createContext)(null);
4591
+
4592
+ // src/components/chip/chip-group.hook.ts
4593
+ var import_react46 = require("react");
4594
+ function useChipGroupSelection(selectMode, selectedValues, defaultSelectedValues, onSelectionChange) {
4595
+ const [internalValues, setInternalValues] = (0, import_react46.useState)(
4596
+ defaultSelectedValues ?? []
4597
+ );
4598
+ const isControlled = selectedValues !== void 0;
4599
+ const currentValues = isControlled ? selectedValues : internalValues;
4600
+ const onToggle = (0, import_react46.useCallback)(
4601
+ (value) => {
4602
+ const isSelected = currentValues.includes(value);
4603
+ let nextValues;
4604
+ if (selectMode === "single") {
4605
+ nextValues = isSelected ? [] : [value];
4606
+ } else {
4607
+ nextValues = isSelected ? currentValues.filter((v) => v !== value) : [...currentValues, value];
4608
+ }
4609
+ if (!isControlled) {
4610
+ setInternalValues(nextValues);
4611
+ }
4612
+ onSelectionChange?.(nextValues);
4613
+ },
4614
+ [currentValues, isControlled, onSelectionChange, selectMode]
4615
+ );
4616
+ return (0, import_react46.useMemo)(
4617
+ () => ({ currentValues, onToggle }),
4618
+ [currentValues, onToggle]
4619
+ );
4620
+ }
4621
+
4622
+ // src/components/chip/chip-group.tsx
4623
+ var ChipGroup = ({
4624
+ children,
4625
+ isSelectable = false,
4626
+ selectMode = "single",
4627
+ variant = "solid",
4628
+ themeColor = "default",
4629
+ size = "md",
4630
+ radius = "full",
4631
+ isDisabled = false,
4632
+ selectedValues,
4633
+ defaultSelectedValues,
4634
+ onSelectionChange,
4635
+ spacing = 8,
4636
+ customAppearance
4637
+ }) => {
4638
+ const { currentValues, onToggle } = useChipGroupSelection(
4639
+ selectMode,
4640
+ selectedValues,
4641
+ defaultSelectedValues,
4642
+ onSelectionChange
4643
+ );
4644
+ const contextValue = import_react47.default.useMemo(
4645
+ () => ({
4646
+ variant,
4647
+ themeColor,
4648
+ size,
4649
+ radius,
4650
+ isDisabled,
4651
+ isSelectable,
4652
+ selectMode,
4653
+ selectedValues: currentValues,
4654
+ onToggle
4655
+ }),
4656
+ [
4657
+ variant,
4658
+ themeColor,
4659
+ size,
4660
+ radius,
4661
+ isDisabled,
4662
+ isSelectable,
4663
+ selectMode,
4664
+ currentValues,
4665
+ onToggle
4666
+ ]
4667
+ );
4668
+ return /* @__PURE__ */ import_react47.default.createElement(ChipGroupContext.Provider, { value: contextValue }, /* @__PURE__ */ import_react47.default.createElement(
4669
+ import_react_native40.View,
4670
+ {
4671
+ style: [
4672
+ styles12.groupContainer,
4673
+ { gap: spacing },
4674
+ customAppearance?.container
4675
+ ],
4676
+ accessible: true
4677
+ },
4678
+ children
4679
+ ));
4680
+ };
4681
+
4682
+ // src/components/chip/chip-item.tsx
4683
+ var import_react48 = __toESM(require("react"), 1);
4684
+ function getSelectableVariant(baseVariant, isSelected) {
4685
+ if (isSelected) {
4686
+ return baseVariant;
4687
+ }
4688
+ if (baseVariant === "solid" || baseVariant === "shadow") {
4689
+ return "bordered";
4690
+ }
4691
+ return "light";
4692
+ }
4693
+ var ChipItem = ({
4694
+ value,
4695
+ children,
4696
+ variant,
4697
+ themeColor,
4698
+ avatar,
4699
+ startContent,
4700
+ endContent,
4701
+ isDisabled,
4702
+ customAppearance
4703
+ }) => {
4704
+ const groupContext = (0, import_react48.useContext)(ChipGroupContext);
4705
+ if (!groupContext) {
4706
+ return null;
4707
+ }
4708
+ const resolvedVariant = variant ?? groupContext.variant;
4709
+ const resolvedColor = themeColor ?? groupContext.themeColor;
4710
+ const resolvedDisabled = isDisabled ?? groupContext.isDisabled;
4711
+ const isSelected = groupContext.selectedValues.includes(value);
4712
+ const chipVariant = groupContext.isSelectable ? getSelectableVariant(resolvedVariant, isSelected) : resolvedVariant;
4713
+ const handlePress = groupContext.isSelectable ? () => groupContext.onToggle(value) : void 0;
4714
+ return /* @__PURE__ */ import_react48.default.createElement(
4715
+ Chip,
4716
+ {
4717
+ variant: chipVariant,
4718
+ themeColor: resolvedColor,
4719
+ size: groupContext.size,
4720
+ radius: groupContext.radius,
4721
+ isDisabled: resolvedDisabled,
4722
+ avatar,
4723
+ startContent,
4724
+ endContent,
4725
+ customAppearance,
4726
+ onPress: handlePress
4727
+ },
4728
+ children
4729
+ );
4730
+ };
4731
+
4732
+ // src/components/bottom-sheet/bottom-sheet.tsx
4733
+ var import_react50 = __toESM(require("react"), 1);
4734
+ var import_react_native44 = require("react-native");
4735
+
4736
+ // src/components/bottom-sheet/bottom-sheet.hook.ts
4737
+ var import_react49 = require("react");
4738
+ var import_react_native42 = require("react-native");
4739
+ var import_core34 = require("@xaui/core");
4740
+
4741
+ // src/components/bottom-sheet/bottom-sheet.animation.ts
4742
+ var import_react_native41 = require("react-native");
4743
+ var SPRING_CONFIG = {
4744
+ useNativeDriver: true,
4745
+ speed: 14,
4746
+ bounciness: 4
4747
+ };
4748
+ var TIMING_CONFIG = {
4749
+ duration: 280,
4750
+ easing: import_react_native41.Easing.bezier(0.2, 0, 0, 1),
4751
+ useNativeDriver: true
4752
+ };
4753
+ var runOpenAnimation = (translateY, backdropOpacity, targetTranslateY) => {
4754
+ const animation = import_react_native41.Animated.parallel([
4755
+ import_react_native41.Animated.spring(translateY, {
4756
+ ...SPRING_CONFIG,
4757
+ toValue: targetTranslateY
4758
+ }),
4759
+ import_react_native41.Animated.timing(backdropOpacity, {
4760
+ ...TIMING_CONFIG,
4761
+ toValue: 1
4762
+ })
4763
+ ]);
4764
+ animation.start();
4765
+ return animation;
4766
+ };
4767
+ var runCloseAnimation = (translateY, backdropOpacity, screenHeight, onComplete) => {
4768
+ const animation = import_react_native41.Animated.parallel([
4769
+ import_react_native41.Animated.timing(translateY, {
4770
+ ...TIMING_CONFIG,
4771
+ toValue: screenHeight
4772
+ }),
4773
+ import_react_native41.Animated.timing(backdropOpacity, {
4774
+ ...TIMING_CONFIG,
4775
+ toValue: 0
4776
+ })
4777
+ ]);
4778
+ animation.start(({ finished }) => {
4779
+ if (finished && onComplete) {
4780
+ onComplete();
4781
+ }
4782
+ });
4783
+ return animation;
4784
+ };
4785
+ var runSnapAnimation = (translateY, targetTranslateY) => {
4786
+ const animation = import_react_native41.Animated.spring(translateY, {
4787
+ ...SPRING_CONFIG,
4788
+ toValue: targetTranslateY
4789
+ });
4790
+ animation.start();
4791
+ return animation;
4792
+ };
4793
+
4794
+ // src/components/bottom-sheet/bottom-sheet.hook.ts
4795
+ var DISMISS_VELOCITY_THRESHOLD = 0.5;
4796
+ var DISMISS_DISTANCE_FRACTION = 0.3;
4797
+ var SCREEN_HEIGHT = import_react_native42.Dimensions.get("window").height;
4798
+ var getTranslateYForSnap = (snapFraction) => SCREEN_HEIGHT * (1 - snapFraction);
4799
+ var useBottomSheetAnimation = ({
4800
+ isOpen,
4801
+ snapPoints,
4802
+ initialSnapIndex,
4803
+ enableSwipeToDismiss,
4804
+ disableAnimation,
4805
+ onClose,
4806
+ onSnapChange
4807
+ }) => {
4808
+ const [shouldRender, setShouldRender] = (0, import_react49.useState)(false);
4809
+ const currentSnapIndex = (0, import_react49.useRef)(initialSnapIndex);
4810
+ const animationRef = (0, import_react49.useRef)(null);
4811
+ const translateY = (0, import_react49.useRef)(new import_react_native42.Animated.Value(SCREEN_HEIGHT)).current;
4812
+ const backdropOpacity = (0, import_react49.useRef)(new import_react_native42.Animated.Value(0)).current;
4813
+ const sortedSnapPoints = (0, import_react49.useMemo)(
4814
+ () => [...snapPoints].sort((a, b) => a - b),
4815
+ [snapPoints]
4816
+ );
4817
+ const snapTranslateValues = (0, import_react49.useMemo)(
4818
+ () => sortedSnapPoints.map(getTranslateYForSnap),
4819
+ [sortedSnapPoints]
4820
+ );
4821
+ const open = (0, import_react49.useCallback)(() => {
4822
+ setShouldRender(true);
4823
+ const targetIndex = Math.min(initialSnapIndex, sortedSnapPoints.length - 1);
4824
+ currentSnapIndex.current = targetIndex;
4825
+ if (disableAnimation) {
4826
+ translateY.setValue(snapTranslateValues[targetIndex]);
4827
+ backdropOpacity.setValue(1);
4828
+ return;
4829
+ }
4830
+ translateY.setValue(SCREEN_HEIGHT);
4831
+ backdropOpacity.setValue(0);
4832
+ animationRef.current?.stop();
4833
+ animationRef.current = runOpenAnimation(
4834
+ translateY,
4835
+ backdropOpacity,
4836
+ snapTranslateValues[targetIndex]
4837
+ );
4838
+ }, [
4839
+ initialSnapIndex,
4840
+ sortedSnapPoints,
4841
+ snapTranslateValues,
4842
+ disableAnimation,
4843
+ translateY,
4844
+ backdropOpacity
4845
+ ]);
4846
+ const close = (0, import_react49.useCallback)(() => {
4847
+ if (disableAnimation) {
4848
+ translateY.setValue(SCREEN_HEIGHT);
4849
+ backdropOpacity.setValue(0);
4850
+ setShouldRender(false);
4851
+ onClose?.();
4852
+ return;
4853
+ }
4854
+ animationRef.current?.stop();
4855
+ animationRef.current = runCloseAnimation(
4856
+ translateY,
4857
+ backdropOpacity,
4858
+ SCREEN_HEIGHT,
4859
+ () => {
4860
+ setShouldRender(false);
4861
+ onClose?.();
4862
+ }
4863
+ );
4864
+ }, [disableAnimation, translateY, backdropOpacity, onClose]);
4865
+ const snapTo = (0, import_react49.useCallback)(
4866
+ (index) => {
4867
+ const clampedIndex = Math.max(0, Math.min(index, sortedSnapPoints.length - 1));
4868
+ currentSnapIndex.current = clampedIndex;
4869
+ onSnapChange?.(clampedIndex);
4870
+ if (disableAnimation) {
4871
+ translateY.setValue(snapTranslateValues[clampedIndex]);
4872
+ return;
4873
+ }
4874
+ animationRef.current?.stop();
4875
+ animationRef.current = runSnapAnimation(
4876
+ translateY,
4877
+ snapTranslateValues[clampedIndex]
4878
+ );
4879
+ },
4880
+ [sortedSnapPoints, snapTranslateValues, disableAnimation, translateY, onSnapChange]
4881
+ );
4882
+ (0, import_react49.useEffect)(() => {
4883
+ if (isOpen) {
4884
+ open();
4885
+ } else if (shouldRender) {
4886
+ close();
4887
+ }
4888
+ }, [isOpen]);
4889
+ const panResponder = (0, import_react49.useMemo)(
4890
+ () => import_react_native42.PanResponder.create({
4891
+ onStartShouldSetPanResponder: () => true,
4892
+ onMoveShouldSetPanResponder: (_, gestureState) => Math.abs(gestureState.dy) > 5,
4893
+ onPanResponderMove: (_, gestureState) => {
4894
+ const currentTranslate = snapTranslateValues[currentSnapIndex.current];
4895
+ const newTranslateY = currentTranslate + gestureState.dy;
4896
+ const maxExpanded = snapTranslateValues[snapTranslateValues.length - 1];
4897
+ const clamped = Math.max(maxExpanded, newTranslateY);
4898
+ translateY.setValue(clamped);
4899
+ },
4900
+ onPanResponderRelease: (_, gestureState) => {
4901
+ const currentTranslate = snapTranslateValues[currentSnapIndex.current];
4902
+ const finalPosition = currentTranslate + gestureState.dy;
4903
+ if (enableSwipeToDismiss && (gestureState.vy > DISMISS_VELOCITY_THRESHOLD || finalPosition > SCREEN_HEIGHT * (1 - sortedSnapPoints[0] * DISMISS_DISTANCE_FRACTION))) {
4904
+ close();
4905
+ return;
4906
+ }
4907
+ if (gestureState.vy < -DISMISS_VELOCITY_THRESHOLD) {
4908
+ const nextIndex = Math.min(
4909
+ currentSnapIndex.current + 1,
4910
+ sortedSnapPoints.length - 1
4911
+ );
4912
+ snapTo(nextIndex);
4913
+ return;
4914
+ }
4915
+ if (gestureState.vy > DISMISS_VELOCITY_THRESHOLD) {
4916
+ const prevIndex = Math.max(currentSnapIndex.current - 1, 0);
4917
+ if (prevIndex === currentSnapIndex.current && enableSwipeToDismiss) {
4918
+ close();
4919
+ return;
4920
+ }
4921
+ snapTo(prevIndex);
4922
+ return;
4923
+ }
4924
+ let closestIndex = 0;
4925
+ let minDistance = Infinity;
4926
+ snapTranslateValues.forEach((snapVal, index) => {
4927
+ const distance = Math.abs(finalPosition - snapVal);
4928
+ if (distance < minDistance) {
4929
+ minDistance = distance;
4930
+ closestIndex = index;
4931
+ }
4932
+ });
4933
+ snapTo(closestIndex);
4934
+ }
4935
+ }),
4936
+ [
4937
+ snapTranslateValues,
4938
+ sortedSnapPoints,
4939
+ enableSwipeToDismiss,
4940
+ translateY,
4941
+ close,
4942
+ snapTo
4943
+ ]
4944
+ );
4945
+ return {
4946
+ shouldRender,
4947
+ translateY,
4948
+ backdropOpacity,
4949
+ panResponder,
4950
+ close,
4951
+ snapTo,
4952
+ screenHeight: SCREEN_HEIGHT
4953
+ };
4954
+ };
4955
+ var useBottomSheetStyles = (themeColor, radius) => {
4956
+ const theme = useXUITheme();
4957
+ const safeThemeColor = (0, import_core34.getSafeThemeColor)(themeColor);
4958
+ const colorScheme = theme.colors[safeThemeColor];
4959
+ const sheetStyles = (0, import_react49.useMemo)(
4960
+ () => ({
4961
+ backgroundColor: colorScheme.background ?? theme.colors.background ?? "#ffffff",
4962
+ borderTopLeftRadius: theme.borderRadius[radius],
4963
+ borderTopRightRadius: theme.borderRadius[radius]
4964
+ }),
4965
+ [theme, colorScheme, radius]
4966
+ );
4967
+ const handleIndicatorColor = (0, import_react49.useMemo)(
4968
+ () => theme.mode === "dark" ? `${colorScheme.main}60` : `${colorScheme.main}40`,
4969
+ [theme, colorScheme]
4970
+ );
4971
+ return { sheetStyles, handleIndicatorColor };
4972
+ };
4973
+
4974
+ // src/components/bottom-sheet/bottom-sheet.style.ts
4975
+ var import_react_native43 = require("react-native");
4976
+ var styles13 = import_react_native43.StyleSheet.create({
4977
+ backdrop: {
4978
+ position: "absolute",
4979
+ top: 0,
4980
+ left: 0,
4981
+ right: 0,
4982
+ bottom: 0,
4983
+ backgroundColor: "rgba(0, 0, 0, 0.5)"
4984
+ },
4985
+ container: {
4986
+ position: "absolute",
4987
+ left: 0,
4988
+ right: 0,
4989
+ bottom: 0
4990
+ },
4991
+ sheet: {
4992
+ overflow: "hidden"
4993
+ },
4994
+ handle: {
4995
+ alignItems: "center",
4996
+ justifyContent: "center",
4997
+ paddingVertical: 10
4998
+ },
4999
+ handleIndicator: {
5000
+ width: 36,
5001
+ height: 4,
5002
+ borderRadius: 2
5003
+ },
5004
+ content: {
5005
+ flex: 1
5006
+ }
5007
+ });
5008
+
5009
+ // src/components/bottom-sheet/bottom-sheet.tsx
5010
+ var BottomSheet = ({
5011
+ children,
5012
+ isOpen,
5013
+ snapPoints = [0.4, 0.9],
5014
+ initialSnapIndex = 0,
5015
+ themeColor = "default",
5016
+ radius = "lg",
5017
+ showBackdrop = true,
5018
+ closeOnBackdropPress = true,
5019
+ enableSwipeToDismiss = true,
5020
+ showHandle = true,
5021
+ disableAnimation = false,
5022
+ style,
5023
+ handleContent,
5024
+ onClose,
5025
+ onSnapChange
5026
+ }) => {
5027
+ const {
5028
+ shouldRender,
5029
+ translateY,
5030
+ backdropOpacity,
5031
+ panResponder,
5032
+ close,
5033
+ screenHeight
5034
+ } = useBottomSheetAnimation({
5035
+ isOpen,
5036
+ snapPoints,
5037
+ initialSnapIndex,
5038
+ enableSwipeToDismiss,
5039
+ disableAnimation,
5040
+ onClose,
5041
+ onSnapChange
5042
+ });
5043
+ const { sheetStyles, handleIndicatorColor } = useBottomSheetStyles(
5044
+ themeColor,
5045
+ radius
5046
+ );
5047
+ if (!shouldRender) {
5048
+ return null;
5049
+ }
5050
+ const handleBackdropPress = () => {
5051
+ if (closeOnBackdropPress) {
5052
+ close();
5053
+ }
5054
+ };
5055
+ return /* @__PURE__ */ import_react50.default.createElement(Portal, null, showBackdrop && /* @__PURE__ */ import_react50.default.createElement(
5056
+ import_react_native44.Animated.View,
5057
+ {
5058
+ style: [styles13.backdrop, { opacity: backdropOpacity }]
5059
+ },
5060
+ /* @__PURE__ */ import_react50.default.createElement(
5061
+ import_react_native44.Pressable,
5062
+ {
5063
+ style: styles13.backdrop,
5064
+ onPress: handleBackdropPress
5065
+ }
5066
+ )
5067
+ ), /* @__PURE__ */ import_react50.default.createElement(
5068
+ import_react_native44.Animated.View,
5069
+ {
5070
+ style: [
5071
+ styles13.container,
5072
+ {
5073
+ height: screenHeight,
5074
+ transform: [{ translateY }]
5075
+ }
5076
+ ]
5077
+ },
5078
+ /* @__PURE__ */ import_react50.default.createElement(
5079
+ import_react_native44.View,
5080
+ {
5081
+ style: [
5082
+ styles13.sheet,
5083
+ { height: screenHeight },
5084
+ sheetStyles,
5085
+ style
5086
+ ],
5087
+ ...panResponder.panHandlers
5088
+ },
5089
+ showHandle && /* @__PURE__ */ import_react50.default.createElement(import_react_native44.View, { style: styles13.handle }, handleContent ?? /* @__PURE__ */ import_react50.default.createElement(
5090
+ import_react_native44.View,
5091
+ {
5092
+ style: [
5093
+ styles13.handleIndicator,
5094
+ { backgroundColor: handleIndicatorColor }
5095
+ ]
5096
+ }
5097
+ )),
5098
+ /* @__PURE__ */ import_react50.default.createElement(import_react_native44.View, { style: styles13.content }, children)
5099
+ )
5100
+ ));
5101
+ };
4227
5102
  // Annotate the CommonJS export names for ESM import in node:
4228
5103
  0 && (module.exports = {
4229
5104
  ActivityIndicator,
@@ -4233,6 +5108,10 @@ var Typography = ({
4233
5108
  Avatar,
4234
5109
  AvatarGroup,
4235
5110
  Badge,
5111
+ BottomSheet,
5112
+ Chip,
5113
+ ChipGroup,
5114
+ ChipItem,
4236
5115
  DatePicker,
4237
5116
  Divider,
4238
5117
  Typography