alouette 20.2.0 → 20.4.0

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 (69) hide show
  1. package/bin/install-skills.mjs +72 -0
  2. package/dist/definitions/animationDurationsMs.d.ts +3 -0
  3. package/dist/definitions/animationDurationsMs.d.ts.map +1 -1
  4. package/dist/definitions/core/useColorToken.d.ts +9 -0
  5. package/dist/definitions/core/useColorToken.d.ts.map +1 -0
  6. package/dist/definitions/index.d.ts +8 -0
  7. package/dist/definitions/index.d.ts.map +1 -1
  8. package/dist/definitions/ui/containers/AlertDialog.d.ts +78 -0
  9. package/dist/definitions/ui/containers/AlertDialog.d.ts.map +1 -0
  10. package/dist/definitions/ui/containers/AlertDialog.stories.d.ts +33 -0
  11. package/dist/definitions/ui/containers/AlertDialog.stories.d.ts.map +1 -0
  12. package/dist/definitions/ui/containers/Modal.d.ts +66 -0
  13. package/dist/definitions/ui/containers/Modal.d.ts.map +1 -0
  14. package/dist/definitions/ui/containers/Modal.stories.d.ts +31 -0
  15. package/dist/definitions/ui/containers/Modal.stories.d.ts.map +1 -0
  16. package/dist/definitions/ui/feedback/CircularProgress.d.ts +21 -0
  17. package/dist/definitions/ui/feedback/CircularProgress.d.ts.map +1 -0
  18. package/dist/definitions/ui/feedback/CircularProgress.stories.d.ts +38 -0
  19. package/dist/definitions/ui/feedback/CircularProgress.stories.d.ts.map +1 -0
  20. package/dist/definitions/ui/feedback/LinearProgress.d.ts +21 -0
  21. package/dist/definitions/ui/feedback/LinearProgress.d.ts.map +1 -0
  22. package/dist/definitions/ui/feedback/LinearProgress.stories.d.ts +38 -0
  23. package/dist/definitions/ui/feedback/LinearProgress.stories.d.ts.map +1 -0
  24. package/dist/definitions/ui/feedback/RingCircle.d.ts +16 -0
  25. package/dist/definitions/ui/feedback/RingCircle.d.ts.map +1 -0
  26. package/dist/definitions/ui/feedback/RingCircle.web.d.ts +4 -0
  27. package/dist/definitions/ui/feedback/RingCircle.web.d.ts.map +1 -0
  28. package/dist/definitions/ui/feedback/useSimulatedProgress.d.ts +5 -0
  29. package/dist/definitions/ui/feedback/useSimulatedProgress.d.ts.map +1 -0
  30. package/dist/definitions/ui/primitives/Icon.d.ts +2 -1
  31. package/dist/definitions/ui/primitives/Icon.d.ts.map +1 -1
  32. package/dist/definitions/ui/story-components/IndeterminateToggleDemo.d.ts +7 -0
  33. package/dist/definitions/ui/story-components/IndeterminateToggleDemo.d.ts.map +1 -0
  34. package/dist/index-browser.es.js +380 -32
  35. package/dist/index-browser.es.js.map +1 -1
  36. package/dist/index-node22.cjs +411 -28
  37. package/dist/index-node22.cjs.map +1 -1
  38. package/dist/index-node22.mjs +407 -32
  39. package/dist/index-node22.mjs.map +1 -1
  40. package/dist/index-react-native.cjs.js +411 -28
  41. package/dist/index-react-native.cjs.js.map +1 -1
  42. package/dist/index-react-native.es.js +407 -32
  43. package/dist/index-react-native.es.js.map +1 -1
  44. package/package.json +6 -2
  45. package/src/animationDurationsMs.ts +4 -1
  46. package/src/config/defaultColorScales.ts +1 -1
  47. package/src/core/useColorToken.ts +31 -0
  48. package/src/global.css +21 -12
  49. package/src/index.ts +25 -0
  50. package/src/themeVariables.ts +6 -6
  51. package/src/ui/containers/AlertDialog.stories.tsx +425 -0
  52. package/src/ui/containers/AlertDialog.tsx +211 -0
  53. package/src/ui/containers/Box.tsx +1 -1
  54. package/src/ui/containers/Modal.stories.tsx +231 -0
  55. package/src/ui/containers/Modal.tsx +197 -0
  56. package/src/ui/feedback/CircularProgress.stories.tsx +100 -0
  57. package/src/ui/feedback/CircularProgress.tsx +118 -0
  58. package/src/ui/feedback/ConnectionState.tsx +2 -2
  59. package/src/ui/feedback/LinearProgress.stories.tsx +101 -0
  60. package/src/ui/feedback/LinearProgress.tsx +77 -0
  61. package/src/ui/feedback/RingCircle.tsx +83 -0
  62. package/src/ui/feedback/RingCircle.web.tsx +39 -0
  63. package/src/ui/feedback/useSimulatedProgress.ts +66 -0
  64. package/src/ui/inputs/InputText.tsx +1 -1
  65. package/src/ui/inputs/Select.shared.tsx +1 -1
  66. package/src/ui/inputs/Select.web.tsx +2 -2
  67. package/src/ui/inputs/Switch.web.tsx +2 -2
  68. package/src/ui/primitives/Icon.tsx +4 -22
  69. package/src/ui/story-components/IndeterminateToggleDemo.tsx +29 -0
