@oxyhq/bloom 0.4.0 → 0.5.1

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 (275) hide show
  1. package/README.md +105 -90
  2. package/lib/commonjs/bottom-sheet/index.js +2 -2
  3. package/lib/commonjs/context-menu/index.js +18 -19
  4. package/lib/commonjs/context-menu/index.js.map +1 -1
  5. package/lib/commonjs/dialog/BloomDialogProvider.js +61 -0
  6. package/lib/commonjs/dialog/BloomDialogProvider.js.map +1 -0
  7. package/lib/commonjs/dialog/BloomDialogProvider.web.js +45 -0
  8. package/lib/commonjs/dialog/BloomDialogProvider.web.js.map +1 -0
  9. package/lib/commonjs/dialog/Dialog.js +197 -100
  10. package/lib/commonjs/dialog/Dialog.js.map +1 -1
  11. package/lib/commonjs/dialog/Dialog.web.js +194 -84
  12. package/lib/commonjs/dialog/Dialog.web.js.map +1 -1
  13. package/lib/commonjs/dialog/SheetShell.js +149 -0
  14. package/lib/commonjs/dialog/SheetShell.js.map +1 -0
  15. package/lib/commonjs/dialog/alert-store.js +116 -0
  16. package/lib/commonjs/dialog/alert-store.js.map +1 -0
  17. package/lib/commonjs/dialog/alert.js +38 -0
  18. package/lib/commonjs/dialog/alert.js.map +1 -0
  19. package/lib/commonjs/dialog/context.js +10 -2
  20. package/lib/commonjs/dialog/context.js.map +1 -1
  21. package/lib/commonjs/dialog/index.js +8 -24
  22. package/lib/commonjs/dialog/index.js.map +1 -1
  23. package/lib/commonjs/dialog/index.web.js +10 -20
  24. package/lib/commonjs/dialog/index.web.js.map +1 -1
  25. package/lib/commonjs/fonts/FontLoader.js +6 -5
  26. package/lib/commonjs/fonts/FontLoader.js.map +1 -1
  27. package/lib/commonjs/fonts/apply-font-faces.js +4 -4
  28. package/lib/commonjs/fonts/apply-font-faces.web.js +13 -12
  29. package/lib/commonjs/fonts/apply-font-faces.web.js.map +1 -1
  30. package/lib/commonjs/fonts/font-assets.js +2 -2
  31. package/lib/commonjs/fonts/font-data.web.js +22 -0
  32. package/lib/commonjs/fonts/font-data.web.js.map +1 -0
  33. package/lib/commonjs/index.js +101 -66
  34. package/lib/commonjs/index.js.map +1 -1
  35. package/lib/commonjs/index.web.js +101 -66
  36. package/lib/commonjs/index.web.js.map +1 -1
  37. package/lib/commonjs/menu/index.js +21 -23
  38. package/lib/commonjs/menu/index.js.map +1 -1
  39. package/lib/commonjs/select/index.js +26 -27
  40. package/lib/commonjs/select/index.js.map +1 -1
  41. package/lib/commonjs/toast/index.js +42 -13
  42. package/lib/commonjs/toast/index.js.map +1 -1
  43. package/lib/commonjs/toast/index.web.js +19 -15
  44. package/lib/commonjs/toast/index.web.js.map +1 -1
  45. package/lib/module/bottom-sheet/index.js +2 -2
  46. package/lib/module/context-menu/index.js +15 -16
  47. package/lib/module/context-menu/index.js.map +1 -1
  48. package/lib/module/dialog/BloomDialogProvider.js +57 -0
  49. package/lib/module/dialog/BloomDialogProvider.js.map +1 -0
  50. package/lib/module/dialog/BloomDialogProvider.web.js +41 -0
  51. package/lib/module/dialog/BloomDialogProvider.web.js.map +1 -0
  52. package/lib/module/dialog/Dialog.js +199 -87
  53. package/lib/module/dialog/Dialog.js.map +1 -1
  54. package/lib/module/dialog/Dialog.web.js +195 -70
  55. package/lib/module/dialog/Dialog.web.js.map +1 -1
  56. package/lib/module/dialog/SheetShell.js +143 -0
  57. package/lib/module/dialog/SheetShell.js.map +1 -0
  58. package/lib/module/dialog/alert-store.js +107 -0
  59. package/lib/module/dialog/alert-store.js.map +1 -0
  60. package/lib/module/dialog/alert.js +35 -0
  61. package/lib/module/dialog/alert.js.map +1 -0
  62. package/lib/module/dialog/context.js +10 -2
  63. package/lib/module/dialog/context.js.map +1 -1
  64. package/lib/module/dialog/index.js +3 -1
  65. package/lib/module/dialog/index.js.map +1 -1
  66. package/lib/module/dialog/index.web.js +9 -7
  67. package/lib/module/dialog/index.web.js.map +1 -1
  68. package/lib/module/fonts/FontLoader.js +6 -5
  69. package/lib/module/fonts/FontLoader.js.map +1 -1
  70. package/lib/module/fonts/apply-font-faces.js +4 -4
  71. package/lib/module/fonts/apply-font-faces.web.js +13 -10
  72. package/lib/module/fonts/apply-font-faces.web.js.map +1 -1
  73. package/lib/module/fonts/font-assets.js +2 -2
  74. package/lib/module/fonts/font-data.web.js +18 -0
  75. package/lib/module/fonts/font-data.web.js.map +1 -0
  76. package/lib/module/fonts/index.web.js +4 -4
  77. package/lib/module/index.js +2 -3
  78. package/lib/module/index.js.map +1 -1
  79. package/lib/module/index.web.js +2 -3
  80. package/lib/module/index.web.js.map +1 -1
  81. package/lib/module/menu/index.js +11 -13
  82. package/lib/module/menu/index.js.map +1 -1
  83. package/lib/module/select/index.js +27 -28
  84. package/lib/module/select/index.js.map +1 -1
  85. package/lib/module/toast/index.js +41 -11
  86. package/lib/module/toast/index.js.map +1 -1
  87. package/lib/module/toast/index.web.js +18 -13
  88. package/lib/module/toast/index.web.js.map +1 -1
  89. package/lib/typescript/commonjs/bottom-sheet/index.d.ts +1 -1
  90. package/lib/typescript/commonjs/context-menu/index.d.ts +4 -3
  91. package/lib/typescript/commonjs/context-menu/index.d.ts.map +1 -1
  92. package/lib/typescript/commonjs/dialog/BloomDialogProvider.d.ts +27 -0
  93. package/lib/typescript/commonjs/dialog/BloomDialogProvider.d.ts.map +1 -0
  94. package/lib/typescript/commonjs/dialog/BloomDialogProvider.web.d.ts +15 -0
  95. package/lib/typescript/commonjs/dialog/BloomDialogProvider.web.d.ts.map +1 -0
  96. package/lib/typescript/commonjs/dialog/Dialog.d.ts +37 -10
  97. package/lib/typescript/commonjs/dialog/Dialog.d.ts.map +1 -1
  98. package/lib/typescript/commonjs/dialog/Dialog.web.d.ts +26 -10
  99. package/lib/typescript/commonjs/dialog/Dialog.web.d.ts.map +1 -1
  100. package/lib/typescript/commonjs/dialog/SheetShell.d.ts +31 -0
  101. package/lib/typescript/commonjs/dialog/SheetShell.d.ts.map +1 -0
  102. package/lib/typescript/commonjs/dialog/alert-store.d.ts +70 -0
  103. package/lib/typescript/commonjs/dialog/alert-store.d.ts.map +1 -0
  104. package/lib/typescript/commonjs/dialog/alert.d.ts +27 -0
  105. package/lib/typescript/commonjs/dialog/alert.d.ts.map +1 -0
  106. package/lib/typescript/commonjs/dialog/context.d.ts +7 -0
  107. package/lib/typescript/commonjs/dialog/context.d.ts.map +1 -1
  108. package/lib/typescript/commonjs/dialog/index.d.ts +5 -2
  109. package/lib/typescript/commonjs/dialog/index.d.ts.map +1 -1
  110. package/lib/typescript/commonjs/dialog/index.web.d.ts +5 -2
  111. package/lib/typescript/commonjs/dialog/index.web.d.ts.map +1 -1
  112. package/lib/typescript/commonjs/dialog/types.d.ts +70 -15
  113. package/lib/typescript/commonjs/dialog/types.d.ts.map +1 -1
  114. package/lib/typescript/commonjs/fonts/FontLoader.d.ts.map +1 -1
  115. package/lib/typescript/commonjs/fonts/apply-font-faces.web.d.ts +8 -1
  116. package/lib/typescript/commonjs/fonts/apply-font-faces.web.d.ts.map +1 -1
  117. package/lib/typescript/commonjs/fonts/font-data.web.d.ts +5 -0
  118. package/lib/typescript/commonjs/fonts/font-data.web.d.ts.map +1 -0
  119. package/lib/typescript/commonjs/index.d.ts +3 -3
  120. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  121. package/lib/typescript/commonjs/index.web.d.ts +3 -3
  122. package/lib/typescript/commonjs/index.web.d.ts.map +1 -1
  123. package/lib/typescript/commonjs/menu/index.d.ts +4 -4
  124. package/lib/typescript/commonjs/menu/index.d.ts.map +1 -1
  125. package/lib/typescript/commonjs/select/index.d.ts.map +1 -1
  126. package/lib/typescript/commonjs/toast/index.d.ts +32 -3
  127. package/lib/typescript/commonjs/toast/index.d.ts.map +1 -1
  128. package/lib/typescript/commonjs/toast/index.web.d.ts +14 -7
  129. package/lib/typescript/commonjs/toast/index.web.d.ts.map +1 -1
  130. package/lib/typescript/module/bottom-sheet/index.d.ts +1 -1
  131. package/lib/typescript/module/context-menu/index.d.ts +4 -3
  132. package/lib/typescript/module/context-menu/index.d.ts.map +1 -1
  133. package/lib/typescript/module/dialog/BloomDialogProvider.d.ts +27 -0
  134. package/lib/typescript/module/dialog/BloomDialogProvider.d.ts.map +1 -0
  135. package/lib/typescript/module/dialog/BloomDialogProvider.web.d.ts +15 -0
  136. package/lib/typescript/module/dialog/BloomDialogProvider.web.d.ts.map +1 -0
  137. package/lib/typescript/module/dialog/Dialog.d.ts +37 -10
  138. package/lib/typescript/module/dialog/Dialog.d.ts.map +1 -1
  139. package/lib/typescript/module/dialog/Dialog.web.d.ts +26 -10
  140. package/lib/typescript/module/dialog/Dialog.web.d.ts.map +1 -1
  141. package/lib/typescript/module/dialog/SheetShell.d.ts +31 -0
  142. package/lib/typescript/module/dialog/SheetShell.d.ts.map +1 -0
  143. package/lib/typescript/module/dialog/alert-store.d.ts +70 -0
  144. package/lib/typescript/module/dialog/alert-store.d.ts.map +1 -0
  145. package/lib/typescript/module/dialog/alert.d.ts +27 -0
  146. package/lib/typescript/module/dialog/alert.d.ts.map +1 -0
  147. package/lib/typescript/module/dialog/context.d.ts +7 -0
  148. package/lib/typescript/module/dialog/context.d.ts.map +1 -1
  149. package/lib/typescript/module/dialog/index.d.ts +5 -2
  150. package/lib/typescript/module/dialog/index.d.ts.map +1 -1
  151. package/lib/typescript/module/dialog/index.web.d.ts +5 -2
  152. package/lib/typescript/module/dialog/index.web.d.ts.map +1 -1
  153. package/lib/typescript/module/dialog/types.d.ts +70 -15
  154. package/lib/typescript/module/dialog/types.d.ts.map +1 -1
  155. package/lib/typescript/module/fonts/FontLoader.d.ts.map +1 -1
  156. package/lib/typescript/module/fonts/apply-font-faces.web.d.ts +8 -1
  157. package/lib/typescript/module/fonts/apply-font-faces.web.d.ts.map +1 -1
  158. package/lib/typescript/module/fonts/font-data.web.d.ts +5 -0
  159. package/lib/typescript/module/fonts/font-data.web.d.ts.map +1 -0
  160. package/lib/typescript/module/index.d.ts +3 -3
  161. package/lib/typescript/module/index.d.ts.map +1 -1
  162. package/lib/typescript/module/index.web.d.ts +3 -3
  163. package/lib/typescript/module/index.web.d.ts.map +1 -1
  164. package/lib/typescript/module/menu/index.d.ts +4 -4
  165. package/lib/typescript/module/menu/index.d.ts.map +1 -1
  166. package/lib/typescript/module/select/index.d.ts.map +1 -1
  167. package/lib/typescript/module/toast/index.d.ts +32 -3
  168. package/lib/typescript/module/toast/index.d.ts.map +1 -1
  169. package/lib/typescript/module/toast/index.web.d.ts +14 -7
  170. package/lib/typescript/module/toast/index.web.d.ts.map +1 -1
  171. package/package.json +38 -18
  172. package/src/__tests__/Dialog.test.tsx +177 -0
  173. package/src/avatar/Avatar.stories.tsx +69 -0
  174. package/src/bottom-sheet/BottomSheet.stories.tsx +92 -0
  175. package/src/bottom-sheet/index.tsx +3 -3
  176. package/src/button/Button.stories.tsx +94 -0
  177. package/src/context-menu/ContextMenu.stories.tsx +71 -0
  178. package/src/context-menu/index.tsx +12 -12
  179. package/src/dialog/BloomDialogProvider.tsx +61 -0
  180. package/src/dialog/BloomDialogProvider.web.tsx +46 -0
  181. package/src/dialog/Dialog.stories.tsx +112 -0
  182. package/src/dialog/Dialog.tsx +217 -64
  183. package/src/dialog/Dialog.web.tsx +240 -75
  184. package/src/dialog/SheetShell.tsx +154 -0
  185. package/src/dialog/alert-store.ts +126 -0
  186. package/src/dialog/alert.ts +42 -0
  187. package/src/dialog/context.ts +14 -3
  188. package/src/dialog/index.ts +14 -2
  189. package/src/dialog/index.web.ts +20 -8
  190. package/src/dialog/types.ts +73 -16
  191. package/src/fonts/FontLoader.tsx +6 -5
  192. package/src/fonts/apply-font-faces.ts +4 -4
  193. package/src/fonts/apply-font-faces.web.ts +18 -10
  194. package/src/fonts/font-assets.ts +2 -2
  195. package/src/fonts/font-data.web.ts +15 -0
  196. package/src/fonts/index.web.ts +4 -4
  197. package/src/index.ts +17 -3
  198. package/src/index.web.ts +17 -3
  199. package/src/loading/Loading.stories.tsx +60 -0
  200. package/src/menu/Menu.stories.tsx +79 -0
  201. package/src/menu/index.tsx +13 -17
  202. package/src/prompt-input/PromptInput.stories.tsx +82 -0
  203. package/src/select/Select.stories.tsx +84 -0
  204. package/src/select/index.tsx +30 -30
  205. package/src/settings-list/SettingsList.stories.tsx +106 -0
  206. package/src/text-field/TextField.stories.tsx +90 -0
  207. package/src/toast/Toast.stories.tsx +109 -0
  208. package/src/toast/index.tsx +55 -11
  209. package/src/toast/index.web.tsx +33 -13
  210. package/lib/commonjs/fonts/assets/BlomusModernus-Bold.woff2 +0 -0
  211. package/lib/commonjs/fonts/assets/BlomusModernus-Regular.woff2 +0 -0
  212. package/lib/commonjs/fonts/assets/GeistMono-Variable.woff2 +0 -0
  213. package/lib/commonjs/fonts/assets/InterVariable.woff2 +0 -0
  214. package/lib/commonjs/prompt/Prompt.js +0 -267
  215. package/lib/commonjs/prompt/Prompt.js.map +0 -1
  216. package/lib/commonjs/prompt/index.js +0 -61
  217. package/lib/commonjs/prompt/index.js.map +0 -1
  218. package/lib/module/fonts/assets/BlomusModernus-Bold.woff2 +0 -0
  219. package/lib/module/fonts/assets/BlomusModernus-Regular.woff2 +0 -0
  220. package/lib/module/fonts/assets/GeistMono-Variable.woff2 +0 -0
  221. package/lib/module/fonts/assets/InterVariable.woff2 +0 -0
  222. package/lib/module/prompt/Prompt.js +0 -250
  223. package/lib/module/prompt/Prompt.js.map +0 -1
  224. package/lib/module/prompt/index.js +0 -4
  225. package/lib/module/prompt/index.js.map +0 -1
  226. package/lib/typescript/commonjs/__tests__/BloomThemeProvider.fonts-web.test.d.ts +0 -5
  227. package/lib/typescript/commonjs/__tests__/BloomThemeProvider.fonts-web.test.d.ts.map +0 -1
  228. package/lib/typescript/commonjs/__tests__/BloomThemeProvider.test.d.ts +0 -2
  229. package/lib/typescript/commonjs/__tests__/BloomThemeProvider.test.d.ts.map +0 -1
  230. package/lib/typescript/commonjs/__tests__/BottomSheet.test.d.ts +0 -2
  231. package/lib/typescript/commonjs/__tests__/BottomSheet.test.d.ts.map +0 -1
  232. package/lib/typescript/commonjs/__tests__/Button.test.d.ts +0 -2
  233. package/lib/typescript/commonjs/__tests__/Button.test.d.ts.map +0 -1
  234. package/lib/typescript/commonjs/__tests__/Code.test.d.ts +0 -2
  235. package/lib/typescript/commonjs/__tests__/Code.test.d.ts.map +0 -1
  236. package/lib/typescript/commonjs/__tests__/FontLoader.native.test.d.ts +0 -2
  237. package/lib/typescript/commonjs/__tests__/FontLoader.native.test.d.ts.map +0 -1
  238. package/lib/typescript/commonjs/__tests__/Pre.test.d.ts +0 -2
  239. package/lib/typescript/commonjs/__tests__/Pre.test.d.ts.map +0 -1
  240. package/lib/typescript/commonjs/__tests__/SettingsList.test.d.ts +0 -2
  241. package/lib/typescript/commonjs/__tests__/SettingsList.test.d.ts.map +0 -1
  242. package/lib/typescript/commonjs/__tests__/apply-font-faces.test.d.ts +0 -5
  243. package/lib/typescript/commonjs/__tests__/apply-font-faces.test.d.ts.map +0 -1
  244. package/lib/typescript/commonjs/__tests__/theme.test.d.ts +0 -2
  245. package/lib/typescript/commonjs/__tests__/theme.test.d.ts.map +0 -1
  246. package/lib/typescript/commonjs/prompt/Prompt.d.ts +0 -42
  247. package/lib/typescript/commonjs/prompt/Prompt.d.ts.map +0 -1
  248. package/lib/typescript/commonjs/prompt/index.d.ts +0 -3
  249. package/lib/typescript/commonjs/prompt/index.d.ts.map +0 -1
  250. package/lib/typescript/module/__tests__/BloomThemeProvider.fonts-web.test.d.ts +0 -5
  251. package/lib/typescript/module/__tests__/BloomThemeProvider.fonts-web.test.d.ts.map +0 -1
  252. package/lib/typescript/module/__tests__/BloomThemeProvider.test.d.ts +0 -2
  253. package/lib/typescript/module/__tests__/BloomThemeProvider.test.d.ts.map +0 -1
  254. package/lib/typescript/module/__tests__/BottomSheet.test.d.ts +0 -2
  255. package/lib/typescript/module/__tests__/BottomSheet.test.d.ts.map +0 -1
  256. package/lib/typescript/module/__tests__/Button.test.d.ts +0 -2
  257. package/lib/typescript/module/__tests__/Button.test.d.ts.map +0 -1
  258. package/lib/typescript/module/__tests__/Code.test.d.ts +0 -2
  259. package/lib/typescript/module/__tests__/Code.test.d.ts.map +0 -1
  260. package/lib/typescript/module/__tests__/FontLoader.native.test.d.ts +0 -2
  261. package/lib/typescript/module/__tests__/FontLoader.native.test.d.ts.map +0 -1
  262. package/lib/typescript/module/__tests__/Pre.test.d.ts +0 -2
  263. package/lib/typescript/module/__tests__/Pre.test.d.ts.map +0 -1
  264. package/lib/typescript/module/__tests__/SettingsList.test.d.ts +0 -2
  265. package/lib/typescript/module/__tests__/SettingsList.test.d.ts.map +0 -1
  266. package/lib/typescript/module/__tests__/apply-font-faces.test.d.ts +0 -5
  267. package/lib/typescript/module/__tests__/apply-font-faces.test.d.ts.map +0 -1
  268. package/lib/typescript/module/__tests__/theme.test.d.ts +0 -2
  269. package/lib/typescript/module/__tests__/theme.test.d.ts.map +0 -1
  270. package/lib/typescript/module/prompt/Prompt.d.ts +0 -42
  271. package/lib/typescript/module/prompt/Prompt.d.ts.map +0 -1
  272. package/lib/typescript/module/prompt/index.d.ts +0 -3
  273. package/lib/typescript/module/prompt/index.d.ts.map +0 -1
  274. package/src/prompt/Prompt.tsx +0 -247
  275. package/src/prompt/index.ts +0 -13
