@oxyhq/bloom 0.15.0 → 0.16.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 (208) hide show
  1. package/lib/commonjs/alert-dialog/AlertDialog.js +35 -27
  2. package/lib/commonjs/alert-dialog/AlertDialog.js.map +1 -1
  3. package/lib/commonjs/alert-dialog/index.js +1 -1
  4. package/lib/commonjs/alert-dialog/index.js.map +1 -1
  5. package/lib/commonjs/alert-dialog/index.web.js +1 -1
  6. package/lib/commonjs/alert-dialog/index.web.js.map +1 -1
  7. package/lib/commonjs/command/Command.js +27 -16
  8. package/lib/commonjs/command/Command.js.map +1 -1
  9. package/lib/commonjs/command/index.js +1 -1
  10. package/lib/commonjs/command/index.js.map +1 -1
  11. package/lib/commonjs/command/index.web.js +1 -1
  12. package/lib/commonjs/command/index.web.js.map +1 -1
  13. package/lib/commonjs/dialog/Dialog.js +39 -152
  14. package/lib/commonjs/dialog/Dialog.js.map +1 -1
  15. package/lib/commonjs/dialog/Dialog.web.js +61 -196
  16. package/lib/commonjs/dialog/Dialog.web.js.map +1 -1
  17. package/lib/commonjs/dialog/DialogBottomSheet.js +205 -0
  18. package/lib/commonjs/dialog/DialogBottomSheet.js.map +1 -0
  19. package/lib/commonjs/dialog/DialogContent.js +155 -0
  20. package/lib/commonjs/dialog/DialogContent.js.map +1 -0
  21. package/lib/commonjs/dialog/index.js +0 -13
  22. package/lib/commonjs/dialog/index.js.map +1 -1
  23. package/lib/commonjs/dialog/index.web.js +0 -19
  24. package/lib/commonjs/dialog/index.web.js.map +1 -1
  25. package/lib/commonjs/index.js +0 -29
  26. package/lib/commonjs/index.js.map +1 -1
  27. package/lib/commonjs/index.web.js +6 -35
  28. package/lib/commonjs/index.web.js.map +1 -1
  29. package/lib/module/alert-dialog/AlertDialog.js +35 -27
  30. package/lib/module/alert-dialog/AlertDialog.js.map +1 -1
  31. package/lib/module/alert-dialog/index.js +2 -2
  32. package/lib/module/alert-dialog/index.js.map +1 -1
  33. package/lib/module/alert-dialog/index.web.js +2 -2
  34. package/lib/module/alert-dialog/index.web.js.map +1 -1
  35. package/lib/module/command/Command.js +27 -16
  36. package/lib/module/command/Command.js.map +1 -1
  37. package/lib/module/command/index.js +2 -2
  38. package/lib/module/command/index.js.map +1 -1
  39. package/lib/module/command/index.web.js +2 -2
  40. package/lib/module/command/index.web.js.map +1 -1
  41. package/lib/module/dialog/Dialog.js +42 -155
  42. package/lib/module/dialog/Dialog.js.map +1 -1
  43. package/lib/module/dialog/Dialog.web.js +63 -198
  44. package/lib/module/dialog/Dialog.web.js.map +1 -1
  45. package/lib/module/dialog/DialogBottomSheet.js +200 -0
  46. package/lib/module/dialog/DialogBottomSheet.js.map +1 -0
  47. package/lib/module/dialog/DialogContent.js +148 -0
  48. package/lib/module/dialog/DialogContent.js.map +1 -0
  49. package/lib/module/dialog/index.js +0 -1
  50. package/lib/module/dialog/index.js.map +1 -1
  51. package/lib/module/dialog/index.web.js +0 -1
  52. package/lib/module/dialog/index.web.js.map +1 -1
  53. package/lib/module/index.js +1 -3
  54. package/lib/module/index.js.map +1 -1
  55. package/lib/module/index.web.js +1 -3
  56. package/lib/module/index.web.js.map +1 -1
  57. package/lib/typescript/commonjs/alert-dialog/AlertDialog.d.ts +13 -12
  58. package/lib/typescript/commonjs/alert-dialog/AlertDialog.d.ts.map +1 -1
  59. package/lib/typescript/commonjs/alert-dialog/index.d.ts.map +1 -1
  60. package/lib/typescript/commonjs/alert-dialog/index.web.d.ts.map +1 -1
  61. package/lib/typescript/commonjs/command/Command.d.ts +8 -8
  62. package/lib/typescript/commonjs/command/Command.d.ts.map +1 -1
  63. package/lib/typescript/commonjs/command/index.d.ts.map +1 -1
  64. package/lib/typescript/commonjs/command/index.web.d.ts.map +1 -1
  65. package/lib/typescript/commonjs/dialog/Dialog.d.ts +2 -3
  66. package/lib/typescript/commonjs/dialog/Dialog.d.ts.map +1 -1
  67. package/lib/typescript/commonjs/dialog/Dialog.web.d.ts +11 -8
  68. package/lib/typescript/commonjs/dialog/Dialog.web.d.ts.map +1 -1
  69. package/lib/typescript/commonjs/dialog/DialogBottomSheet.d.ts +29 -0
  70. package/lib/typescript/commonjs/dialog/DialogBottomSheet.d.ts.map +1 -0
  71. package/lib/typescript/commonjs/dialog/DialogContent.d.ts +32 -0
  72. package/lib/typescript/commonjs/dialog/DialogContent.d.ts.map +1 -0
  73. package/lib/typescript/commonjs/dialog/index.d.ts +0 -2
  74. package/lib/typescript/commonjs/dialog/index.d.ts.map +1 -1
  75. package/lib/typescript/commonjs/dialog/index.web.d.ts +0 -2
  76. package/lib/typescript/commonjs/dialog/index.web.d.ts.map +1 -1
  77. package/lib/typescript/commonjs/index.d.ts +2 -4
  78. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  79. package/lib/typescript/commonjs/index.web.d.ts +2 -4
  80. package/lib/typescript/commonjs/index.web.d.ts.map +1 -1
  81. package/lib/typescript/module/alert-dialog/AlertDialog.d.ts +13 -12
  82. package/lib/typescript/module/alert-dialog/AlertDialog.d.ts.map +1 -1
  83. package/lib/typescript/module/alert-dialog/index.d.ts.map +1 -1
  84. package/lib/typescript/module/alert-dialog/index.web.d.ts.map +1 -1
  85. package/lib/typescript/module/command/Command.d.ts +8 -8
  86. package/lib/typescript/module/command/Command.d.ts.map +1 -1
  87. package/lib/typescript/module/command/index.d.ts.map +1 -1
  88. package/lib/typescript/module/command/index.web.d.ts.map +1 -1
  89. package/lib/typescript/module/dialog/Dialog.d.ts +2 -3
  90. package/lib/typescript/module/dialog/Dialog.d.ts.map +1 -1
  91. package/lib/typescript/module/dialog/Dialog.web.d.ts +11 -8
  92. package/lib/typescript/module/dialog/Dialog.web.d.ts.map +1 -1
  93. package/lib/typescript/module/dialog/DialogBottomSheet.d.ts +29 -0
  94. package/lib/typescript/module/dialog/DialogBottomSheet.d.ts.map +1 -0
  95. package/lib/typescript/module/dialog/DialogContent.d.ts +32 -0
  96. package/lib/typescript/module/dialog/DialogContent.d.ts.map +1 -0
  97. package/lib/typescript/module/dialog/index.d.ts +0 -2
  98. package/lib/typescript/module/dialog/index.d.ts.map +1 -1
  99. package/lib/typescript/module/dialog/index.web.d.ts +0 -2
  100. package/lib/typescript/module/dialog/index.web.d.ts.map +1 -1
  101. package/lib/typescript/module/index.d.ts +2 -4
  102. package/lib/typescript/module/index.d.ts.map +1 -1
  103. package/lib/typescript/module/index.web.d.ts +2 -4
  104. package/lib/typescript/module/index.web.d.ts.map +1 -1
  105. package/package.json +1 -18
  106. package/src/__tests__/AlertDialog.test.tsx +122 -0
  107. package/src/__tests__/BottomSheetGesture.test.tsx +135 -0
  108. package/src/__tests__/Command.test.tsx +107 -0
  109. package/src/__tests__/DialogBottomSheet.test.tsx +130 -0
  110. package/src/alert-dialog/AlertDialog.tsx +46 -36
  111. package/src/alert-dialog/index.ts +2 -2
  112. package/src/alert-dialog/index.web.ts +2 -2
  113. package/src/command/Command.tsx +30 -19
  114. package/src/command/index.ts +2 -2
  115. package/src/command/index.web.ts +2 -2
  116. package/src/dialog/Dialog.tsx +35 -168
  117. package/src/dialog/Dialog.web.tsx +52 -209
  118. package/src/dialog/DialogBottomSheet.tsx +235 -0
  119. package/src/dialog/DialogContent.tsx +157 -0
  120. package/src/dialog/index.ts +0 -2
  121. package/src/dialog/index.web.ts +0 -6
  122. package/src/index.ts +0 -11
  123. package/src/index.web.ts +0 -11
  124. package/lib/commonjs/dialog/CenteredDialog.js +0 -252
  125. package/lib/commonjs/dialog/CenteredDialog.js.map +0 -1
  126. package/lib/commonjs/dialog/CenteredDialog.web.js +0 -330
  127. package/lib/commonjs/dialog/CenteredDialog.web.js.map +0 -1
  128. package/lib/commonjs/dialog/centered-dialog-tokens.js +0 -62
  129. package/lib/commonjs/dialog/centered-dialog-tokens.js.map +0 -1
  130. package/lib/commonjs/dialog/centered-dialog-types.js +0 -6
  131. package/lib/commonjs/dialog/centered-dialog-types.js.map +0 -1
  132. package/lib/commonjs/responsive-sheet/ResponsiveSheet.js +0 -97
  133. package/lib/commonjs/responsive-sheet/ResponsiveSheet.js.map +0 -1
  134. package/lib/commonjs/responsive-sheet/ResponsiveSheet.web.js +0 -84
  135. package/lib/commonjs/responsive-sheet/ResponsiveSheet.web.js.map +0 -1
  136. package/lib/commonjs/responsive-sheet/index.js +0 -19
  137. package/lib/commonjs/responsive-sheet/index.js.map +0 -1
  138. package/lib/commonjs/responsive-sheet/index.web.js +0 -19
  139. package/lib/commonjs/responsive-sheet/index.web.js.map +0 -1
  140. package/lib/commonjs/responsive-sheet/types.js +0 -6
  141. package/lib/commonjs/responsive-sheet/types.js.map +0 -1
  142. package/lib/module/dialog/CenteredDialog.js +0 -246
  143. package/lib/module/dialog/CenteredDialog.js.map +0 -1
  144. package/lib/module/dialog/CenteredDialog.web.js +0 -324
  145. package/lib/module/dialog/CenteredDialog.web.js.map +0 -1
  146. package/lib/module/dialog/centered-dialog-tokens.js +0 -58
  147. package/lib/module/dialog/centered-dialog-tokens.js.map +0 -1
  148. package/lib/module/dialog/centered-dialog-types.js +0 -4
  149. package/lib/module/dialog/centered-dialog-types.js.map +0 -1
  150. package/lib/module/responsive-sheet/ResponsiveSheet.js +0 -90
  151. package/lib/module/responsive-sheet/ResponsiveSheet.js.map +0 -1
  152. package/lib/module/responsive-sheet/ResponsiveSheet.web.js +0 -77
  153. package/lib/module/responsive-sheet/ResponsiveSheet.web.js.map +0 -1
  154. package/lib/module/responsive-sheet/index.js +0 -4
  155. package/lib/module/responsive-sheet/index.js.map +0 -1
  156. package/lib/module/responsive-sheet/index.web.js +0 -12
  157. package/lib/module/responsive-sheet/index.web.js.map +0 -1
  158. package/lib/module/responsive-sheet/types.js +0 -4
  159. package/lib/module/responsive-sheet/types.js.map +0 -1
  160. package/lib/typescript/commonjs/dialog/CenteredDialog.d.ts +0 -22
  161. package/lib/typescript/commonjs/dialog/CenteredDialog.d.ts.map +0 -1
  162. package/lib/typescript/commonjs/dialog/CenteredDialog.web.d.ts +0 -31
  163. package/lib/typescript/commonjs/dialog/CenteredDialog.web.d.ts.map +0 -1
  164. package/lib/typescript/commonjs/dialog/centered-dialog-tokens.d.ts +0 -47
  165. package/lib/typescript/commonjs/dialog/centered-dialog-tokens.d.ts.map +0 -1
  166. package/lib/typescript/commonjs/dialog/centered-dialog-types.d.ts +0 -74
  167. package/lib/typescript/commonjs/dialog/centered-dialog-types.d.ts.map +0 -1
  168. package/lib/typescript/commonjs/responsive-sheet/ResponsiveSheet.d.ts +0 -22
  169. package/lib/typescript/commonjs/responsive-sheet/ResponsiveSheet.d.ts.map +0 -1
  170. package/lib/typescript/commonjs/responsive-sheet/ResponsiveSheet.web.d.ts +0 -16
  171. package/lib/typescript/commonjs/responsive-sheet/ResponsiveSheet.web.d.ts.map +0 -1
  172. package/lib/typescript/commonjs/responsive-sheet/index.d.ts +0 -3
  173. package/lib/typescript/commonjs/responsive-sheet/index.d.ts.map +0 -1
  174. package/lib/typescript/commonjs/responsive-sheet/index.web.d.ts +0 -3
  175. package/lib/typescript/commonjs/responsive-sheet/index.web.d.ts.map +0 -1
  176. package/lib/typescript/commonjs/responsive-sheet/types.d.ts +0 -58
  177. package/lib/typescript/commonjs/responsive-sheet/types.d.ts.map +0 -1
  178. package/lib/typescript/module/dialog/CenteredDialog.d.ts +0 -22
  179. package/lib/typescript/module/dialog/CenteredDialog.d.ts.map +0 -1
  180. package/lib/typescript/module/dialog/CenteredDialog.web.d.ts +0 -31
  181. package/lib/typescript/module/dialog/CenteredDialog.web.d.ts.map +0 -1
  182. package/lib/typescript/module/dialog/centered-dialog-tokens.d.ts +0 -47
  183. package/lib/typescript/module/dialog/centered-dialog-tokens.d.ts.map +0 -1
  184. package/lib/typescript/module/dialog/centered-dialog-types.d.ts +0 -74
  185. package/lib/typescript/module/dialog/centered-dialog-types.d.ts.map +0 -1
  186. package/lib/typescript/module/responsive-sheet/ResponsiveSheet.d.ts +0 -22
  187. package/lib/typescript/module/responsive-sheet/ResponsiveSheet.d.ts.map +0 -1
  188. package/lib/typescript/module/responsive-sheet/ResponsiveSheet.web.d.ts +0 -16
  189. package/lib/typescript/module/responsive-sheet/ResponsiveSheet.web.d.ts.map +0 -1
  190. package/lib/typescript/module/responsive-sheet/index.d.ts +0 -3
  191. package/lib/typescript/module/responsive-sheet/index.d.ts.map +0 -1
  192. package/lib/typescript/module/responsive-sheet/index.web.d.ts +0 -3
  193. package/lib/typescript/module/responsive-sheet/index.web.d.ts.map +0 -1
  194. package/lib/typescript/module/responsive-sheet/types.d.ts +0 -58
  195. package/lib/typescript/module/responsive-sheet/types.d.ts.map +0 -1
  196. package/src/__tests__/CenteredDialog.test.tsx +0 -108
  197. package/src/__tests__/ResponsiveSheet.test.tsx +0 -88
  198. package/src/dialog/CenteredDialog.stories.tsx +0 -125
  199. package/src/dialog/CenteredDialog.tsx +0 -305
  200. package/src/dialog/CenteredDialog.web.tsx +0 -374
  201. package/src/dialog/centered-dialog-tokens.ts +0 -68
  202. package/src/dialog/centered-dialog-types.ts +0 -74
  203. package/src/responsive-sheet/ResponsiveSheet.stories.tsx +0 -54
  204. package/src/responsive-sheet/ResponsiveSheet.tsx +0 -88
  205. package/src/responsive-sheet/ResponsiveSheet.web.tsx +0 -76
  206. package/src/responsive-sheet/index.ts +0 -6
  207. package/src/responsive-sheet/index.web.ts +0 -14
  208. package/src/responsive-sheet/types.ts +0 -60
