@vellira-ui/react-native 2.44.2 → 2.44.4

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.
Files changed (2) hide show
  1. package/dist/index.js +113 -15
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1528,8 +1528,26 @@ const createStyles$13 = (theme) => StyleSheet.create({ content: {
1528
1528
  //#endregion
1529
1529
  //#region src/components/Modal/Content/ModalContent.tsx
1530
1530
  const ModalContent = ({ children, style }) => {
1531
- return /* @__PURE__ */ jsx(View, {
1532
- style: [useThemeStyles(createStyles$13).content, style],
1531
+ const styles = useThemeStyles(createStyles$13);
1532
+ const { animation, animationProgress, open } = useModalContext();
1533
+ const closedTranslateY = open ? animation === "slide" ? 16 : 8 : 4;
1534
+ const closedScale = open ? .96 : .98;
1535
+ const animatedStyle = animation === "none" ? void 0 : {
1536
+ opacity: animationProgress,
1537
+ transform: animation === "fade" ? [] : [{ translateY: animationProgress.interpolate({
1538
+ inputRange: [0, 1],
1539
+ outputRange: [closedTranslateY, 0]
1540
+ }) }, ...animation === "scale" ? [{ scale: animationProgress.interpolate({
1541
+ inputRange: [0, 1],
1542
+ outputRange: [closedScale, 1]
1543
+ }) }] : []]
1544
+ };
1545
+ return /* @__PURE__ */ jsx(Animated.View, {
1546
+ style: [
1547
+ styles.content,
1548
+ style,
1549
+ animatedStyle
1550
+ ],
1533
1551
  children
1534
1552
  });
1535
1553
  };
@@ -1582,27 +1600,55 @@ const createStyles$11 = (theme) => StyleSheet.create({
1582
1600
  //#region src/components/Modal/Overlay/ModalOverlay.tsx
1583
1601
  const ModalOverlay = ({ children, overlayStyle }) => {
1584
1602
  const styles = useThemeStyles(createStyles$11);
1585
- const { closeOnOutsidePress, onClose, onOutsideClose, open } = useModalContext();
1603
+ const { animation, animationProgress, closeOnOutsidePress, onClose, onOutsideClose, shouldRender } = useModalContext();
1604
+ const backdropStyle = animation === "none" ? void 0 : { opacity: animationProgress };
1586
1605
  return /* @__PURE__ */ jsx(Modal$1, {
1587
- visible: open,
1606
+ visible: shouldRender,
1588
1607
  transparent: true,
1589
- animationType: "fade",
1608
+ animationType: "none",
1590
1609
  onRequestClose: onClose,
1591
1610
  children: /* @__PURE__ */ jsxs(View, {
1592
1611
  style: [styles.overlay, overlayStyle],
1593
- children: [/* @__PURE__ */ jsx(Pressable, {
1594
- testID: "modal-backdrop",
1595
- accessibilityRole: closeOnOutsidePress ? "button" : void 0,
1596
- accessibilityLabel: closeOnOutsidePress ? "Close modal" : void 0,
1597
- style: styles.backdrop,
1598
- onPress: closeOnOutsidePress ? onOutsideClose : void 0
1612
+ children: [/* @__PURE__ */ jsx(Animated.View, {
1613
+ style: [styles.backdrop, backdropStyle],
1614
+ children: /* @__PURE__ */ jsx(Pressable, {
1615
+ testID: "modal-backdrop",
1616
+ accessibilityRole: closeOnOutsidePress ? "button" : void 0,
1617
+ accessibilityLabel: closeOnOutsidePress ? "Close modal" : void 0,
1618
+ style: StyleSheet.absoluteFill,
1619
+ onPress: closeOnOutsidePress ? onOutsideClose : void 0
1620
+ })
1599
1621
  }), children]
1600
1622
  })
1601
1623
  });
1602
1624
  };
1603
1625
  //#endregion
1604
1626
  //#region src/components/Modal/Root/ModalRoot.tsx
1605
- const ModalRoot = ({ open, defaultOpen = false, onOpenChange, closeOnOutsidePress = true, children }) => {
1627
+ const linearEasing = (value) => value;
1628
+ const easingMap = {
1629
+ standard: Easing?.bezier?.(.22, 1, .36, 1) ?? linearEasing,
1630
+ linear: Easing?.linear ?? linearEasing,
1631
+ ease: Easing?.ease ?? linearEasing,
1632
+ "ease-in": Easing?.in?.(Easing?.ease ?? linearEasing) ?? linearEasing,
1633
+ "ease-out": Easing?.out?.(Easing?.ease ?? linearEasing) ?? linearEasing,
1634
+ "ease-in-out": Easing?.inOut?.(Easing?.ease ?? linearEasing) ?? linearEasing
1635
+ };
1636
+ const parseDuration = (duration) => Number.parseFloat(duration);
1637
+ const resolveDuration = (duration) => {
1638
+ if (typeof duration === "number") return {
1639
+ close: duration,
1640
+ open: duration
1641
+ };
1642
+ return {
1643
+ close: duration?.close ?? parseDuration(nativeThemes.light.components.modal.motion.closeDuration),
1644
+ open: duration?.open ?? parseDuration(nativeThemes.light.components.modal.motion.openDuration)
1645
+ };
1646
+ };
1647
+ const ModalRoot = ({ open, defaultOpen = false, onOpenChange, animation = "scale", duration, easing = "standard", closeOnOutsidePress = true, children }) => {
1648
+ const initialOpen = open ?? defaultOpen;
1649
+ const animationProgress = useRef(new Animated.Value(initialOpen ? 1 : 0));
1650
+ const [shouldRender, setShouldRender] = useState(initialOpen);
1651
+ const [reduceMotion, setReduceMotion] = useState(false);
1606
1652
  const modal = useModal({
1607
1653
  open,
1608
1654
  defaultOpen,
@@ -1615,13 +1661,62 @@ const ModalRoot = ({ open, defaultOpen = false, onOpenChange, closeOnOutsidePres
1615
1661
  closeOnOutsidePress: modal.closeOnOutsidePress,
1616
1662
  requestClose: modal.requestClose
1617
1663
  });
1664
+ const animationDuration = resolveDuration(duration);
1665
+ const shouldAnimate = animation !== "none" && !reduceMotion;
1666
+ useEffect(() => {
1667
+ AccessibilityInfo.isReduceMotionEnabled?.().then(setReduceMotion);
1668
+ const subscription = AccessibilityInfo.addEventListener?.("reduceMotionChanged", setReduceMotion);
1669
+ return () => {
1670
+ subscription?.remove();
1671
+ };
1672
+ }, []);
1673
+ useEffect(() => {
1674
+ const progress = animationProgress.current;
1675
+ if (modal.open) {
1676
+ setShouldRender(true);
1677
+ if (!shouldAnimate) {
1678
+ progress.setValue(1);
1679
+ return;
1680
+ }
1681
+ progress.setValue(0);
1682
+ Animated.timing(progress, {
1683
+ toValue: 1,
1684
+ duration: animationDuration.open,
1685
+ easing: easingMap[easing],
1686
+ useNativeDriver: Platform.OS !== "web"
1687
+ }).start();
1688
+ return;
1689
+ }
1690
+ if (!shouldAnimate) {
1691
+ progress.setValue(0);
1692
+ setShouldRender(false);
1693
+ return;
1694
+ }
1695
+ Animated.timing(progress, {
1696
+ toValue: 0,
1697
+ duration: animationDuration.close,
1698
+ easing: easingMap[easing],
1699
+ useNativeDriver: Platform.OS !== "web"
1700
+ }).start(({ finished }) => {
1701
+ if (finished) setShouldRender(false);
1702
+ });
1703
+ }, [
1704
+ animationDuration.close,
1705
+ animationDuration.open,
1706
+ easing,
1707
+ modal.open,
1708
+ shouldAnimate
1709
+ ]);
1618
1710
  return /* @__PURE__ */ jsx(ModalContext.Provider, {
1619
1711
  value: {
1712
+ animation,
1713
+ animationProgress: animationProgress.current,
1620
1714
  closeOnOutsidePress: modal.closeOnOutsidePress,
1621
1715
  onClose: dismiss.requestClose,
1622
1716
  onOutsideClose: dismiss.requestOutsideClose,
1623
1717
  open: modal.open,
1624
- setOpen: modal.setOpen
1718
+ setOpen: modal.setOpen,
1719
+ shouldRender
1625
1720
  },
1626
1721
  children
1627
1722
  });
@@ -2493,11 +2588,12 @@ const SelectItemRow = ({ option, isSelected, isDisabled, optionStyle, onSelect }
2493
2588
  const { theme } = useTheme();
2494
2589
  const styles = useThemeStyles(createItemStyles);
2495
2590
  const { color, variant, renderOption } = useSelectContext();
2591
+ const [isHovered, setIsHovered] = useState(false);
2496
2592
  const optionPalette = theme.components.select[option.color ?? color][variant].option;
2497
2593
  const getOptionState = (pressed) => {
2498
2594
  if (isDisabled) return theme.components.select.option.disabled;
2499
- if (isSelected) return pressed ? optionPalette.selectedPressed : optionPalette.selected;
2500
- return pressed ? optionPalette.pressed : theme.components.select.option.default;
2595
+ if (isSelected) return pressed ? optionPalette.selectedPressed : isHovered ? optionPalette.selectedHover : optionPalette.selected;
2596
+ return pressed ? optionPalette.pressed : isHovered ? optionPalette.hover : theme.components.select.option.default;
2501
2597
  };
2502
2598
  return /* @__PURE__ */ jsx(Pressable, {
2503
2599
  disabled: isDisabled,
@@ -2509,6 +2605,8 @@ const SelectItemRow = ({ option, isSelected, isDisabled, optionStyle, onSelect }
2509
2605
  disabled: isDisabled
2510
2606
  },
2511
2607
  onPress: () => onSelect(option),
2608
+ onHoverIn: () => setIsHovered(true),
2609
+ onHoverOut: () => setIsHovered(false),
2512
2610
  style: ({ pressed }) => {
2513
2611
  const optionState = getOptionState(pressed);
2514
2612
  return [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vellira-ui/react-native",
3
- "version": "2.44.2",
3
+ "version": "2.44.4",
4
4
  "description": "React Native components for Vellira Design System",
5
5
  "author": "Roman Bakurov",
6
6
  "license": "MIT",