@@ -9,11 +9,14 @@ const reactNative = require('react-native');
9
9
  const reactNativeSafeAreaContext = require('react-native-safe-area-context');
10
10
  const tailwindMerge = require('tailwind-merge');
11
11
  const tailwindVariants = require('tailwind-variants');
12
+ const XRegularIcon = require('alouette-icons/phosphor-icons/XRegularIcon');
12
13
  const CheckRegularIcon = require('alouette-icons/phosphor-icons/CheckRegularIcon');
13
- const CaretDownRegularIcon = require('alouette-icons/phosphor-icons/CaretDownRegularIcon');
14
14
  const InfoRegularIcon = require('alouette-icons/phosphor-icons/InfoRegularIcon');
15
+ const QuestionRegularIcon = require('alouette-icons/phosphor-icons/QuestionRegularIcon');
15
16
  const WarningRegularIcon = require('alouette-icons/phosphor-icons/WarningRegularIcon');
16
- const XRegularIcon = require('alouette-icons/phosphor-icons/XRegularIcon');
17
+ const CaretDownRegularIcon = require('alouette-icons/phosphor-icons/CaretDownRegularIcon');
18
+ const Animated = require('react-native-reanimated');
19
+ const reactNativeSvg = require('react-native-svg');
17
20
  const CaretRightRegularIcon = require('alouette-icons/phosphor-icons/CaretRightRegularIcon');
18
21
  const WebBrowser = require('expo-web-browser');
19
22
 
