@cdx-ui/components 0.3.4 → 0.3.6

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 (287) hide show
  1. package/README.md +1 -1
  2. package/coverage.svg +1 -1
  3. package/docs/components/bar-chart/content.md +703 -0
  4. package/docs/components/content.md +9 -1
  5. package/docs/components/line-chart/content.md +567 -0
  6. package/docs/components/pie-chart/content.md +493 -0
  7. package/docs/components/progress-segmented/content.md +1 -1
  8. package/docs/components/select/content.md +144 -2
  9. package/docs/components/stepper/content.md +599 -0
  10. package/docs/components/system-alert/content.md +533 -0
  11. package/docs/foundations/expressions/icons/content.md +1 -1
  12. package/docs/foundations/styles/tokens/all-tokens/content.md +2 -1
  13. package/docs/llms.txt +10 -0
  14. package/docs/patterns/content.md +1 -0
  15. package/docs/patterns/dashboard/content.md +423 -19
  16. package/docs/patterns/insights/content.md +590 -0
  17. package/docs/resources/release-notes/0.3.4/content.md +27 -0
  18. package/docs/resources/release-notes/0.3.5/content.md +7 -0
  19. package/docs/resources/release-notes/content.md +2 -0
  20. package/lib/commonjs/components/BarChart/geometry.js +1130 -0
  21. package/lib/commonjs/components/BarChart/geometry.js.map +1 -0
  22. package/lib/commonjs/components/BarChart/index.js +942 -0
  23. package/lib/commonjs/components/BarChart/index.js.map +1 -0
  24. package/lib/commonjs/components/BarChart/styles.js +26 -0
  25. package/lib/commonjs/components/BarChart/styles.js.map +1 -0
  26. package/lib/commonjs/components/Button/index.js +2 -2
  27. package/lib/commonjs/components/Button/index.js.map +1 -1
  28. package/lib/commonjs/components/Chip/styles.js +3 -1
  29. package/lib/commonjs/components/Chip/styles.js.map +1 -1
  30. package/lib/commonjs/components/LineChart/geometry.js +698 -0
  31. package/lib/commonjs/components/LineChart/geometry.js.map +1 -0
  32. package/lib/commonjs/components/LineChart/index.js +747 -0
  33. package/lib/commonjs/components/LineChart/index.js.map +1 -0
  34. package/lib/commonjs/components/LineChart/styles.js +25 -0
  35. package/lib/commonjs/components/LineChart/styles.js.map +1 -0
  36. package/lib/commonjs/components/PieChart/geometry.js +216 -0
  37. package/lib/commonjs/components/PieChart/geometry.js.map +1 -0
  38. package/lib/commonjs/components/PieChart/index.js +476 -0
  39. package/lib/commonjs/components/PieChart/index.js.map +1 -0
  40. package/lib/commonjs/components/PieChart/styles.js +88 -0
  41. package/lib/commonjs/components/PieChart/styles.js.map +1 -0
  42. package/lib/commonjs/components/ProgressCircle/ProgressCircleRing.js +9 -31
  43. package/lib/commonjs/components/ProgressCircle/ProgressCircleRing.js.map +1 -1
  44. package/lib/commonjs/components/ProgressCircle/ProgressRing.js +52 -0
  45. package/lib/commonjs/components/ProgressCircle/ProgressRing.js.map +1 -0
  46. package/lib/commonjs/components/ScrollShadow/useScrollShadow.js +8 -7
  47. package/lib/commonjs/components/ScrollShadow/useScrollShadow.js.map +1 -1
  48. package/lib/commonjs/components/Stepper/index.js +369 -0
  49. package/lib/commonjs/components/Stepper/index.js.map +1 -0
  50. package/lib/commonjs/components/Stepper/styles.js +211 -0
  51. package/lib/commonjs/components/Stepper/styles.js.map +1 -0
  52. package/lib/commonjs/components/Stepper/useStepperLabelFit.js +22 -0
  53. package/lib/commonjs/components/Stepper/useStepperLabelFit.js.map +1 -0
  54. package/lib/commonjs/components/Stepper/useStepperLabelFit.web.js +52 -0
  55. package/lib/commonjs/components/Stepper/useStepperLabelFit.web.js.map +1 -0
  56. package/lib/commonjs/components/Stepper/useStepperRingColors.js +31 -0
  57. package/lib/commonjs/components/Stepper/useStepperRingColors.js.map +1 -0
  58. package/lib/commonjs/components/SystemAlert/animation.js +218 -0
  59. package/lib/commonjs/components/SystemAlert/animation.js.map +1 -0
  60. package/lib/commonjs/components/SystemAlert/index.js +525 -0
  61. package/lib/commonjs/components/SystemAlert/index.js.map +1 -0
  62. package/lib/commonjs/components/SystemAlert/styles.js +178 -0
  63. package/lib/commonjs/components/SystemAlert/styles.js.map +1 -0
  64. package/lib/commonjs/components/SystemAlert/useSystemAlertStatusBarStyle.js +53 -0
  65. package/lib/commonjs/components/SystemAlert/useSystemAlertStatusBarStyle.js.map +1 -0
  66. package/lib/commonjs/components/Tabs/index.js +4 -0
  67. package/lib/commonjs/components/Tabs/index.js.map +1 -1
  68. package/lib/commonjs/components/Tabs/styles.js +1 -1
  69. package/lib/commonjs/components/Tabs/styles.js.map +1 -1
  70. package/lib/commonjs/components/chart/ChartInspector.js +610 -0
  71. package/lib/commonjs/components/chart/ChartInspector.js.map +1 -0
  72. package/lib/commonjs/components/chart/format.js +93 -0
  73. package/lib/commonjs/components/chart/format.js.map +1 -0
  74. package/lib/commonjs/components/chart/index.js +2 -0
  75. package/lib/commonjs/components/chart/index.js.map +1 -0
  76. package/lib/commonjs/components/chart/motion.js +97 -0
  77. package/lib/commonjs/components/chart/motion.js.map +1 -0
  78. package/lib/commonjs/components/chart/palette.js +178 -0
  79. package/lib/commonjs/components/chart/palette.js.map +1 -0
  80. package/lib/commonjs/components/chart/size.js +34 -0
  81. package/lib/commonjs/components/chart/size.js.map +1 -0
  82. package/lib/commonjs/components/chart/ticks.js +59 -0
  83. package/lib/commonjs/components/chart/ticks.js.map +1 -0
  84. package/lib/commonjs/components/chart/types.js +6 -0
  85. package/lib/commonjs/components/chart/types.js.map +1 -0
  86. package/lib/commonjs/components/chart/useChartHostWidth.js +27 -0
  87. package/lib/commonjs/components/chart/useChartHostWidth.js.map +1 -0
  88. package/lib/commonjs/components/index.js +60 -0
  89. package/lib/commonjs/components/index.js.map +1 -1
  90. package/lib/commonjs/figma/SystemAlert.Button.figma.js +28 -0
  91. package/lib/commonjs/figma/SystemAlert.Button.figma.js.map +1 -0
  92. package/lib/commonjs/figma/SystemAlert.Close.figma.js +22 -0
  93. package/lib/commonjs/figma/SystemAlert.Close.figma.js.map +1 -0
  94. package/lib/commonjs/figma/SystemAlert.Description.figma.js +20 -0
  95. package/lib/commonjs/figma/SystemAlert.Description.figma.js.map +1 -0
  96. package/lib/commonjs/figma/SystemAlert.IconButton.figma.js +31 -0
  97. package/lib/commonjs/figma/SystemAlert.IconButton.figma.js.map +1 -0
  98. package/lib/commonjs/figma/SystemAlert.figma.js +48 -0
  99. package/lib/commonjs/figma/SystemAlert.figma.js.map +1 -0
  100. package/lib/module/components/BarChart/geometry.js +1110 -0
  101. package/lib/module/components/BarChart/geometry.js.map +1 -0
  102. package/lib/module/components/BarChart/index.js +936 -0
  103. package/lib/module/components/BarChart/index.js.map +1 -0
  104. package/lib/module/components/BarChart/styles.js +22 -0
  105. package/lib/module/components/BarChart/styles.js.map +1 -0
  106. package/lib/module/components/Button/index.js +2 -2
  107. package/lib/module/components/Button/index.js.map +1 -1
  108. package/lib/module/components/Chip/styles.js +3 -1
  109. package/lib/module/components/Chip/styles.js.map +1 -1
  110. package/lib/module/components/LineChart/geometry.js +685 -0
  111. package/lib/module/components/LineChart/geometry.js.map +1 -0
  112. package/lib/module/components/LineChart/index.js +741 -0
  113. package/lib/module/components/LineChart/index.js.map +1 -0
  114. package/lib/module/components/LineChart/styles.js +21 -0
  115. package/lib/module/components/LineChart/styles.js.map +1 -0
  116. package/lib/module/components/PieChart/geometry.js +209 -0
  117. package/lib/module/components/PieChart/geometry.js.map +1 -0
  118. package/lib/module/components/PieChart/index.js +471 -0
  119. package/lib/module/components/PieChart/index.js.map +1 -0
  120. package/lib/module/components/PieChart/styles.js +84 -0
  121. package/lib/module/components/PieChart/styles.js.map +1 -0
  122. package/lib/module/components/ProgressCircle/ProgressCircleRing.js +10 -32
  123. package/lib/module/components/ProgressCircle/ProgressCircleRing.js.map +1 -1
  124. package/lib/module/components/ProgressCircle/ProgressRing.js +48 -0
  125. package/lib/module/components/ProgressCircle/ProgressRing.js.map +1 -0
  126. package/lib/module/components/ScrollShadow/useScrollShadow.js +8 -7
  127. package/lib/module/components/ScrollShadow/useScrollShadow.js.map +1 -1
  128. package/lib/module/components/Stepper/index.js +360 -0
  129. package/lib/module/components/Stepper/index.js.map +1 -0
  130. package/lib/module/components/Stepper/styles.js +206 -0
  131. package/lib/module/components/Stepper/styles.js.map +1 -0
  132. package/lib/module/components/Stepper/useStepperLabelFit.js +18 -0
  133. package/lib/module/components/Stepper/useStepperLabelFit.js.map +1 -0
  134. package/lib/module/components/Stepper/useStepperLabelFit.web.js +48 -0
  135. package/lib/module/components/Stepper/useStepperLabelFit.web.js.map +1 -0
  136. package/lib/module/components/Stepper/useStepperRingColors.js +28 -0
  137. package/lib/module/components/Stepper/useStepperRingColors.js.map +1 -0
  138. package/lib/module/components/SystemAlert/animation.js +213 -0
  139. package/lib/module/components/SystemAlert/animation.js.map +1 -0
  140. package/lib/module/components/SystemAlert/index.js +515 -0
  141. package/lib/module/components/SystemAlert/index.js.map +1 -0
  142. package/lib/module/components/SystemAlert/styles.js +174 -0
  143. package/lib/module/components/SystemAlert/styles.js.map +1 -0
  144. package/lib/module/components/SystemAlert/useSystemAlertStatusBarStyle.js +49 -0
  145. package/lib/module/components/SystemAlert/useSystemAlertStatusBarStyle.js.map +1 -0
  146. package/lib/module/components/Tabs/index.js +4 -0
  147. package/lib/module/components/Tabs/index.js.map +1 -1
  148. package/lib/module/components/Tabs/styles.js +1 -1
  149. package/lib/module/components/Tabs/styles.js.map +1 -1
  150. package/lib/module/components/chart/ChartInspector.js +600 -0
  151. package/lib/module/components/chart/ChartInspector.js.map +1 -0
  152. package/lib/module/components/chart/format.js +84 -0
  153. package/lib/module/components/chart/format.js.map +1 -0
  154. package/lib/module/components/chart/index.js +2 -0
  155. package/lib/module/components/chart/index.js.map +1 -0
  156. package/lib/module/components/chart/motion.js +89 -0
  157. package/lib/module/components/chart/motion.js.map +1 -0
  158. package/lib/module/components/chart/palette.js +168 -0
  159. package/lib/module/components/chart/palette.js.map +1 -0
  160. package/lib/module/components/chart/size.js +29 -0
  161. package/lib/module/components/chart/size.js.map +1 -0
  162. package/lib/module/components/chart/ticks.js +55 -0
  163. package/lib/module/components/chart/ticks.js.map +1 -0
  164. package/lib/module/components/chart/types.js +4 -0
  165. package/lib/module/components/chart/types.js.map +1 -0
  166. package/lib/module/components/chart/useChartHostWidth.js +23 -0
  167. package/lib/module/components/chart/useChartHostWidth.js.map +1 -0
  168. package/lib/module/components/index.js +5 -0
  169. package/lib/module/components/index.js.map +1 -1
  170. package/lib/module/figma/SystemAlert.Button.figma.js +22 -0
  171. package/lib/module/figma/SystemAlert.Button.figma.js.map +1 -0
  172. package/lib/module/figma/SystemAlert.Close.figma.js +18 -0
  173. package/lib/module/figma/SystemAlert.Close.figma.js.map +1 -0
  174. package/lib/module/figma/SystemAlert.Description.figma.js +14 -0
  175. package/lib/module/figma/SystemAlert.Description.figma.js.map +1 -0
  176. package/lib/module/figma/SystemAlert.IconButton.figma.js +25 -0
  177. package/lib/module/figma/SystemAlert.IconButton.figma.js.map +1 -0
  178. package/lib/module/figma/SystemAlert.figma.js +42 -0
  179. package/lib/module/figma/SystemAlert.figma.js.map +1 -0
  180. package/lib/typescript/components/BarChart/geometry.d.ts +236 -0
  181. package/lib/typescript/components/BarChart/geometry.d.ts.map +1 -0
  182. package/lib/typescript/components/BarChart/index.d.ts +193 -0
  183. package/lib/typescript/components/BarChart/index.d.ts.map +1 -0
  184. package/lib/typescript/components/BarChart/styles.d.ts +32 -0
  185. package/lib/typescript/components/BarChart/styles.d.ts.map +1 -0
  186. package/lib/typescript/components/Chip/styles.d.ts.map +1 -1
  187. package/lib/typescript/components/LineChart/geometry.d.ts +248 -0
  188. package/lib/typescript/components/LineChart/geometry.d.ts.map +1 -0
  189. package/lib/typescript/components/LineChart/index.d.ts +105 -0
  190. package/lib/typescript/components/LineChart/index.d.ts.map +1 -0
  191. package/lib/typescript/components/LineChart/styles.d.ts +12 -0
  192. package/lib/typescript/components/LineChart/styles.d.ts.map +1 -0
  193. package/lib/typescript/components/PieChart/geometry.d.ts +43 -0
  194. package/lib/typescript/components/PieChart/geometry.d.ts.map +1 -0
  195. package/lib/typescript/components/PieChart/index.d.ts +147 -0
  196. package/lib/typescript/components/PieChart/index.d.ts.map +1 -0
  197. package/lib/typescript/components/PieChart/styles.d.ts +27 -0
  198. package/lib/typescript/components/PieChart/styles.d.ts.map +1 -0
  199. package/lib/typescript/components/ProgressCircle/ProgressCircleRing.d.ts.map +1 -1
  200. package/lib/typescript/components/ProgressCircle/ProgressRing.d.ts +17 -0
  201. package/lib/typescript/components/ProgressCircle/ProgressRing.d.ts.map +1 -0
  202. package/lib/typescript/components/ScrollShadow/useScrollShadow.d.ts.map +1 -1
  203. package/lib/typescript/components/Stepper/index.d.ts +68 -0
  204. package/lib/typescript/components/Stepper/index.d.ts.map +1 -0
  205. package/lib/typescript/components/Stepper/styles.d.ts +46 -0
  206. package/lib/typescript/components/Stepper/styles.d.ts.map +1 -0
  207. package/lib/typescript/components/Stepper/useStepperLabelFit.d.ts +15 -0
  208. package/lib/typescript/components/Stepper/useStepperLabelFit.d.ts.map +1 -0
  209. package/lib/typescript/components/Stepper/useStepperLabelFit.web.d.ts +10 -0
  210. package/lib/typescript/components/Stepper/useStepperLabelFit.web.d.ts.map +1 -0
  211. package/lib/typescript/components/Stepper/useStepperRingColors.d.ts +6 -0
  212. package/lib/typescript/components/Stepper/useStepperRingColors.d.ts.map +1 -0
  213. package/lib/typescript/components/SystemAlert/animation.d.ts +56 -0
  214. package/lib/typescript/components/SystemAlert/animation.d.ts.map +1 -0
  215. package/lib/typescript/components/SystemAlert/index.d.ts +110 -0
  216. package/lib/typescript/components/SystemAlert/index.d.ts.map +1 -0
  217. package/lib/typescript/components/SystemAlert/styles.d.ts +38 -0
  218. package/lib/typescript/components/SystemAlert/styles.d.ts.map +1 -0
  219. package/lib/typescript/components/SystemAlert/useSystemAlertStatusBarStyle.d.ts +14 -0
  220. package/lib/typescript/components/SystemAlert/useSystemAlertStatusBarStyle.d.ts.map +1 -0
  221. package/lib/typescript/components/Tabs/index.d.ts.map +1 -1
  222. package/lib/typescript/components/chart/ChartInspector.d.ts +101 -0
  223. package/lib/typescript/components/chart/ChartInspector.d.ts.map +1 -0
  224. package/lib/typescript/components/chart/format.d.ts +16 -0
  225. package/lib/typescript/components/chart/format.d.ts.map +1 -0
  226. package/lib/typescript/components/chart/index.d.ts +3 -0
  227. package/lib/typescript/components/chart/index.d.ts.map +1 -0
  228. package/lib/typescript/components/chart/motion.d.ts +27 -0
  229. package/lib/typescript/components/chart/motion.d.ts.map +1 -0
  230. package/lib/typescript/components/chart/palette.d.ts +44 -0
  231. package/lib/typescript/components/chart/palette.d.ts.map +1 -0
  232. package/lib/typescript/components/chart/size.d.ts +25 -0
  233. package/lib/typescript/components/chart/size.d.ts.map +1 -0
  234. package/lib/typescript/components/chart/ticks.d.ts +3 -0
  235. package/lib/typescript/components/chart/ticks.d.ts.map +1 -0
  236. package/lib/typescript/components/chart/types.d.ts +163 -0
  237. package/lib/typescript/components/chart/types.d.ts.map +1 -0
  238. package/lib/typescript/components/chart/useChartHostWidth.d.ts +9 -0
  239. package/lib/typescript/components/chart/useChartHostWidth.d.ts.map +1 -0
  240. package/lib/typescript/components/index.d.ts +5 -0
  241. package/lib/typescript/components/index.d.ts.map +1 -1
  242. package/lib/typescript/figma/SystemAlert.Button.figma.d.ts +11 -0
  243. package/lib/typescript/figma/SystemAlert.Button.figma.d.ts.map +1 -0
  244. package/lib/typescript/figma/SystemAlert.Close.figma.d.ts +11 -0
  245. package/lib/typescript/figma/SystemAlert.Close.figma.d.ts.map +1 -0
  246. package/lib/typescript/figma/SystemAlert.Description.figma.d.ts +8 -0
  247. package/lib/typescript/figma/SystemAlert.Description.figma.d.ts.map +1 -0
  248. package/lib/typescript/figma/SystemAlert.IconButton.figma.d.ts +11 -0
  249. package/lib/typescript/figma/SystemAlert.IconButton.figma.d.ts.map +1 -0
  250. package/lib/typescript/figma/SystemAlert.figma.d.ts +8 -0
  251. package/lib/typescript/figma/SystemAlert.figma.d.ts.map +1 -0
  252. package/package.json +5 -5
  253. package/src/components/BarChart/geometry.ts +1469 -0
  254. package/src/components/BarChart/index.tsx +1424 -0
  255. package/src/components/BarChart/styles.ts +31 -0
  256. package/src/components/Button/index.tsx +1 -1
  257. package/src/components/Chip/styles.ts +3 -1
  258. package/src/components/LineChart/geometry.ts +957 -0
  259. package/src/components/LineChart/index.tsx +1109 -0
  260. package/src/components/LineChart/styles.ts +26 -0
  261. package/src/components/PieChart/geometry.ts +295 -0
  262. package/src/components/PieChart/index.tsx +715 -0
  263. package/src/components/PieChart/styles.ts +101 -0
  264. package/src/components/ProgressCircle/ProgressCircleRing.tsx +10 -39
  265. package/src/components/ProgressCircle/ProgressRing.tsx +60 -0
  266. package/src/components/ScrollShadow/useScrollShadow.ts +12 -11
  267. package/src/components/Stepper/index.tsx +452 -0
  268. package/src/components/Stepper/styles.ts +234 -0
  269. package/src/components/Stepper/useStepperLabelFit.ts +21 -0
  270. package/src/components/Stepper/useStepperLabelFit.web.ts +53 -0
  271. package/src/components/Stepper/useStepperRingColors.ts +29 -0
  272. package/src/components/SystemAlert/animation.ts +252 -0
  273. package/src/components/SystemAlert/index.tsx +684 -0
  274. package/src/components/SystemAlert/styles.ts +212 -0
  275. package/src/components/SystemAlert/useSystemAlertStatusBarStyle.ts +57 -0
  276. package/src/components/Tabs/index.tsx +4 -0
  277. package/src/components/Tabs/styles.ts +1 -1
  278. package/src/components/chart/ChartInspector.tsx +726 -0
  279. package/src/components/chart/format.ts +95 -0
  280. package/src/components/chart/index.ts +24 -0
  281. package/src/components/chart/motion.ts +98 -0
  282. package/src/components/chart/palette.tsx +247 -0
  283. package/src/components/chart/size.ts +21 -0
  284. package/src/components/chart/ticks.ts +53 -0
  285. package/src/components/chart/types.ts +183 -0
  286. package/src/components/chart/useChartHostWidth.ts +26 -0
  287. package/src/components/index.ts +5 -0