@@ -1,33 +1,83 @@
1
- import React, { useCallback, useImperativeHandle, useMemo, useRef } from 'react';
2
- import { Pressable, StyleSheet, View } from 'react-native';
1
+ import React, {
2
+ useCallback,
3
+ useEffect,
4
+ useId,
5
+ useImperativeHandle,
6
+ useMemo,
7
+ useRef,
8
+ } from 'react';
9
+ import {
10
+ Text,
11
+ TouchableOpacity,
12
+ View,
13
+ type GestureResponderEvent,
14
+ } from 'react-native';
3
15
 
4
16
  import { BottomSheet, type BottomSheetRef } from '../bottom-sheet';
17
+ import type { ThemeColors } from '../theme/types';
5
18
  import { useTheme } from '../theme/use-theme';
6
- import { Context, useDialogContext } from './context';
7
- import type { DialogControlProps, DialogInnerProps, DialogOuterProps } from './types';
19
+ import { Context, useDialogContext, useDialogControl } from './context';
20
+ import type {
21
+ DialogAction,
22
+ DialogActionColor,
23
+ DialogControlProps,
24
+ DialogProps,
25
+ } from './types';
8
26
 
9
- export { useDialogContext, useDialogControl } from './context';
10
- export type { DialogControlProps, DialogOuterProps, DialogInnerProps } from './types';
11
-
12
- export function Outer({
13
- children,
27
+ /**
28
+ * Native variant of `<Dialog>`.
29
+ *
30
+ * Uses bloom's own `BottomSheet` in `detached` mode as the underlying
31
+ * surface — a floating, dynamically-sized, content-hugging card that
32
+ * gracefully degrades from sheet (phone) to centered card (tablet, via the
33
+ * 500px max-width cap).
34
+ *
35
+ * The component accepts three rendering modes simultaneously:
36
+ *
37
+ * 1. Declarative — `title`, `description`, `actions`. Bloom renders a
38
+ * standard confirm/destructive/cancel layout.
39
+ * 2. Custom children — caller passes JSX, bloom renders the chrome (title
40
+ * + close behaviour) and the children fill the body.
41
+ * 3. Pure children — no `title`/`description`/`actions`; caller owns
42
+ * every pixel.
43
+ *
44
+ * All three share the same dismissal semantics: tapping the backdrop, the
45
+ * drag handle, swiping down, or `control.close()` runs the queued close
46
+ * callbacks once the sheet's exit animation has settled.
47
+ */
48
+ export function Dialog({
14
49
  control,
15
50
  onClose,
16
51
  testID,
17
- }: React.PropsWithChildren<DialogOuterProps>) {
52
+ title,
53
+ description,
54
+ actions,
55
+ style,
56
+ label,
57
+ children,
58
+ }: DialogProps) {
18
59
  const theme = useTheme();
19
60
  const ref = useRef<BottomSheetRef>(null);
20
61
  const closeCallbacks = useRef<(() => void)[]>([]);
62
+ const titleId = useId();
63
+ const descriptionId = useId();
21
64
 
65
+ // Drain queued close callbacks atomically — capturing the list and
66
+ // resetting it before invocation ensures a callback that synchronously
67
+ // re-opens the dialog (and queues fresh callbacks) does not see the old
68
+ // ones replayed against the new session.
22
69
  const callQueuedCallbacks = useCallback(() => {
23
- for (const cb of closeCallbacks.current) {
70
+ const queued = closeCallbacks.current;
71
+ closeCallbacks.current = [];
72
+ for (const cb of queued) {
24
73
  try {
25
74
  cb();
26
75
  } catch (e) {
27
- console.error('Dialog close callback error:', e);
76
+ if (typeof console !== 'undefined' && console.error) {
77
+ console.error('Dialog close callback error:', e);
78
+ }
28
79
  }
29
80
  }
30
- closeCallbacks.current = [];
31
81
  }, []);
32
82
 
33
83
  const open = useCallback(() => {
@@ -41,10 +91,6 @@ export function Outer({
41
91
  ref.current?.dismiss();
42
92
  }, []);
43
93
 
44
- // onDismiss fires after the BottomSheet's close animation finishes — this is
45
- // the integration point for the closeCallbacks queue. Consumers (e.g.
46
- // Prompt.Action) rely on the queued callback running AFTER the sheet has
47
- // visually closed so the screen transition feels natural.
48
94
  const handleDismiss = useCallback(() => {
49
95
  callQueuedCallbacks();
50
96
  onClose?.();
@@ -65,9 +111,9 @@ export function Outer({
65
111
  () => ({
66
112
  maxWidth: 500,
67
113
  backgroundColor: theme.colors.background,
68
- // All four corners rounded — Dialog uses BottomSheet in `detached` mode
69
- // (floating card with safe-area margins), so we round the bottom too
70
- // instead of leaving the default top-only radius.
114
+ // All four corners rounded — bloom's BottomSheet defaults to top-only
115
+ // radius in flush mode, but we use `detached` so the whole card is
116
+ // floating and rounded uniformly.
71
117
  borderRadius: 20,
72
118
  }),
73
119
  [theme.colors.background],
@@ -79,75 +125,182 @@ export function Outer({
79
125
  onDismiss={handleDismiss}
80
126
  enablePanDownToClose
81
127
  detached
82
- // Stronger dim so the underlying bottom-sheet's handle/content doesn't
83
- // bleed through when a Dialog/Prompt is stacked over another sheet.
128
+ // Stronger dim when a Dialog is stacked over another sheet so the
129
+ // underlying sheet's handle/content doesn't bleed through.
84
130
  backdropOpacity={0.7}
85
131
  style={sheetStyle}
86
132
  >
87
133
  <Context.Provider value={context}>
88
134
  <View
89
135
  testID={testID}
90
- style={{ backgroundColor: theme.colors.background }}
136
+ accessibilityLabel={label}
137
+ aria-labelledby={title ? titleId : undefined}
138
+ aria-describedby={description ? descriptionId : undefined}
139
+ style={[
140
+ // Detached BottomSheet already adds `marginBottom: insets.bottom + 16`
141
+ // to the sheet container — the floating card sits ABOVE the
142
+ // system gesture bar, so we don't add `insets.bottom` here.
143
+ { paddingTop: 20, paddingHorizontal: 20, paddingBottom: 20 },
144
+ { backgroundColor: theme.colors.background },
145
+ style,
146
+ ]}
91
147
  >
148
+ {title ? (
149
+ <Text
150
+ nativeID={titleId}
151
+ style={{
152
+ fontSize: 22,
153
+ fontWeight: '600',
154
+ color: theme.colors.text,
155
+ paddingBottom: description ? 4 : 16,
156
+ lineHeight: 30,
157
+ }}
158
+ >
159
+ {title}
160
+ </Text>
161
+ ) : null}
162
+ {description ? (
163
+ <Text
164
+ nativeID={descriptionId}
165
+ style={{
166
+ fontSize: 16,
167
+ color: theme.colors.textSecondary,
168
+ paddingBottom: 16,
169
+ lineHeight: 22,
170
+ }}
171
+ >
172
+ {description}
173
+ </Text>
174
+ ) : null}
92
175
  {children}
176
+ {actions && actions.length > 0 ? (
177
+ <ActionRow actions={actions} />
178
+ ) : null}
93
179
  </View>
94
180
  </Context.Provider>
95
181
  </BottomSheet>
96
182
  );
97
183
  }
98
184
 
99
- export function Inner({ children, style, header, contentContainerStyle }: DialogInnerProps) {
100
- // Dialog renders inside a `detached` BottomSheet, which already adds
101
- // `marginBottom: insets.bottom + 16` to the sheet container — the floating
102
- // card sits ABOVE the system gesture bar, so we don't add `insets.bottom`
103
- // here. Doing so double-padded the bottom on Android edge-to-edge displays.
185
+ function ActionRow({ actions }: { actions: DialogAction[] }) {
104
186
  return (
105
- <>
106
- {header}
107
- <View
108
- style={[
109
- { paddingTop: 20, paddingHorizontal: 20, paddingBottom: 20 },
110
- contentContainerStyle,
111
- style,
112
- ]}
113
- >
114
- {children}
115
- </View>
116
- </>
187
+ <View style={{ width: '100%', gap: 8, justifyContent: 'flex-end' }}>
188
+ {actions.map((action, idx) => (
189
+ <ActionButton
190
+ key={`${action.label}-${idx}`}
191
+ action={action}
192
+ />
193
+ ))}
194
+ </View>
117
195
  );
118
196
  }
119
197
 
120
- export function ScrollableInner(props: DialogInnerProps) {
121
- return <Inner {...props} />;
122
- }
198
+ function ActionButton({ action }: { action: DialogAction }) {
199
+ const { close } = useDialogContext();
200
+ const theme = useTheme();
201
+ const color: DialogActionColor = action.color ?? 'default';
202
+ const shouldCloseOnPress = action.shouldCloseOnPress ?? true;
123
203
 
124
- const handleStyles = StyleSheet.create({
125
- container: { position: 'absolute', width: '100%', alignItems: 'center', zIndex: 10, height: 20 },
126
- bar: { top: 8, width: 35, height: 5, borderRadius: 3, alignSelf: 'center', opacity: 0.5 },
127
- });
204
+ const { background, foreground } = getActionPalette(color, theme.colors);
128
205
 
129
- export function Handle() {
130
- const theme = useTheme();
131
- const { close } = useDialogContext();
206
+ const handlePress = useCallback(
207
+ (e: GestureResponderEvent) => {
208
+ const onPress = action.onPress;
209
+ if (color === 'cancel') {
210
+ // Cancel always dismisses; consumer's onPress (rare) runs after.
211
+ close(onPress ? () => onPress(e) : undefined);
212
+ return;
213
+ }
214
+ if (shouldCloseOnPress) {
215
+ close(onPress ? () => onPress(e) : undefined);
216
+ } else {
217
+ onPress?.(e);
218
+ }
219
+ },
220
+ [action.onPress, close, color, shouldCloseOnPress],
221
+ );
132
222
 
133
223
  return (
134
- <View style={handleStyles.container}>
135
- <Pressable
136
- onPress={() => close()}
137
- accessibilityLabel="Dismiss"
138
- accessibilityHint="Tap to close the dialog"
139
- hitSlop={{ top: 10, bottom: 10, left: 40, right: 40 }}
140
- >
141
- <View style={[handleStyles.bar, { backgroundColor: theme.colors.text }]} />
142
- </Pressable>
143
- </View>
224
+ <TouchableOpacity
225
+ style={{
226
+ borderRadius: 9999,
227
+ alignItems: 'center',
228
+ justifyContent: 'center',
229
+ backgroundColor: background,
230
+ opacity: action.disabled ? 0.5 : 1,
231
+ paddingVertical: 12,
232
+ paddingHorizontal: 24,
233
+ }}
234
+ onPress={handlePress}
235
+ disabled={action.disabled}
236
+ activeOpacity={0.7}
237
+ testID={action.testID}
238
+ >
239
+ <Text style={{ fontSize: 16, fontWeight: '500', color: foreground }}>
240
+ {action.label}
241
+ </Text>
242
+ </TouchableOpacity>
144
243
  );
145
244
  }
146
245
 
147
- export function Close() {
148
- return null;
246
+ function getActionPalette(
247
+ color: DialogActionColor,
248
+ colors: ThemeColors,
249
+ ): { background: string; foreground: string } {
250
+ switch (color) {
251
+ case 'destructive':
252
+ return {
253
+ background: colors.negative,
254
+ foreground: colors.negativeForeground,
255
+ };
256
+ case 'cancel':
257
+ return { background: colors.contrast50, foreground: colors.text };
258
+ case 'default':
259
+ return { background: colors.primary, foreground: '#FFFFFF' };
260
+ /* c8 ignore next 2 -- TS exhaustiveness check guards this branch */
261
+ default: {
262
+ const _exhaustive: never = color;
263
+ return { background: colors.primary, foreground: '#FFFFFF' };
264
+ }
265
+ }
149
266
  }
150
267
 
151
- export function Backdrop() {
152
- return null;
268
+ /**
269
+ * Helper used by the imperative `alert()` API. Mounts a `<Dialog>` against
270
+ * a fresh control and presents it immediately. `onResolve` is invoked
271
+ * exactly once when the dialog finishes closing (regardless of how the
272
+ * dismissal happened).
273
+ *
274
+ * Kept private to the dialog module — `alert()` is the public surface.
275
+ */
276
+ export function AutoMountedDialog({
277
+ title,
278
+ description,
279
+ actions,
280
+ onResolve,
281
+ }: {
282
+ title?: string;
283
+ description?: string;
284
+ actions: DialogAction[];
285
+ onResolve: () => void;
286
+ }) {
287
+ const control = useDialogControl();
288
+
289
+ // `control` is referentially stable for the lifetime of the component
290
+ // (memoised by `useDialogControl` on `[id]`), so this effect runs exactly
291
+ // once per mount — present-on-mount semantics for an `alert()` call
292
+ // without re-presenting on subsequent renders.
293
+ useEffect(() => {
294
+ control.open();
295
+ }, [control]);
296
+
297
+ return (
298
+ <Dialog
299
+ control={control}
300
+ title={title}
301
+ description={description}
302
+ actions={actions}
303
+ onClose={onResolve}
304
+ />
305
+ );
153
306
  }