@@ -54,7 +57,7 @@ const themeVariables = {
54
57
  "--color-interactive-accent-contained-bg-disabled": "#EBEBEB",
55
58
  "--color-interactive-accent-outlined-disabled": "#B8B8B8",
56
59
  "--color-screen": "#EBEBEB",
57
- "--color-surface": "#F5F5F5",
60
+ "--color-surface": "#FAFAFA",
58
61
  "--color-highlight": "#FFFFFF",
59
62
  "--color-enabled": "#C7C7C7",
60
63
  "--color-highlight-accent": "#E0E0E0",
@@ -65,8 +68,8 @@ const themeVariables = {
65
68
  "--color-border-muted": "#8F8F8F",
66
69
  "--color-border-sharp": "#616161",
67
70
  "--color-interactive-contained-pressable": "#FFFFFF",
68
- "--color-interactive-contained-hover": "#F5F5F5",
69
- "--color-interactive-contained-focus": "#F5F5F5",
71
+ "--color-interactive-contained-hover": "#FAFAFA",
72
+ "--color-interactive-contained-focus": "#FAFAFA",
70
73
  "--color-interactive-contained-active": "#EBEBEB",
71
74
  "--color-interactive-outlined-pressable": "#616161",
72
75
  "--color-interactive-outlined-hover": "#8F8F8F",
@@ -83,9 +86,9 @@ const themeVariables = {
83
86
  "--color-on-accent-muted": "#616161",
84
87
  "--color-selection": "#47474740",
85
88
  "--color-interactive-accent-contained-bg": "#EBEBEB",
86
- "--color-interactive-accent-contained-bg-hover": "#F5F5F5",
87
- "--color-interactive-accent-contained-bg-focus": "#F5F5F5",
88
- "--color-interactive-accent-contained-bg-active": "#F5F5F5"
89
+ "--color-interactive-accent-contained-bg-hover": "#FAFAFA",
90
+ "--color-interactive-accent-contained-bg-focus": "#FAFAFA",
91
+ "--color-interactive-accent-contained-bg-active": "#FAFAFA"
89
92
  },
90
93
  "dark": {
91
94
  "--color-translucent": "#1f1e1e55",
@@ -792,7 +795,7 @@ const interactiveBoxVariants = tailwindVariants.tv({
792
795
  base: [
793
796
  boxBaseClasses,
794
797
  "cursor-pointer",
795
- "transition-[transform,background-color,border-color] duration-200 ease-in",
798
+ "transition-[transform,background-color,border-color] duration-fast ease-in",
796
799
  "disabled:cursor-not-allowed disabled:opacity-70 aria-disabled:cursor-not-allowed aria-disabled:opacity-70",
797
800
  "active:scale-[0.975]"
798
801
  ].join(" "),
@@ -1258,23 +1261,12 @@ function PresenceOne({
1258
1261
 
1259
1262
  const animationDurationsMs = {
1260
1263
  "slide": 600,
1261
- "collapse": 800
1264
+ "collapse": 800,
1265
+ "progress": 300,
1266
+ "fade": 300,
1267
+ "fast": 200
1262
1268
  };
1263
1269
 
1264
- function Icon({
1265
- icon,
1266
- size = 20,
1267
- className = "text-sharp"
1268
- }) {
1269
- const token = className.split(/\s+/).find((part) => part.startsWith("text-"))?.slice("text-".length);
1270
- const color = useThemeToken(`--color-${token ?? "sharp"}`);
1271
- return react.cloneElement(icon, {
1272
- color,
1273
- width: size,
1274
- height: size
1275
- });
1276
- }
1277
-
1278
1270
  const pressableBoxVariants = tailwindVariants.tv(
1279
1271
  {
1280
1272
  extend: interactiveBoxVariants,
@@ -1406,6 +1398,24 @@ const PressableBox = react.forwardRef(
1406
1398
  }
1407
1399
  );
1408
1400
 
1401
+ function useColorToken(className) {
1402
+ const token = className.split(/\s+/).find((part) => part.startsWith("text-"))?.slice("text-".length);
1403
+ return useThemeToken(`--color-${token ?? "sharp"}`);
1404
+ }
1405
+
1406
+ function Icon({
1407
+ icon,
1408
+ size = 20,
1409
+ className = "text-sharp"
1410
+ }) {
1411
+ const color = useColorToken(className);
1412
+ return react.cloneElement(icon, {
1413
+ color,
1414
+ width: size,
1415
+ height: size
1416
+ });
1417
+ }
1418
+
1409
1419
  const buttonHeight = {
1410
1420
  sm: 38,
1411
1421
  md: 44
@@ -1617,12 +1627,231 @@ function IconButton({
1617
1627
  );
1618
1628
  }
1619
1629
 
1630
+ const panelVariants = tailwindVariants.tv(
1631
+ {
1632
+ // w-full so the panel shrinks on small screens (the backdrop padding keeps a
1633
+ // margin); max-w caps it on wide viewports.
1634
+ base: "w-full",
1635
+ variants: {
1636
+ size: {
1637
+ sm: "max-w-[360px]",
1638
+ md: "max-w-[520px]",
1639
+ lg: "max-w-[720px]"
1640
+ }
1641
+ },
1642
+ defaultVariants: { size: "md" }
1643
+ },
1644
+ { twMerge: false }
1645
+ );
1646
+ const titleReserveVariants = tailwindVariants.tv(
1647
+ {
1648
+ variants: {
1649
+ size: {
1650
+ sm: "pr-xxl",
1651
+ md: "pr-xl",
1652
+ lg: "pr-xl"
1653
+ }
1654
+ },
1655
+ defaultVariants: { size: "md" }
1656
+ },
1657
+ { twMerge: false }
1658
+ );
1659
+ function Modal({
1660
+ visible,
1661
+ onClose,
1662
+ children,
1663
+ icon,
1664
+ footer,
1665
+ accent,
1666
+ size = "md",
1667
+ title,
1668
+ hideCloseButton = false,
1669
+ closeButtonAriaLabel = "Close",
1670
+ role = "dialog",
1671
+ "aria-describedby": ariaDescribedby,
1672
+ testID,
1673
+ "aria-label": ariaLabel
1674
+ }) {
1675
+ const { height: windowHeight } = reactNative.useWindowDimensions();
1676
+ const titleId = react.useId();
1677
+ return /* @__PURE__ */ jsxRuntime.jsx(AccentScope, { accent, children: /* @__PURE__ */ jsxRuntime.jsx(
1678
+ reactNative.Modal,
1679
+ {
1680
+ transparent: true,
1681
+ visible,
1682
+ animationType: "fade",
1683
+ onRequestClose: onClose,
1684
+ children: /* @__PURE__ */ jsxRuntime.jsxs(View, { className: "flex-1 flex-center p-l", children: [
1685
+ /* @__PURE__ */ jsxRuntime.jsx(
1686
+ reactNative.Pressable,
1687
+ {
1688
+ "aria-hidden": true,
1689
+ focusable: false,
1690
+ className: "absolute inset-0 bg-translucent",
1691
+ onPress: onClose
1692
+ }
1693
+ ),
1694
+ /* @__PURE__ */ jsxRuntime.jsx(
1695
+ View,
1696
+ {
1697
+ "aria-modal": true,
1698
+ role,
1699
+ "aria-label": title === void 0 ? ariaLabel : void 0,
1700
+ "aria-labelledby": title === void 0 ? void 0 : titleId,
1701
+ "aria-describedby": ariaDescribedby,
1702
+ testID,
1703
+ className: `relative ${panelVariants({ size })}`,
1704
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
1705
+ Surface,
1706
+ {
1707
+ variant: "highlight",
1708
+ size,
1709
+ shadow: "l",
1710
+ className: "relative gap-m",
1711
+ children: [
1712
+ title === void 0 && icon === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsxs(
1713
+ HStack,
1714
+ {
1715
+ className: `items-center gap-xs ${hideCloseButton ? "" : titleReserveVariants({ size })}`,
1716
+ children: [
1717
+ icon === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon, size: 24, className: "text-accent" }),
1718
+ title === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(
1719
+ Text,
1720
+ {
1721
+ nativeID: titleId,
1722
+ className: "shrink font-heading-bold text-xl leading-tight text-sharp",
1723
+ children: title
1724
+ }
1725
+ )
1726
+ ]
1727
+ }
1728
+ ),
1729
+ hideCloseButton ? null : /* @__PURE__ */ jsxRuntime.jsx(
1730
+ IconButton,
1731
+ {
1732
+ icon: /* @__PURE__ */ jsxRuntime.jsx(XRegularIcon.XRegularIcon, {}),
1733
+ variant: "ghost",
1734
+ size: size === "lg" ? "md" : size,
1735
+ "aria-label": closeButtonAriaLabel,
1736
+ className: "absolute right-sm top-sm",
1737
+ onPress: onClose
1738
+ }
1739
+ ),
1740
+ /* @__PURE__ */ jsxRuntime.jsx(ScrollView, { style: { maxHeight: windowHeight * 0.7 }, children: /* @__PURE__ */ jsxRuntime.jsx(VStack, { className: "gap-m", children }) }),
1741
+ footer === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(HStack, { className: "items-center justify-end gap-m", children: footer })
1742
+ ]
1743
+ }
1744
+ )
1745
+ }
1746
+ )
1747
+ ] })
1748
+ }
1749
+ ) });
1750
+ }
1751
+
1752
+ function resolveVariant(props, accent) {
1753
+ switch (props.variant) {
1754
+ case "alert": {
1755
+ const { onClose, closeText } = props;
1756
+ return {
1757
+ onDismiss: onClose,
1758
+ footer: /* @__PURE__ */ jsxRuntime.jsx(Button, { accent, text: closeText ?? "OK", onPress: onClose })
1759
+ };
1760
+ }
1761
+ case "required": {
1762
+ const { onConfirm, confirmText, confirmDisabled } = props;
1763
+ return {
1764
+ // Non-dismissible: only the explicit action closes it.
1765
+ onDismiss: () => void 0,
1766
+ footer: /* @__PURE__ */ jsxRuntime.jsx(
1767
+ Button,
1768
+ {
1769
+ accent,
1770
+ text: confirmText ?? "OK",
1771
+ disabled: confirmDisabled,
1772
+ onPress: onConfirm
1773
+ }
1774
+ )
1775
+ };
1776
+ }
1777
+ case "confirm":
1778
+ case void 0:
1779
+ default: {
1780
+ const { onConfirm, onCancel, confirmText, cancelText, confirmDisabled } = props;
1781
+ return {
1782
+ onDismiss: onCancel,
1783
+ footer: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1784
+ /* @__PURE__ */ jsxRuntime.jsx(
1785
+ Button,
1786
+ {
1787
+ variant: "outlined",
1788
+ text: cancelText ?? "Cancel",
1789
+ onPress: onCancel
1790
+ }
1791
+ ),
1792
+ /* @__PURE__ */ jsxRuntime.jsx(
1793
+ Button,
1794
+ {
1795
+ accent,
1796
+ text: confirmText ?? "Confirm",
1797
+ disabled: confirmDisabled,
1798
+ onPress: onConfirm
1799
+ }
1800
+ )
1801
+ ] })
1802
+ };
1803
+ }
1804
+ }
1805
+ }
1806
+ function AlertDialog(props) {
1807
+ const {
1808
+ visible,
1809
+ title,
1810
+ children,
1811
+ accent = "danger",
1812
+ icon,
1813
+ size = "md",
1814
+ testID
1815
+ } = props;
1816
+ const descriptionId = react.useId();
1817
+ const { footer, onDismiss } = resolveVariant(props, accent);
1818
+ return /* @__PURE__ */ jsxRuntime.jsx(
1819
+ Modal,
1820
+ {
1821
+ hideCloseButton: true,
1822
+ visible,
1823
+ role: "alertdialog",
1824
+ accent,
1825
+ size,
1826
+ title,
1827
+ icon,
1828
+ "aria-describedby": children === void 0 ? void 0 : descriptionId,
1829
+ testID,
1830
+ footer,
1831
+ onClose: onDismiss,
1832
+ children: children === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(Text, { nativeID: descriptionId, className: "text-base text-muted", children })
1833
+ }
1834
+ );
1835
+ }
1836
+ function QuestionAlertDialog(props) {
1837
+ return /* @__PURE__ */ jsxRuntime.jsx(AlertDialog, { ...props, icon: /* @__PURE__ */ jsxRuntime.jsx(QuestionRegularIcon.QuestionRegularIcon, {}) });
1838
+ }
1839
+ function WarningAlertDialog(props) {
1840
+ return /* @__PURE__ */ jsxRuntime.jsx(AlertDialog, { ...props, icon: /* @__PURE__ */ jsxRuntime.jsx(WarningRegularIcon.WarningRegularIcon, {}) });
1841
+ }
1842
+ function InfoAlertDialog(props) {
1843
+ return /* @__PURE__ */ jsxRuntime.jsx(AlertDialog, { ...props, icon: /* @__PURE__ */ jsxRuntime.jsx(InfoRegularIcon.InfoRegularIcon, {}) });
1844
+ }
1845
+ function SuccessAlertDialog(props) {
1846
+ return /* @__PURE__ */ jsxRuntime.jsx(AlertDialog, { ...props, icon: /* @__PURE__ */ jsxRuntime.jsx(CheckRegularIcon.CheckRegularIcon, {}) });
1847
+ }
1848
+
1620
1849
  const inputVariants = tailwindVariants.tv(
1621
1850
  {
1622
1851
  base: [
1623
1852
  "bg-highlight text-base text-sharp",
1624
1853
  "border",
1625
- "transition-[border-color,background-color,outline-color] duration-200 ease-in",
1854
+ "transition-[border-color,background-color,outline-color] duration-fast ease-in",
1626
1855
  "outline-interactive-outlined-pressable",
1627
1856
  // to have proper outline color transition
1628
1857
  process.env.EXPO_PUBLIC_STORYBOOK_ENABLED ? "" : "border-interactive-outlined-pressable",
@@ -1773,7 +2002,7 @@ function useControllableValue(controlled, defaultValue, onValueChange) {
1773
2002
  const selectTriggerBaseClassName = [
1774
2003
  "flex-row items-center justify-between gap-xs",
1775
2004
  "rounded-md border px-m py-xs min-h-[44px]",
1776
- "transition-[border-color,outline-color,background-color] duration-200 ease-in"
2005
+ "transition-[border-color,outline-color,background-color] duration-fast ease-in"
1777
2006
  ].join(" ");
1778
2007
  const triggerLabelVariants = tailwindVariants.tv({
1779
2008
  base: "flex-1 text-base",
@@ -2047,8 +2276,154 @@ function ConnectionState({
2047
2276
  return /* @__PURE__ */ jsxRuntime.jsx(AccentScope, { accent, children: /* @__PURE__ */ jsxRuntime.jsx(
2048
2277
  View,
2049
2278
  {
2050
- className: `absolute inset-x-0 top-0 z-9 h-0.5 bg-interactive-contained-pressable shadow-m transition-transform duration-700 ease-in-out ${hidden ? "-translate-y-6" : "translate-y-0"}`,
2051
- children: state ? /* @__PURE__ */ jsxRuntime.jsx(Text, { className: "absolute left-1/2 top-0.5 h-5.5 w-50 -translate-x-1/2 rounded-b-sm bg-interactive-contained-pressable text-center leading-5.5 text-on-accent transition-colors duration-200", children }) : null
2279
+ className: `absolute inset-x-0 top-0 z-9 h-0.5 bg-interactive-contained-pressable shadow-m transition-transform duration-slide ease-in-out ${hidden ? "-translate-y-6" : "translate-y-0"}`,
2280
+ children: state ? /* @__PURE__ */ jsxRuntime.jsx(Text, { className: "absolute left-1/2 top-0.5 h-5.5 w-50 -translate-x-1/2 rounded-b-sm bg-interactive-contained-pressable text-center leading-5.5 text-on-accent transition-colors duration-fast", children }) : null
2281
+ }
2282
+ ) });
2283
+ }
2284
+
2285
+ const track = tailwindVariants.tv({
2286
+ base: "absolute inset-x-0 top-0 z-10 overflow-hidden transition-opacity duration-fade",
2287
+ variants: {
2288
+ size: {
2289
+ xs: "h-0.5",
2290
+ sm: "h-1",
2291
+ md: "h-1.5",
2292
+ lg: "h-2"
2293
+ },
2294
+ hidden: {
2295
+ true: "opacity-0",
2296
+ false: "opacity-100"
2297
+ }
2298
+ },
2299
+ defaultVariants: { size: "md", hidden: false }
2300
+ });
2301
+ function LinearProgress({
2302
+ progress,
2303
+ hidden = false,
2304
+ accent = "brand",
2305
+ size = "md"
2306
+ }) {
2307
+ return /* @__PURE__ */ jsxRuntime.jsx(AccentScope, { accent, children: /* @__PURE__ */ jsxRuntime.jsx(View, { pointerEvents: "none", className: track({ size, hidden }), children: /* @__PURE__ */ jsxRuntime.jsx(
2308
+ View,
2309
+ {
2310
+ className: "h-full bg-accent transition-[width] duration-progress ease-out",
2311
+ style: { width: `${progress}%` }
2312
+ }
2313
+ ) }) });
2314
+ }
2315
+
2316
+ const AnimatedCircle = Animated.createAnimatedComponent(reactNativeSvg.Circle);
2317
+ const easeOut = Animated.Easing.bezier(0, 0, 0.58, 1);
2318
+ function RingCircle({
2319
+ center,
2320
+ radius,
2321
+ strokeWidth,
2322
+ strokeDasharray,
2323
+ strokeDashoffset,
2324
+ color,
2325
+ width,
2326
+ height
2327
+ }) {
2328
+ const animatedOffset = Animated.useSharedValue(strokeDashoffset ?? 0);
2329
+ react.useEffect(() => {
2330
+ animatedOffset.value = Animated.withTiming(strokeDashoffset ?? 0, {
2331
+ duration: animationDurationsMs.progress,
2332
+ easing: easeOut
2333
+ });
2334
+ }, [animatedOffset, strokeDashoffset]);
2335
+ const animatedProps = Animated.useAnimatedProps(() => ({
2336
+ strokeDashoffset: animatedOffset.value
2337
+ }));
2338
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNativeSvg.Svg, { color, width, height, children: strokeDasharray == null ? /* @__PURE__ */ jsxRuntime.jsx(
2339
+ reactNativeSvg.Circle,
2340
+ {
2341
+ cx: center,
2342
+ cy: center,
2343
+ r: radius,
2344
+ stroke: "currentColor",
2345
+ strokeWidth,
2346
+ fill: "none"
2347
+ }
2348
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
2349
+ AnimatedCircle,
2350
+ {
2351
+ animatedProps,
2352
+ cx: center,
2353
+ cy: center,
2354
+ r: radius,
2355
+ stroke: "currentColor",
2356
+ strokeWidth,
2357
+ strokeDasharray,
2358
+ strokeLinecap: "round",
2359
+ transform: `rotate(-90 ${center} ${center})`,
2360
+ fill: "none"
2361
+ }
2362
+ ) });
2363
+ }
2364
+
2365
+ const diameterBySize = {
2366
+ xs: 16,
2367
+ sm: 32,
2368
+ md: 64,
2369
+ lg: 128
2370
+ };
2371
+ const strokeWidthBySize = {
2372
+ xs: 2,
2373
+ sm: 4,
2374
+ md: 8,
2375
+ lg: 16
2376
+ };
2377
+ const ring = tailwindVariants.tv({
2378
+ base: "relative transition-opacity duration-fade",
2379
+ variants: {
2380
+ hidden: {
2381
+ true: "opacity-0",
2382
+ false: "opacity-100"
2383
+ }
2384
+ },
2385
+ defaultVariants: { hidden: false }
2386
+ });
2387
+ function CircularProgress({
2388
+ progress,
2389
+ hidden = false,
2390
+ accent = "brand",
2391
+ size = "md"
2392
+ }) {
2393
+ const diameter = diameterBySize[size];
2394
+ const strokeWidth = strokeWidthBySize[size];
2395
+ const radius = (diameter - strokeWidth) / 2;
2396
+ const circumference = 2 * Math.PI * radius;
2397
+ const clampedProgress = Math.min(Math.max(progress, 0), 100);
2398
+ const dashOffset = circumference * (1 - clampedProgress / 100);
2399
+ const center = diameter / 2;
2400
+ const trackRing = /* @__PURE__ */ jsxRuntime.jsx(RingCircle, { center, radius, strokeWidth });
2401
+ const fillRing = /* @__PURE__ */ jsxRuntime.jsx(
2402
+ RingCircle,
2403
+ {
2404
+ center,
2405
+ radius,
2406
+ strokeWidth,
2407
+ strokeDasharray: circumference,
2408
+ strokeDashoffset: dashOffset
2409
+ }
2410
+ );
2411
+ return /* @__PURE__ */ jsxRuntime.jsx(AccentScope, { accent, children: /* @__PURE__ */ jsxRuntime.jsxs(
2412
+ View,
2413
+ {
2414
+ className: ring({ hidden }),
2415
+ style: { width: diameter, height: diameter },
2416
+ children: [
2417
+ /* @__PURE__ */ jsxRuntime.jsx(View, { className: "absolute inset-0", children: /* @__PURE__ */ jsxRuntime.jsx(
2418
+ Icon,
2419
+ {
2420
+ icon: trackRing,
2421
+ size: diameter,
2422
+ className: "text-highlight-accent"
2423
+ }
2424
+ ) }),
2425
+ /* @__PURE__ */ jsxRuntime.jsx(View, { className: "absolute inset-0", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: fillRing, size: diameter, className: "text-accent" }) })
2426
+ ]
2052
2427
  }
2053
2428
  ) });
2054
2429
  }
@@ -2334,6 +2709,7 @@ function ExternalLink({
2334
2709
  exports.SafeAreaProvider = reactNativeSafeAreaContext.SafeAreaProvider;
2335
2710
  exports.useSafeAreaInsets = reactNativeSafeAreaContext.useSafeAreaInsets;
2336
2711
  exports.AccentScope = AccentScope;
2712
+ exports.AlertDialog = AlertDialog;
2337
2713
  exports.AlouetteDecorator = AlouetteDecorator;
2338
2714
  exports.AlouetteProvider = AlouetteProvider;
2339
2715
  exports.Badge = Badge;
@@ -2341,6 +2717,7 @@ exports.Box = Box;
2341
2717
  exports.BreakpointNameEnum = BreakpointNameEnum;
2342
2718
  exports.Breakpoints = Breakpoints;
2343
2719
  exports.Button = Button;
2720
+ exports.CircularProgress = CircularProgress;
2344
2721
  exports.ConfirmationMessage = ConfirmationMessage;
2345
2722
  exports.ConnectionState = ConnectionState;
2346
2723
  exports.ExternalLink = ExternalLink;
@@ -2351,16 +2728,20 @@ exports.GradientScrollView = GradientScrollView;
2351
2728
  exports.HStack = HStack;
2352
2729
  exports.Icon = Icon;
2353
2730
  exports.IconButton = IconButton;
2731
+ exports.InfoAlertDialog = InfoAlertDialog;
2354
2732
  exports.InfoMessage = InfoMessage;
2355
2733
  exports.InputText = InputText;
2356
2734
  exports.InteractiveBox = InteractiveBox;
2357
2735
  exports.InternalLinkButton = InternalLinkButton;
2736
+ exports.LinearProgress = LinearProgress;
2358
2737
  exports.Message = Message;
2738
+ exports.Modal = Modal;
2359
2739
  exports.Paragraph = Paragraph;
2360
2740
  exports.PresenceList = PresenceList;
2361
2741
  exports.PresenceOne = PresenceOne;
2362
2742
  exports.PressableBox = PressableBox;
2363
2743
  exports.PressableListItem = PressableListItem;
2744
+ exports.QuestionAlertDialog = QuestionAlertDialog;
2364
2745
  exports.SafeAreaBox = SafeAreaBox;
2365
2746
  exports.ScopedTheme = ScopedTheme;
2366
2747
  exports.ScrollView = ScrollView;
@@ -2373,6 +2754,7 @@ exports.StoryContainer = StoryContainer;
2373
2754
  exports.StoryDecorator = StoryDecorator;
2374
2755
  exports.StoryGrid = StoryGrid;
2375
2756
  exports.StoryTitle = StoryTitle;
2757
+ exports.SuccessAlertDialog = SuccessAlertDialog;
2376
2758
  exports.Surface = Surface;
2377
2759
  exports.Switch = Switch;
2378
2760
  exports.SwitchBreakpointsUsingDisplayNone = SwitchBreakpointsUsingDisplayNone;
@@ -2381,6 +2763,7 @@ exports.Text = Text;
2381
2763
  exports.TextArea = TextArea;
2382
2764
  exports.VStack = VStack;
2383
2765
  exports.View = View;
2766
+ exports.WarningAlertDialog = WarningAlertDialog;
2384
2767
  exports.WarningMessage = WarningMessage;
2385
2768
  exports.animationDurationsMs = animationDurationsMs;
2386
2769
  exports.styled = styled;