@@ -1,8 +1,8 @@
1
- import { CenteredDialog } from '../dialog/index';
1
+ import { Dialog } from '../dialog/index';
2
2
  import { createAlertDialog } from './AlertDialog';
3
3
  import { createAlertDialogHost } from './AlertDialogHost';
4
4
 
5
- export const AlertDialog = createAlertDialog(CenteredDialog);
5
+ export const AlertDialog = createAlertDialog(Dialog);
6
6
  export const AlertDialogHost = createAlertDialogHost(AlertDialog);
7
7
 
8
8
  export { confirm } from './confirm-store';
@@ -1,8 +1,8 @@
1
- import { CenteredDialog } from '../dialog/index.web';
1
+ import { Dialog } from '../dialog/index.web';
2
2
  import { createAlertDialog } from './AlertDialog';
3
3
  import { createAlertDialogHost } from './AlertDialogHost';
4
4
 
5
- export const AlertDialog = createAlertDialog(CenteredDialog);
5
+ export const AlertDialog = createAlertDialog(Dialog);
6
6
  export const AlertDialogHost = createAlertDialogHost(AlertDialog);
7
7
 
8
8
  export { confirm } from './confirm-store';
@@ -14,10 +14,13 @@ import { Item } from '../item';
14
14
  import { Kbd } from '../kbd';