@@ -0,0 +1,684 @@
1
+ import {
2
+ forwardRef,
3
+ useCallback,
4
+ useContext,
5
+ useEffect,
6
+ useLayoutEffect,
7
+ useMemo,
8
+ useRef,
9
+ useState,
10
+ type ComponentType,
11
+ type ForwardedRef,
12
+ type ReactNode,
13
+ } from 'react';
14
+ import {
15
+ AccessibilityInfo,
16
+ Platform,
17
+ Text,
18
+ View,
19
+ type LayoutChangeEvent,
20
+ type TextProps,
21
+ type ViewProps,
22
+ type ViewStyle,
23
+ } from 'react-native';
24
+ import Animated from 'react-native-reanimated';
25
+ import { SafeAreaInsetsContext } from 'react-native-safe-area-context';
26
+ import { Slot, dataAttributes, mergeDataAttributes } from '@cdx-ui/primitives';
27
+ import type { ForgeIcon } from '@cdx-ui/icons';
28
+ import {
29
+ CheckCircle,
30
+ Close,
31
+ EmergencyHome,
32
+ Error as ErrorIcon,
33
+ Info,
34
+ Warning,
35
+ } from '@cdx-ui/icons';
36
+ import {
37
+ cn,
38
+ createContext,
39
+ getTextContent,
40
+ mergeRefs,
41
+ ParentContext,
42
+ useParentContext,
43
+ useStyleContext,
44
+ } from '@cdx-ui/utils';
45
+ import type { AnimationRootDisableAll } from '../../animation';
46
+ import { Button, type ButtonProps } from '../Button';
47
+ import { Icon, type IconProps } from '../Icon';
48
+ import { IconButton, type IconButtonProps } from '../IconButton';
49
+ import {
50
+ useSystemAlertPresence,
51
+ useSystemAlertSurfaceStyle,
52
+ type SystemAlertPresence as SystemAlertPresenceState,
53
+ } from './animation';
54
+ import {
55
+ systemAlertActionLabelVariants,
56
+ systemAlertActionVariants,
57
+ systemAlertActionsVariants,
58
+ systemAlertBodyVariants,
59
+ systemAlertCloseIconVariants,
60
+ systemAlertCloseVariants,
61
+ systemAlertDescriptionVariants,
62
+ systemAlertIconActionIconVariants,
63
+ systemAlertIconActionVariants,
64
+ systemAlertIconVariants,
65
+ systemAlertPresenceClipVariants,
66
+ systemAlertPresenceSurfaceVariants,
67
+ systemAlertPresenceVariants,
68
+ systemAlertRootVariants,
69
+ type SystemAlertColor,
70
+ type SystemAlertVariantProps,
71
+ } from './styles';
72
+
73
+ // =============================================================================
74
+ // CONTEXT
75
+ // =============================================================================
76
+
77
+ const SCOPE = 'SYSTEM_ALERT';
78
+
79
+ interface SystemAlertContextValue {
80
+ color: SystemAlertColor;
81
+ hasClose: boolean;
82
+ }
83
+
84
+ const useSystemAlertStyleContext = (): SystemAlertContextValue => {
85
+ const ctx = useStyleContext(SCOPE) as Partial<SystemAlertContextValue> | undefined;
86
+ return { color: ctx?.color ?? 'info', hasClose: ctx?.hasClose ?? false };
87
+ };
88
+
89
+ interface SystemAlertDescriptionRegistry {
90
+ /** `owner` identifies the Description instance, so one unmounting never clears another's text. */
91
+ registerDescription: (owner: object, text: string | null) => void;
92
+ }
93
+
94
+ // Provided only in presence mode, so a static banner's Description never registers.
95
+ const [SystemAlertDescriptionRegistryProvider, useSystemAlertDescriptionRegistry] = createContext<
96
+ SystemAlertDescriptionRegistry | undefined
97
+ >('SystemAlertDescriptionRegistry', { strict: false });
98
+
99
+ const COLOR_ICONS: Record<SystemAlertColor, ForgeIcon> = {
100
+ danger: EmergencyHome,
101
+ warning: Warning,
102
+ success: CheckCircle,
103
+ info: Info,
104
+ brand: ErrorIcon,
105
+ };
106
+
107
+ // =============================================================================
108
+ // PRESENCE (internal, `isOpen` only)
109
+ // =============================================================================
110
+
111
+ const AnimatedSlot = Animated.createAnimatedComponent(Slot as ComponentType<ViewProps>);
112
+
113
+ // Screen-reader focus on a leaving surface would land somewhere unpredictable.
114
+ const EXITING_SURFACE_PROPS = {
115
+ importantForAccessibility: 'no-hide-descendants',
116
+ accessibilityElementsHidden: true,
117
+ pointerEvents: 'none',
118
+ } as const satisfies ViewProps;
119
+
120
+ // `scroll` clips like `hidden` on iOS and Android, but Yoga caps a child's flex-basis height at
121
+ // its parent's height unless the parent's overflow is `scroll`. Under `hidden`, the moving
122
+ // wrapper's fixed height caps the surface, iOS lays the description out as one clipped line,
123
+ // and the banner jumps by a line when it settles. Inline because Uniwind compiles
124
+ // `overflow-scroll` to `{ x, y }` keys that React Native ignores.
125
+ const NATIVE_WRAPPER_STYLE = { overflow: 'scroll' } as const satisfies ViewStyle;
126
+
127
+ // RNW ignores the native hiding props and deprecates the `pointerEvents` prop.
128
+ const WEB_EXITING_SURFACE_PROPS = { 'aria-hidden': true } as const satisfies ViewProps;
129
+ const WEB_EXITING_SURFACE_STYLE = { pointerEvents: 'none' } as const satisfies ViewStyle;
130
+
131
+ interface SystemAlertPresenceSurfaceProps extends ViewProps {
132
+ presence: SystemAlertPresenceState;
133
+ asChild?: boolean;
134
+ className: string;
135
+ surfaceRef: ForwardedRef<View>;
136
+ }
137
+
138
+ function SystemAlertPresenceSurface({
139
+ presence,
140
+ asChild,
141
+ surfaceRef,
142
+ style,
143
+ onLayout,
144
+ children,
145
+ ...props
146
+ }: SystemAlertPresenceSurfaceProps) {
147
+ const { setSurfaceHeight, phase } = presence;
148
+ const isWeb = Platform.OS === 'web';
149
+ const nodeRef = useRef<View | null>(null);
150
+ const ref = useMemo(() => mergeRefs(surfaceRef, nodeRef), [surfaceRef]);
151
+ const surfaceStyle = useSystemAlertSurfaceStyle(presence);
152
+
153
+ useLayoutEffect(() => {
154
+ const node = nodeRef.current;
155
+ // RNW's `measure` is deferred, which would let the first frames transition toward 0.
156
+ if (isWeb) {
157
+ const element = node as unknown as HTMLElement | null;
158
+ if (typeof element?.getBoundingClientRect === 'function') {
159
+ setSurfaceHeight(element.getBoundingClientRect().height);
160
+ }
161
+ return;
162
+ }
163
+ if (typeof node?.measure !== 'function') return;
164
+ node.measure((_x, _y, _width, height) => {
165
+ setSurfaceHeight(height);
166
+ });
167
+ }, [isWeb, setSurfaceHeight]);
168
+
169
+ const handleLayout = useCallback(
170
+ (event: LayoutChangeEvent) => {
171
+ onLayout?.(event);
172
+ setSurfaceHeight(event.nativeEvent.layout.height);
173
+ },
174
+ [onLayout, setSurfaceHeight],
175
+ );
176
+
177
+ const isExiting = phase === 'exiting';
178
+
179
+ if (isWeb) {
180
+ const WebComp = asChild ? Slot : View;
181
+ return (
182
+ <WebComp
183
+ ref={ref}
184
+ style={[style, isExiting ? WEB_EXITING_SURFACE_STYLE : undefined]}
185
+ {...props}
186
+ {...(isExiting ? WEB_EXITING_SURFACE_PROPS : undefined)}
187
+ onLayout={handleLayout}
188
+ >
189
+ {children}
190
+ </WebComp>
191
+ );
192
+ }
193
+
194
+ const Comp = asChild ? AnimatedSlot : Animated.View;
195
+
196
+ return (
197
+ <Comp
198
+ ref={ref}
199
+ style={[style, surfaceStyle]}
200
+ {...props}
201
+ {...(isExiting ? EXITING_SURFACE_PROPS : undefined)}
202
+ onLayout={handleLayout}
203
+ >
204
+ {children}
205
+ </Comp>
206
+ );
207
+ }
208
+
209
+ interface SystemAlertPresenceProps extends Omit<SystemAlertPresenceSurfaceProps, 'presence'> {
210
+ isOpen: boolean;
211
+ animation: AnimationRootDisableAll | undefined;
212
+ collapsedHeight: number;
213
+ isAssertive: boolean;
214
+ liveRegion: ViewProps['accessibilityLiveRegion'];
215
+ }
216
+
217
+ function SystemAlertPresence({
218
+ isOpen,
219
+ animation,
220
+ collapsedHeight,
221
+ isAssertive,
222
+ liveRegion,
223
+ ...surfaceProps
224
+ }: SystemAlertPresenceProps) {
225
+ const presence = useSystemAlertPresence({ isOpen, animation, collapsedHeight });
226
+
227
+ const descriptionRef = useRef<{ owner: object; text: string } | null>(null);
228
+ const registerDescription = useCallback((owner: object, text: string | null) => {
229
+ if (text !== null) {
230
+ descriptionRef.current = { owner, text };
231
+ } else if (descriptionRef.current?.owner === owner) {
232
+ descriptionRef.current = null;
233
+ }
234
+ }, []);
235
+ const registry = useMemo(() => ({ registerDescription }), [registerDescription]);
236
+
237
+ // iOS has no live regions. Announce on the open edge only, after the newly mounted
238
+ // Description has registered, and without waiting for the slide.
239
+ const wasOpenRef = useRef(isOpen);
240
+ useEffect(() => {
241
+ const wasOpen = wasOpenRef.current;
242
+ wasOpenRef.current = isOpen;
243
+ if (!isOpen || wasOpen || Platform.OS !== 'ios') return;
244
+
245
+ const text = descriptionRef.current?.text ?? '';
246
+ if (!text) {
247
+ if (__DEV__) {
248
+ console.warn(
249
+ '[SystemAlert] Opened without an announcement: `SystemAlert.Description` children must contain text. Text a component resolves itself, outside its children, cannot be read.',
250
+ );
251
+ }
252
+ return;
253
+ }
254
+ AccessibilityInfo.announceForAccessibilityWithOptions(text, { queue: !isAssertive });
255
+ }, [isOpen, isAssertive]);
256
+
257
+ const surface = presence.isSurfaceMounted ? (
258
+ <SystemAlertPresenceSurface presence={presence} {...surfaceProps} />
259
+ ) : null;
260
+
261
+ // Web announces the surface's `role` insertion; an `aria-live` wrapper around it could
262
+ // announce it twice.
263
+ if (Platform.OS === 'web') {
264
+ return (
265
+ <SystemAlertDescriptionRegistryProvider value={registry}>
266
+ <View
267
+ ref={presence.wrapperRef}
268
+ className={systemAlertPresenceVariants()}
269
+ style={{ height: presence.webWrapperHeight, minHeight: collapsedHeight }}
270
+ {...dataAttributes({ state: presence.webState })}
271
+ >
272
+ <View
273
+ className={systemAlertPresenceClipVariants()}
274
+ style={{ height: presence.webWrapperHeight }}
275
+ {...dataAttributes({ state: presence.webState })}
276
+ >
277
+ {surface}
278
+ </View>
279
+ </View>
280
+ </SystemAlertDescriptionRegistryProvider>
281
+ );
282
+ }
283
+
284
+ // The live region sits on the wrapper, which stays mounted while closed, so TalkBack
285
+ // hears the open as a change inside an existing region.
286
+ return (
287
+ <SystemAlertDescriptionRegistryProvider value={registry}>
288
+ <Animated.View
289
+ className={systemAlertPresenceVariants()}
290
+ style={[NATIVE_WRAPPER_STYLE, presence.wrapperStyle]}
291
+ accessibilityLiveRegion={liveRegion}
292
+ >
293
+ {surface}
294
+ </Animated.View>
295
+ </SystemAlertDescriptionRegistryProvider>
296
+ );
297
+ }
298
+
299
+ // =============================================================================
300
+ // ROOT
301
+ // =============================================================================
302
+
303
+ export interface SystemAlertProps extends ViewProps, SystemAlertVariantProps {
304
+ /**
305
+ * Replace the root element with the consumer's child element via `Slot`.
306
+ * When `true`, children render as-is: no body row and no close button.
307
+ * The `color` context is still provided so sub-components receive the correct styles.
308
+ */
309
+ asChild?: boolean;
310
+ /**
311
+ * Colour treatment. Drives the surface, the default icon, and live-region urgency:
312
+ * `danger` and `warning` announce assertively, the rest politely.
313
+ * @default 'info'
314
+ */
315
+ color?: SystemAlertColor;
316
+ /**
317
+ * Pad the top of the root by the top safe-area inset so the surface paints behind
318
+ * the status bar and the content row starts below it. Set `false` for a banner that
319
+ * does not sit at the top edge of the screen. The inset is zero on web and without a
320
+ * safe-area provider.
321
+ * @default true
322
+ */
323
+ hasSafeAreaInset?: boolean;
324
+ /** Renders a dismiss button as the last control in the row. */
325
+ onClose?: () => void;
326
+ /**
327
+ * Accessible name for the dismiss button.
328
+ * @default 'Dismiss alert'
329
+ */
330
+ closeAccessibilityLabel?: string;
331
+ /**
332
+ * Controlled presence. Omit it for a banner that shows while mounted, with no motion.
333
+ * When set, SystemAlert stays mounted and owns presence: `false` → `true` slides the
334
+ * banner down from the top edge and pushes the content below it, and `true` → `false`
335
+ * reverses that, then removes the surface. `true` on first render shows the banner in
336
+ * place without motion. While closed with `hasSafeAreaInset`, a transparent strip the
337
+ * height of the top inset stays reserved, so the header below never applies the inset.
338
+ * Pick one mode per mount: switching between omitted and set is not supported.
339
+ */
340
+ isOpen?: boolean;
341
+ /**
342
+ * Pass `'disable-all'` to open and close in one frame, without motion. Has no effect
343
+ * without `isOpen`.
344
+ */
345
+ animation?: AnimationRootDisableAll;
346
+ className?: string;
347
+ /**
348
+ * Rendered in order inside the content row, typically `SystemAlert.Icon`,
349
+ * `SystemAlert.Description`, and `SystemAlert.Actions`.
350
+ */
351
+ children?: ReactNode;
352
+ }
353
+
354
+ const SystemAlertRoot = forwardRef<View, SystemAlertProps>(
355
+ (
356
+ {
357
+ asChild,
358
+ isOpen,
359
+ animation,
360
+ color = 'info',
361
+ hasSafeAreaInset = true,
362
+ onClose,
363
+ closeAccessibilityLabel = 'Dismiss alert',
364
+ className,
365
+ style,
366
+ children,
367
+ ...props
368
+ },
369
+ ref,
370
+ ) => {
371
+ const insets = useContext(SafeAreaInsetsContext);
372
+ const hasClose = !!onClose;
373
+ const parent = useParentContext();
374
+ const ctx = useMemo(
375
+ () => ({ ...parent, [SCOPE]: { color, hasClose } }),
376
+ [parent, color, hasClose],
377
+ );
378
+
379
+ const isAssertive = color === 'danger' || color === 'warning';
380
+ const role = isAssertive ? 'alert' : 'status';
381
+ const liveRegion = isAssertive ? 'assertive' : 'polite';
382
+ const insetTop = hasSafeAreaInset ? (insets?.top ?? 0) : 0;
383
+ const rootStyle = hasSafeAreaInset ? [{ paddingTop: insetTop }, style] : style;
384
+ const dataProps = mergeDataAttributes(props, dataAttributes({ slot: 'system-alert' }));
385
+
386
+ const body = asChild ? null : (
387
+ <View className={systemAlertBodyVariants()}>
388
+ {children}
389
+ {onClose ? (
390
+ <IconButton
391
+ as={Close}
392
+ variant="ghost"
393
+ size="small"
394
+ onPress={onClose}
395
+ accessibilityLabel={closeAccessibilityLabel}
396
+ className={systemAlertCloseVariants({ color })}
397
+ iconClassName={systemAlertCloseIconVariants({ color })}
398
+ {...dataAttributes({ slot: 'system-alert-close' })}
399
+ />
400
+ ) : null}
401
+ </View>
402
+ );
403
+
404
+ if (isOpen !== undefined) {
405
+ return (
406
+ <ParentContext.Provider value={ctx}>
407
+ <SystemAlertPresence
408
+ isOpen={isOpen}
409
+ animation={animation}
410
+ collapsedHeight={insetTop}
411
+ isAssertive={isAssertive}
412
+ liveRegion={liveRegion}
413
+ surfaceRef={ref}
414
+ asChild={asChild}
415
+ className={cn(
416
+ systemAlertRootVariants({ color }),
417
+ systemAlertPresenceSurfaceVariants(),
418
+ className,
419
+ )}
420
+ style={rootStyle}
421
+ role={role}
422
+ {...props}
423
+ {...dataProps}
424
+ >
425
+ {asChild ? children : body}
426
+ </SystemAlertPresence>
427
+ </ParentContext.Provider>
428
+ );
429
+ }
430
+
431
+ const rootClassName = cn(systemAlertRootVariants({ color }), className);
432
+
433
+ if (asChild) {
434
+ return (
435
+ <ParentContext.Provider value={ctx}>
436
+ <Slot
437
+ ref={ref}
438
+ className={rootClassName}
439
+ style={rootStyle}
440
+ role={role}
441
+ accessibilityLiveRegion={liveRegion}
442
+ {...props}
443
+ {...dataProps}
444
+ >
445
+ {children}
446
+ </Slot>
447
+ </ParentContext.Provider>
448
+ );
449
+ }
450
+
451
+ return (
452
+ <ParentContext.Provider value={ctx}>
453
+ <View
454
+ ref={ref}
455
+ className={rootClassName}
456
+ style={rootStyle}
457
+ role={role}
458
+ accessibilityLiveRegion={liveRegion}
459
+ {...props}
460
+ {...dataProps}
461
+ >
462
+ {body}
463
+ </View>
464
+ </ParentContext.Provider>
465
+ );
466
+ },
467
+ );
468
+
469
+ SystemAlertRoot.displayName = 'SystemAlert';
470
+
471
+ // =============================================================================
472
+ // ICON
473
+ // =============================================================================
474
+
475
+ export interface SystemAlertIconProps extends Omit<IconProps, 'as' | 'color'> {
476
+ asChild?: boolean;
477
+ /**
478
+ * Override the default icon for the current `color` (`EmergencyHome`, `Warning`,
479
+ * `CheckCircle`, `Info`, or `Error` for `brand`). Not required when `asChild` is set.
480
+ */
481
+ as?: ForgeIcon;
482
+ }
483
+
484
+ const SystemAlertIcon = forwardRef<View, SystemAlertIconProps>(
485
+ ({ asChild, as: asOverride, className, style, ...props }, ref) => {
486
+ const { color } = useSystemAlertStyleContext();
487
+ const computedClassName = cn(systemAlertIconVariants({ color }), className);
488
+ const dataProps = mergeDataAttributes(props, dataAttributes({ slot: 'system-alert-icon' }));
489
+
490
+ if (asChild) {
491
+ return (
492
+ <Slot ref={ref} className={computedClassName} style={style} {...props} {...dataProps} />
493
+ );
494
+ }
495
+
496
+ return (
497
+ <Icon
498
+ as={asOverride ?? COLOR_ICONS[color]}
499
+ className={computedClassName}
500
+ style={style}
501
+ {...props}
502
+ {...dataProps}
503
+ />
504
+ );
505
+ },
506
+ );
507
+
508
+ SystemAlertIcon.displayName = 'SystemAlert.Icon';
509
+
510
+ // =============================================================================
511
+ // DESCRIPTION
512
+ // =============================================================================
513
+
514
+ export interface SystemAlertDescriptionProps extends TextProps {
515
+ asChild?: boolean;
516
+ className?: string;
517
+ /**
518
+ * Message text. Wraps by default; pass `numberOfLines` to clamp it. With `isOpen` on the
519
+ * root, its plain text is what iOS announces when the banner opens, so it must be passed
520
+ * as children rather than resolved inside a child component.
521
+ */
522
+ children?: ReactNode;
523
+ }
524
+
525
+ const SystemAlertDescription = forwardRef<Text, SystemAlertDescriptionProps>(
526
+ ({ asChild, className, style, children, ...props }, ref) => {
527
+ const { color } = useSystemAlertStyleContext();
528
+ const registry = useSystemAlertDescriptionRegistry();
529
+ const [owner] = useState(() => ({}));
530
+ const text = registry ? getTextContent(children) : '';
531
+
532
+ useLayoutEffect(() => {
533
+ registry?.registerDescription(owner, text);
534
+ }, [registry, owner, text]);
535
+
536
+ useLayoutEffect(() => () => registry?.registerDescription(owner, null), [registry, owner]);
537
+
538
+ const computedClassName = cn(systemAlertDescriptionVariants({ color }), className);
539
+ const Comp = asChild ? Slot : Text;
540
+
541
+ return (
542
+ <Comp
543
+ ref={ref}
544
+ className={computedClassName}
545
+ style={style}
546
+ {...props}
547
+ {...mergeDataAttributes(props, dataAttributes({ slot: 'system-alert-description' }))}
548
+ >
549
+ {children}
550
+ </Comp>
551
+ );
552
+ },
553
+ );
554
+
555
+ SystemAlertDescription.displayName = 'SystemAlert.Description';
556
+
557
+ // =============================================================================
558
+ // ACTIONS
559
+ // =============================================================================
560
+
561
+ export interface SystemAlertActionsProps extends ViewProps {
562
+ asChild?: boolean;
563
+ className?: string;
564
+ /** Typically `SystemAlert.Action` and `SystemAlert.IconAction`. */
565
+ children?: ReactNode;
566
+ }
567
+
568
+ const SystemAlertActions = forwardRef<View, SystemAlertActionsProps>(
569
+ ({ asChild, className, style, children, ...props }, ref) => {
570
+ const { hasClose } = useSystemAlertStyleContext();
571
+ const computedClassName = cn(systemAlertActionsVariants({ hasClose }), className);
572
+ const Comp = asChild ? Slot : View;
573
+
574
+ return (
575
+ <Comp
576
+ ref={ref}
577
+ className={computedClassName}
578
+ style={style}
579
+ {...props}
580
+ {...mergeDataAttributes(props, dataAttributes({ slot: 'system-alert-actions' }))}
581
+ >
582
+ {children}
583
+ </Comp>
584
+ );
585
+ },
586
+ );
587
+
588
+ SystemAlertActions.displayName = 'SystemAlert.Actions';
589
+
590
+ // =============================================================================
591
+ // ACTION
592
+ // =============================================================================
593
+
594
+ export interface SystemAlertActionProps extends Omit<
595
+ ButtonProps,
596
+ 'variant' | 'color' | 'size' | 'fullWidth' | 'asChild'
597
+ > {
598
+ className?: string;
599
+ /** Label text, rendered inside `Button.Label`. */
600
+ children?: ReactNode;
601
+ }
602
+
603
+ const SystemAlertAction = forwardRef<View, SystemAlertActionProps>(
604
+ ({ className, children, ...props }, ref) => {
605
+ const { color } = useSystemAlertStyleContext();
606
+
607
+ return (
608
+ <Button
609
+ ref={ref}
610
+ variant="ghost"
611
+ size="small"
612
+ className={cn(systemAlertActionVariants({ color }), className)}
613
+ {...props}
614
+ {...mergeDataAttributes(props, dataAttributes({ slot: 'system-alert-action' }))}
615
+ >
616
+ <Button.Label className={systemAlertActionLabelVariants({ color })}>
617
+ {children}
618
+ </Button.Label>
619
+ </Button>
620
+ );
621
+ },
622
+ );
623
+
624
+ SystemAlertAction.displayName = 'SystemAlert.Action';
625
+
626
+ // =============================================================================
627
+ // ICON ACTION
628
+ // =============================================================================
629
+
630
+ export interface SystemAlertIconActionProps extends Omit<
631
+ IconButtonProps,
632
+ 'variant' | 'color' | 'size' | 'accessibilityLabel'
633
+ > {
634
+ /** Forge icon component to render. */
635
+ as: ForgeIcon;
636
+ /** Accessible name. Required: the control has no visible text. */
637
+ accessibilityLabel: string;
638
+ }
639
+
640
+ const SystemAlertIconAction = forwardRef<View, SystemAlertIconActionProps>(
641
+ ({ className, iconClassName, ...props }, ref) => {
642
+ const { color } = useSystemAlertStyleContext();
643
+
644
+ return (
645
+ <IconButton
646
+ ref={ref}
647
+ variant="ghost"
648
+ size="small"
649
+ className={cn(systemAlertIconActionVariants({ color }), className)}
650
+ iconClassName={cn(systemAlertIconActionIconVariants({ color }), iconClassName)}
651
+ {...props}
652
+ {...mergeDataAttributes(props, dataAttributes({ slot: 'system-alert-icon-action' }))}
653
+ />
654
+ );
655
+ },
656
+ );
657
+
658
+ SystemAlertIconAction.displayName = 'SystemAlert.IconAction';
659
+
660
+ // =============================================================================
661
+ // COMPOUND EXPORT
662
+ // =============================================================================
663
+
664
+ type SystemAlertCompoundComponent = typeof SystemAlertRoot & {
665
+ Icon: typeof SystemAlertIcon;
666
+ Description: typeof SystemAlertDescription;
667
+ Actions: typeof SystemAlertActions;
668
+ Action: typeof SystemAlertAction;
669
+ IconAction: typeof SystemAlertIconAction;
670
+ };
671
+
672
+ export const SystemAlert = Object.assign(SystemAlertRoot, {
673
+ Icon: SystemAlertIcon,
674
+ Description: SystemAlertDescription,
675
+ Actions: SystemAlertActions,
676
+ Action: SystemAlertAction,
677
+ IconAction: SystemAlertIconAction,
678
+ }) as SystemAlertCompoundComponent;
679
+
680
+ export type { SystemAlertColor, SystemAlertVariantProps };
681
+ export {
682
+ useSystemAlertStatusBarStyle,
683
+ type SystemAlertStatusBarStyle,
684
+ } from './useSystemAlertStatusBarStyle';