15
15
  import { SearchInput } from '../search-input';
16
16
  import { fontSize, space } from '../styles/tokens';
17
- import type { CenteredDialogProps } from '../dialog';
17
+ import type { DialogProps } from '../dialog';
18
18
  import type { CommandItem, CommandProps } from './types';
19
19
 
20
- type CenteredDialogComponent = React.ComponentType<CenteredDialogProps>;
20
+ type DialogComponent = React.ComponentType<DialogProps>;
21
+
22
+ /** Centered command-palette max width (px). Matches the legacy palette card. */
23
+ const COMMAND_MAX_WIDTH = 560;
21
24
 
22
25
  function defaultFilter(item: CommandItem, query: string): boolean {
23
26
  const q = query.trim().toLowerCase();
@@ -36,17 +39,17 @@ interface FlatEntry {
36
39
  }
37
40
 
38
41
  /**
39
- * Build the `Command` palette bound to a platform `CenteredDialog`. The
40
- * platform entry files (`index.ts` / `index.web.ts`) inject the correct one
41
- * (native RN `Modal` vs pure-DOM web overlay) — this repo never relies on
42
- * implicit `.web` resolution. The body is single-source.
42
+ * Build the `Command` palette bound to a platform `Dialog`. The platform entry
43
+ * files (`index.ts` / `index.web.ts`) inject the correct one (native
44
+ * `BottomSheet`-backed surface vs pure-DOM web overlay) — this repo never
45
+ * relies on implicit `.web` resolution. The body is single-source.
43
46
  *
44
- * `Command` is a ⌘K command palette built on Bloom's `CenteredDialog`,
47
+ * `Command` is a ⌘K command palette built on `<Dialog placement="center">`,
45
48
  * `SearchInput`, an `Item` results list and `Kbd` shortcut hints. Items group
46
49
  * by their `group` field (ungrouped first). On web the list is
47
50
  * keyboard-navigable (Up/Down/Enter); on native, tap to select.
48
51
  */
49
- export function createCommand(CenteredDialog: CenteredDialogComponent) {
52
+ export function createCommand(Dialog: DialogComponent) {
50
53
  const Command = function Command({
51
54
  visible,
52
55
  onClose,
@@ -168,15 +171,16 @@ export function createCommand(CenteredDialog: CenteredDialogComponent) {
168
171
  : {};
169
172
 
170
173
  return (
171
- <CenteredDialog
172
- visible={visible}
174
+ <Dialog
175
+ open={visible}
173
176
  onClose={onClose}
174
- dismissible
175
- showClose={false}
176
- maxWidth={560}
177
- accessibilityLabel="Command palette"
178
- cardStyle={style}
179
- contentStyle={styles.content}
177
+ placement="center"
178
+ dismissOnBackdrop
179
+ maxWidth={COMMAND_MAX_WIDTH}
180
+ label="Command palette"
181
+ // The palette owns its own edge-to-edge layout (full-bleed search border,
182
+ // padded results) so the Dialog panel contributes no padding of its own.
183
+ style={[styles.panel, style]}
180
184
  testID={testID}>
181
185
  <View {...webKeyHandler}>
182
186
  <View style={[styles.searchWrap, { borderBottomColor: theme.colors.borderLight }]}>
@@ -200,6 +204,7 @@ export function createCommand(CenteredDialog: CenteredDialogComponent) {
200
204
  ) : (
201
205
  <ScrollView
202
206
  style={{ maxHeight: maxListHeight }}
207
+ contentContainerStyle={styles.list}
203
208
  keyboardShouldPersistTaps="handled"
204
209
  showsVerticalScrollIndicator={false}>
205
210
  {entries.map((entry, i) => {
@@ -238,7 +243,7 @@ export function createCommand(CenteredDialog: CenteredDialogComponent) {
238
243
  </ScrollView>
239
244
  )}
240
245
  </View>
241
- </CenteredDialog>
246
+ </Dialog>
242
247
  );
243
248
  };
244
249
 
@@ -249,9 +254,15 @@ export function createCommand(CenteredDialog: CenteredDialogComponent) {
249
254
  export type CommandType = ReturnType<typeof createCommand>;
250
255
 
251
256
  const styles = StyleSheet.create({
252
- content: {
253
- paddingHorizontal: 0,
257
+ // Zero out the Dialog panel's default padding (longhands beat the web
258
+ // panel's `padding` shorthand and the native panel's longhand paddings) so
259
+ // the palette renders edge-to-edge.
260
+ panel: {
254
261
  paddingTop: 0,
262
+ paddingHorizontal: 0,
263
+ paddingBottom: space.xs,
264
+ },
265
+ list: {
255
266
  paddingBottom: space.xs,
256
267
  },
257
268
  searchWrap: {
@@ -1,6 +1,6 @@
1
- import { CenteredDialog } from '../dialog/index';
1
+ import { Dialog } from '../dialog/index';
2
2
  import { createCommand } from './Command';
3
3
 
4
- export const Command = createCommand(CenteredDialog);
4
+ export const Command = createCommand(Dialog);
5
5
 
6
6
  export type { CommandProps, CommandItem } from './types';
@@ -1,6 +1,6 @@
1
- import { CenteredDialog } from '../dialog/index.web';
1
+ import { Dialog } from '../dialog/index.web';
2
2
  import { createCommand } from './Command';
3
3
 
4
- export const Command = createCommand(CenteredDialog);
4
+ export const Command = createCommand(Dialog);
5
5
 
6
6
  export type { CommandProps, CommandItem } from './types';
@@ -10,11 +10,8 @@ import React, {
10
10
  import {
11
11
  Pressable,
12
12
  StyleSheet,
13
- Text,
14
- TouchableOpacity,
15
13
  useWindowDimensions,
16
14
  View,
17
- type GestureResponderEvent,
18
15
  type StyleProp,
19
16
  type ViewStyle,
20
17
  } from 'react-native';
@@ -29,12 +26,12 @@ import Animated, {
29
26
 
30
27
  import { BottomSheet, type BottomSheetRef } from '../bottom-sheet';
31
28
  import { Z_INDEX } from '../styles/z-index';
32
- import type { ThemeColors } from '../theme/types';
33
29
  import { useTheme } from '../theme/use-theme';
34
- import { Context, useDialogContext, useDialogControl } from './context';
30
+ import { Context, useDialogControl } from './context';
31
+ import { DialogBody } from './DialogContent';
32
+ import { DialogBottomSheet } from './DialogBottomSheet';
35
33
  import {
36
34
  ANIMATION_DURATION,
37
- DEFAULT_MAX_HEIGHT_RATIO,
38
35
  DEFAULT_SIDE_WIDTH,
39
36
  DIALOG_SHEET_BACKDROP_TESTID,
40
37
  PANEL_RADIUS,
@@ -44,7 +41,6 @@ import {
44
41
  } from './placement';
45
42
  import type {
46
43
  DialogAction,
47
- DialogActionColor,
48
44
  DialogControlProps,
49
45
  DialogInset,
50
46
  DialogProps,
@@ -65,8 +61,7 @@ export { DIALOG_SHEET_BACKDROP_TESTID };
65
61
  * centered card via the 500px cap; flush for bottom: a full-width sheet
66
62
  * with a drag handle). Default behavior is unchanged.
67
63
  * - `'left'` / `'right'` — an anchored side-sheet/drawer driven by
68
- * reanimated (the `responsive-sheet` native technique). Exit animations
69
- * are safe on native.
64
+ * reanimated. Exit animations are safe on native.
70
65
  *
71
66
  * The component accepts three rendering modes simultaneously:
72
67
  *
@@ -75,6 +70,31 @@ export { DIALOG_SHEET_BACKDROP_TESTID };
75
70
  * 3. Pure children — no `title`/`description`/`actions`.
76
71
  */
77
72
  export function Dialog({
73
+ placement,
74
+ ...rest
75
+ }: DialogProps) {
76
+ const resolvedPlacement = useResolvedPlacement(placement);
77
+
78
+ // `bottom` routes to the shared cross-platform `BottomSheet` surface — one
79
+ // code path with drag-to-dismiss on web and native. `center` (default) and
80
+ // the side-sheets keep their existing native lifecycle below. Each branch is
81
+ // its own component so the dispatcher only ever calls `useResolvedPlacement`,
82
+ // keeping the rules-of-hooks contract intact across a responsive placement
83
+ // change.
84
+ if (resolvedPlacement === 'bottom') {
85
+ return <DialogBottomSheet {...rest} />;
86
+ }
87
+ return <CenteredOrSideDialog {...rest} placement={resolvedPlacement} />;
88
+ }
89
+
90
+ /**
91
+ * Native `center` and `left`/`right` placements. `center` uses bloom's
92
+ * `BottomSheet` in `detached` mode (a floating, content-hugging card that
93
+ * degrades from sheet to centered card via the 500px cap); the side placements
94
+ * use a reanimated drawer. These share one open/close lifecycle. The `bottom`
95
+ * placement is handled separately by `DialogBottomSheet`.
96
+ */
97
+ function CenteredOrSideDialog({
78
98
  control,
79
99
  open: controlledOpen,
80
100
  onClose,
@@ -84,9 +104,7 @@ export function Dialog({
84
104
  actions,
85
105
  placement,
86
106
  width = DEFAULT_SIDE_WIDTH,
87
- maxHeightRatio = DEFAULT_MAX_HEIGHT_RATIO,
88
107
  inset,
89
- showHandle = true,
90
108
  dismissOnBackdrop = true,
91
109
  style,
92
110
  panelStyle,
@@ -95,10 +113,9 @@ export function Dialog({
95
113
  containerClassName,
96
114
  label,
97
115
  children,
98
- }: DialogProps) {
116
+ }: Omit<DialogProps, 'placement'> & { placement: 'center' | 'left' | 'right' }) {
99
117
  const isControlled = controlledOpen !== undefined;
100
- const resolvedPlacement = useResolvedPlacement(placement);
101
- const isSide = resolvedPlacement === 'left' || resolvedPlacement === 'right';
118
+ const isSide = placement === 'left' || placement === 'right';
102
119
 
103
120
  // Imperative open state for the side placement (the BottomSheet path owns its
104
121
  // own visibility via its ref instead).
@@ -221,7 +238,7 @@ export function Dialog({
221
238
  <SideSheet
222
239
  open={sideOpen}
223
240
  onDismiss={handleDismiss}
224
- side={resolvedPlacement}
241
+ side={placement}
225
242
  width={width}
226
243
  inset={inset}
227
244
  dismissOnBackdrop={dismissOnBackdrop}
@@ -243,19 +260,17 @@ export function Dialog({
243
260
  );
244
261
  }
245
262
 
246
- const isBottom = resolvedPlacement === 'bottom';
247
-
248
263
  return (
249
264
  <BottomSheet
250
265
  ref={ref}
251
266
  onDismiss={handleDismiss}
252
267
  enablePanDownToClose
253
- detached={!isBottom}
254
- showHandle={isBottom ? showHandle : true}
268
+ detached
269
+ showHandle
255
270
  // Stronger dim when a Dialog is stacked over another sheet so the
256
271
  // underlying sheet's handle/content doesn't bleed through.
257
272
  backdropOpacity={0.7}
258
- style={isBottom ? bottomSheetStyle(theme.colors.background, maxHeightRatio) : sheetStyle}
273
+ style={sheetStyle}
259
274
  >
260
275
  <Context.Provider value={context}>
261
276
  <View
@@ -281,71 +296,6 @@ export function Dialog({
281
296
  );
282
297
  }
283
298
 
284
- function bottomSheetStyle(background: string, maxHeightRatio: number): ViewStyle {
285
- return {
286
- backgroundColor: background,
287
- borderTopLeftRadius: PANEL_RADIUS + 4,
288
- borderTopRightRadius: PANEL_RADIUS + 4,
289
- maxHeight: `${Math.round(maxHeightRatio * 100)}%`,
290
- };
291
- }
292
-
293
- /**
294
- * Renders the dialog's body: optional declarative title + description, any
295
- * `children`, then the action row. Shared by all placements. The
296
- * `titleId`/`descriptionId` are wired by the caller for accessibility.
297
- */
298
- function DialogBody({
299
- titleId,
300
- descriptionId,
301
- title,
302
- description,
303
- actions,
304
- children,
305
- }: {
306
- titleId: string;
307
- descriptionId: string;
308
- title?: string;
309
- description?: string;
310
- actions?: DialogAction[];
311
- children?: React.ReactNode;
312
- }) {
313
- const theme = useTheme();
314
- return (
315
- <>
316
- {title ? (
317
- <Text
318
- nativeID={titleId}
319
- style={{
320
- fontSize: 22,
321
- fontWeight: '600',
322
- color: theme.colors.text,
323
- paddingBottom: description ? 4 : 16,
324
- lineHeight: 30,
325
- }}
326
- >
327
- {title}
328
- </Text>
329
- ) : null}
330
- {description ? (
331
- <Text
332
- nativeID={descriptionId}
333
- style={{
334
- fontSize: 16,
335
- color: theme.colors.textSecondary,
336
- paddingBottom: 16,
337
- lineHeight: 22,
338
- }}
339
- >
340
- {description}
341
- </Text>
342
- ) : null}
343
- {children}
344
- {actions && actions.length > 0 ? <ActionRow actions={actions} /> : null}
345
- </>
346
- );
347
- }
348
-
349
299
  /**
350
300
  * Reanimated side-sheet/drawer for the `left`/`right` placements (native).
351
301
  *
@@ -517,89 +467,6 @@ function SideSheet({
517
467
  );
518
468
  }
519
469
 
520
- function ActionRow({ actions }: { actions: DialogAction[] }) {
521
- return (
522
- <View style={{ width: '100%', gap: 8, justifyContent: 'flex-end' }}>
523
- {actions.map((action, idx) => (
524
- <ActionButton
525
- key={`${action.label}-${idx}`}
526
- action={action}
527
- />
528
- ))}
529
- </View>
530
- );
531
- }
532
-
533
- function ActionButton({ action }: { action: DialogAction }) {
534
- const { close } = useDialogContext();
535
- const theme = useTheme();
536
- const color: DialogActionColor = action.color ?? 'default';
537
- const shouldCloseOnPress = action.shouldCloseOnPress ?? true;
538
-
539
- const { background, foreground } = getActionPalette(color, theme.colors);
540
-
541
- const handlePress = useCallback(
542
- (e: GestureResponderEvent) => {
543
- const onPress = action.onPress;
544
- if (color === 'cancel') {
545
- // Cancel always dismisses; consumer's onPress (rare) runs after.
546
- close(onPress ? () => onPress(e) : undefined);
547
- return;
548
- }
549
- if (shouldCloseOnPress) {
550
- close(onPress ? () => onPress(e) : undefined);
551
- } else {
552
- onPress?.(e);
553
- }
554
- },
555
- [action.onPress, close, color, shouldCloseOnPress],
556
- );
557
-
558
- return (
559
- <TouchableOpacity
560
- style={{
561
- borderRadius: 9999,
562
- alignItems: 'center',
563
- justifyContent: 'center',
564
- backgroundColor: background,
565
- opacity: action.disabled ? 0.5 : 1,
566
- paddingVertical: 12,
567
- paddingHorizontal: 24,
568
- }}
569
- onPress={handlePress}
570
- disabled={action.disabled}
571
- activeOpacity={0.7}
572
- testID={action.testID}
573
- >
574
- <Text style={{ fontSize: 16, fontWeight: '500', color: foreground }}>
575
- {action.label}
576
- </Text>
577
- </TouchableOpacity>
578
- );
579
- }
580
-
581
- function getActionPalette(
582
- color: DialogActionColor,
583
- colors: ThemeColors,
584
- ): { background: string; foreground: string } {
585
- switch (color) {
586
- case 'destructive':
587
- return {
588
- background: colors.negative,
589
- foreground: colors.negativeForeground,
590
- };
591
- case 'cancel':
592
- return { background: colors.contrast50, foreground: colors.text };
593
- case 'default':
594
- return { background: colors.primary, foreground: colors.primaryForeground };
595
- /* c8 ignore next 2 -- TS exhaustiveness check guards this branch */
596
- default: {
597
- const _exhaustive: never = color;
598
- return { background: colors.primary, foreground: colors.primaryForeground };
599
- }
600
- }
601
- }
602
-
603
470
  const sideStyles = StyleSheet.create({
604
471
  root: {
605
472
  ...StyleSheet.absoluteFill,