@oxyhq/bloom 0.3.12 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/README.md +133 -90
  2. package/lib/commonjs/bottom-sheet/index.js +341 -98
  3. package/lib/commonjs/bottom-sheet/index.js.map +1 -1
  4. package/lib/commonjs/context-menu/index.js +18 -19
  5. package/lib/commonjs/context-menu/index.js.map +1 -1
  6. package/lib/commonjs/dialog/BloomDialogProvider.js +61 -0
  7. package/lib/commonjs/dialog/BloomDialogProvider.js.map +1 -0
  8. package/lib/commonjs/dialog/BloomDialogProvider.web.js +45 -0
  9. package/lib/commonjs/dialog/BloomDialogProvider.web.js.map +1 -0
  10. package/lib/commonjs/dialog/Dialog.js +197 -100
  11. package/lib/commonjs/dialog/Dialog.js.map +1 -1
  12. package/lib/commonjs/dialog/Dialog.web.js +194 -84
  13. package/lib/commonjs/dialog/Dialog.web.js.map +1 -1
  14. package/lib/commonjs/dialog/SheetShell.js +149 -0
  15. package/lib/commonjs/dialog/SheetShell.js.map +1 -0
  16. package/lib/commonjs/dialog/alert-store.js +116 -0
  17. package/lib/commonjs/dialog/alert-store.js.map +1 -0
  18. package/lib/commonjs/dialog/alert.js +38 -0
  19. package/lib/commonjs/dialog/alert.js.map +1 -0
  20. package/lib/commonjs/dialog/context.js +10 -2
  21. package/lib/commonjs/dialog/context.js.map +1 -1
  22. package/lib/commonjs/dialog/index.js +8 -24
  23. package/lib/commonjs/dialog/index.js.map +1 -1
  24. package/lib/commonjs/dialog/index.web.js +10 -20
  25. package/lib/commonjs/dialog/index.web.js.map +1 -1
  26. package/lib/commonjs/index.js +101 -66
  27. package/lib/commonjs/index.js.map +1 -1
  28. package/lib/commonjs/index.web.js +101 -66
  29. package/lib/commonjs/index.web.js.map +1 -1
  30. package/lib/commonjs/menu/index.js +21 -23
  31. package/lib/commonjs/menu/index.js.map +1 -1
  32. package/lib/commonjs/select/index.js +26 -27
  33. package/lib/commonjs/select/index.js.map +1 -1
  34. package/lib/commonjs/toast/index.js +42 -13
  35. package/lib/commonjs/toast/index.js.map +1 -1
  36. package/lib/commonjs/toast/index.web.js +19 -15
  37. package/lib/commonjs/toast/index.web.js.map +1 -1
  38. package/lib/module/bottom-sheet/index.js +341 -98
  39. package/lib/module/bottom-sheet/index.js.map +1 -1
  40. package/lib/module/context-menu/index.js +15 -16
  41. package/lib/module/context-menu/index.js.map +1 -1
  42. package/lib/module/dialog/BloomDialogProvider.js +57 -0
  43. package/lib/module/dialog/BloomDialogProvider.js.map +1 -0
  44. package/lib/module/dialog/BloomDialogProvider.web.js +41 -0
  45. package/lib/module/dialog/BloomDialogProvider.web.js.map +1 -0
  46. package/lib/module/dialog/Dialog.js +199 -87
  47. package/lib/module/dialog/Dialog.js.map +1 -1
  48. package/lib/module/dialog/Dialog.web.js +195 -70
  49. package/lib/module/dialog/Dialog.web.js.map +1 -1
  50. package/lib/module/dialog/SheetShell.js +143 -0
  51. package/lib/module/dialog/SheetShell.js.map +1 -0
  52. package/lib/module/dialog/alert-store.js +107 -0
  53. package/lib/module/dialog/alert-store.js.map +1 -0
  54. package/lib/module/dialog/alert.js +35 -0
  55. package/lib/module/dialog/alert.js.map +1 -0
  56. package/lib/module/dialog/context.js +10 -2
  57. package/lib/module/dialog/context.js.map +1 -1
  58. package/lib/module/dialog/index.js +3 -1
  59. package/lib/module/dialog/index.js.map +1 -1
  60. package/lib/module/dialog/index.web.js +9 -7
  61. package/lib/module/dialog/index.web.js.map +1 -1
  62. package/lib/module/index.js +2 -3
  63. package/lib/module/index.js.map +1 -1
  64. package/lib/module/index.web.js +2 -3
  65. package/lib/module/index.web.js.map +1 -1
  66. package/lib/module/menu/index.js +11 -13
  67. package/lib/module/menu/index.js.map +1 -1
  68. package/lib/module/select/index.js +27 -28
  69. package/lib/module/select/index.js.map +1 -1
  70. package/lib/module/toast/index.js +41 -11
  71. package/lib/module/toast/index.js.map +1 -1
  72. package/lib/module/toast/index.web.js +18 -13
  73. package/lib/module/toast/index.web.js.map +1 -1
  74. package/lib/typescript/commonjs/__tests__/Dialog.test.d.ts +2 -0
  75. package/lib/typescript/commonjs/__tests__/Dialog.test.d.ts.map +1 -0
  76. package/lib/typescript/commonjs/bottom-sheet/index.d.ts +47 -1
  77. package/lib/typescript/commonjs/bottom-sheet/index.d.ts.map +1 -1
  78. package/lib/typescript/commonjs/context-menu/index.d.ts +4 -3
  79. package/lib/typescript/commonjs/context-menu/index.d.ts.map +1 -1
  80. package/lib/typescript/commonjs/dialog/BloomDialogProvider.d.ts +27 -0
  81. package/lib/typescript/commonjs/dialog/BloomDialogProvider.d.ts.map +1 -0
  82. package/lib/typescript/commonjs/dialog/BloomDialogProvider.web.d.ts +15 -0
  83. package/lib/typescript/commonjs/dialog/BloomDialogProvider.web.d.ts.map +1 -0
  84. package/lib/typescript/commonjs/dialog/Dialog.d.ts +37 -10
  85. package/lib/typescript/commonjs/dialog/Dialog.d.ts.map +1 -1
  86. package/lib/typescript/commonjs/dialog/Dialog.web.d.ts +26 -10
  87. package/lib/typescript/commonjs/dialog/Dialog.web.d.ts.map +1 -1
  88. package/lib/typescript/commonjs/dialog/SheetShell.d.ts +31 -0
  89. package/lib/typescript/commonjs/dialog/SheetShell.d.ts.map +1 -0
  90. package/lib/typescript/commonjs/dialog/alert-store.d.ts +70 -0
  91. package/lib/typescript/commonjs/dialog/alert-store.d.ts.map +1 -0
  92. package/lib/typescript/commonjs/dialog/alert.d.ts +27 -0
  93. package/lib/typescript/commonjs/dialog/alert.d.ts.map +1 -0
  94. package/lib/typescript/commonjs/dialog/context.d.ts +7 -0
  95. package/lib/typescript/commonjs/dialog/context.d.ts.map +1 -1
  96. package/lib/typescript/commonjs/dialog/index.d.ts +5 -2
  97. package/lib/typescript/commonjs/dialog/index.d.ts.map +1 -1
  98. package/lib/typescript/commonjs/dialog/index.web.d.ts +5 -2
  99. package/lib/typescript/commonjs/dialog/index.web.d.ts.map +1 -1
  100. package/lib/typescript/commonjs/dialog/types.d.ts +70 -15
  101. package/lib/typescript/commonjs/dialog/types.d.ts.map +1 -1
  102. package/lib/typescript/commonjs/index.d.ts +3 -3
  103. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  104. package/lib/typescript/commonjs/index.web.d.ts +3 -3
  105. package/lib/typescript/commonjs/index.web.d.ts.map +1 -1
  106. package/lib/typescript/commonjs/menu/index.d.ts +4 -4
  107. package/lib/typescript/commonjs/menu/index.d.ts.map +1 -1
  108. package/lib/typescript/commonjs/select/index.d.ts.map +1 -1
  109. package/lib/typescript/commonjs/toast/index.d.ts +32 -3
  110. package/lib/typescript/commonjs/toast/index.d.ts.map +1 -1
  111. package/lib/typescript/commonjs/toast/index.web.d.ts +14 -7
  112. package/lib/typescript/commonjs/toast/index.web.d.ts.map +1 -1
  113. package/lib/typescript/module/__tests__/Dialog.test.d.ts +2 -0
  114. package/lib/typescript/module/__tests__/Dialog.test.d.ts.map +1 -0
  115. package/lib/typescript/module/bottom-sheet/index.d.ts +47 -1
  116. package/lib/typescript/module/bottom-sheet/index.d.ts.map +1 -1
  117. package/lib/typescript/module/context-menu/index.d.ts +4 -3
  118. package/lib/typescript/module/context-menu/index.d.ts.map +1 -1
  119. package/lib/typescript/module/dialog/BloomDialogProvider.d.ts +27 -0
  120. package/lib/typescript/module/dialog/BloomDialogProvider.d.ts.map +1 -0
  121. package/lib/typescript/module/dialog/BloomDialogProvider.web.d.ts +15 -0
  122. package/lib/typescript/module/dialog/BloomDialogProvider.web.d.ts.map +1 -0
  123. package/lib/typescript/module/dialog/Dialog.d.ts +37 -10
  124. package/lib/typescript/module/dialog/Dialog.d.ts.map +1 -1
  125. package/lib/typescript/module/dialog/Dialog.web.d.ts +26 -10
  126. package/lib/typescript/module/dialog/Dialog.web.d.ts.map +1 -1
  127. package/lib/typescript/module/dialog/SheetShell.d.ts +31 -0
  128. package/lib/typescript/module/dialog/SheetShell.d.ts.map +1 -0
  129. package/lib/typescript/module/dialog/alert-store.d.ts +70 -0
  130. package/lib/typescript/module/dialog/alert-store.d.ts.map +1 -0
  131. package/lib/typescript/module/dialog/alert.d.ts +27 -0
  132. package/lib/typescript/module/dialog/alert.d.ts.map +1 -0
  133. package/lib/typescript/module/dialog/context.d.ts +7 -0
  134. package/lib/typescript/module/dialog/context.d.ts.map +1 -1
  135. package/lib/typescript/module/dialog/index.d.ts +5 -2
  136. package/lib/typescript/module/dialog/index.d.ts.map +1 -1
  137. package/lib/typescript/module/dialog/index.web.d.ts +5 -2
  138. package/lib/typescript/module/dialog/index.web.d.ts.map +1 -1
  139. package/lib/typescript/module/dialog/types.d.ts +70 -15
  140. package/lib/typescript/module/dialog/types.d.ts.map +1 -1
  141. package/lib/typescript/module/index.d.ts +3 -3
  142. package/lib/typescript/module/index.d.ts.map +1 -1
  143. package/lib/typescript/module/index.web.d.ts +3 -3
  144. package/lib/typescript/module/index.web.d.ts.map +1 -1
  145. package/lib/typescript/module/menu/index.d.ts +4 -4
  146. package/lib/typescript/module/menu/index.d.ts.map +1 -1
  147. package/lib/typescript/module/select/index.d.ts.map +1 -1
  148. package/lib/typescript/module/toast/index.d.ts +32 -3
  149. package/lib/typescript/module/toast/index.d.ts.map +1 -1
  150. package/lib/typescript/module/toast/index.web.d.ts +14 -7
  151. package/lib/typescript/module/toast/index.web.d.ts.map +1 -1
  152. package/package.json +3 -14
  153. package/src/__tests__/BottomSheet.test.tsx +149 -2
  154. package/src/__tests__/Dialog.test.tsx +177 -0
  155. package/src/bottom-sheet/index.tsx +367 -83
  156. package/src/context-menu/index.tsx +12 -12
  157. package/src/dialog/BloomDialogProvider.tsx +61 -0
  158. package/src/dialog/BloomDialogProvider.web.tsx +46 -0
  159. package/src/dialog/Dialog.tsx +217 -64
  160. package/src/dialog/Dialog.web.tsx +240 -75
  161. package/src/dialog/SheetShell.tsx +154 -0
  162. package/src/dialog/alert-store.ts +126 -0
  163. package/src/dialog/alert.ts +42 -0
  164. package/src/dialog/context.ts +14 -3
  165. package/src/dialog/index.ts +14 -2
  166. package/src/dialog/index.web.ts +20 -8
  167. package/src/dialog/types.ts +73 -16
  168. package/src/index.ts +17 -3
  169. package/src/index.web.ts +17 -3
  170. package/src/menu/index.tsx +13 -17
  171. package/src/select/index.tsx +30 -30
  172. package/src/toast/index.tsx +55 -11
  173. package/src/toast/index.web.tsx +33 -13
  174. package/lib/commonjs/prompt/Prompt.js +0 -267
  175. package/lib/commonjs/prompt/Prompt.js.map +0 -1
  176. package/lib/commonjs/prompt/index.js +0 -61
  177. package/lib/commonjs/prompt/index.js.map +0 -1
  178. package/lib/module/prompt/Prompt.js +0 -250
  179. package/lib/module/prompt/Prompt.js.map +0 -1
  180. package/lib/module/prompt/index.js +0 -4
  181. package/lib/module/prompt/index.js.map +0 -1
  182. package/lib/typescript/commonjs/prompt/Prompt.d.ts +0 -42
  183. package/lib/typescript/commonjs/prompt/Prompt.d.ts.map +0 -1
  184. package/lib/typescript/commonjs/prompt/index.d.ts +0 -3
  185. package/lib/typescript/commonjs/prompt/index.d.ts.map +0 -1
  186. package/lib/typescript/module/prompt/Prompt.d.ts +0 -42
  187. package/lib/typescript/module/prompt/Prompt.d.ts.map +0 -1
  188. package/lib/typescript/module/prompt/index.d.ts +0 -3
  189. package/lib/typescript/module/prompt/index.d.ts.map +0 -1
  190. package/src/prompt/Prompt.tsx +0 -247
  191. package/src/prompt/index.ts +0 -13
@@ -0,0 +1,42 @@
1
+ import {
2
+ enqueueAlert,
3
+ resolveButtons,
4
+ type AlertButton,
5
+ } from './alert-store';
6
+
7
+ /**
8
+ * Show a Bloom-styled confirmation dialog. Mirrors React Native's
9
+ * `Alert.alert(title, message?, buttons?)` signature so existing call
10
+ * sites migrate by changing the import only.
11
+ *
12
+ * If no buttons are passed, a single `OK` confirmation is rendered.
13
+ *
14
+ * The alert is enqueued in a module-scope store and rendered by
15
+ * `<BloomDialogProvider>`. Calls made before the provider mounts are
16
+ * queued and drained once the provider attaches — there is no fire-and-
17
+ * forget loss window. Calls made when no provider is ever mounted are
18
+ * silently queued forever; in development, mount the provider once at
19
+ * the app root and the queue will catch up immediately.
20
+ *
21
+ * ```tsx
22
+ * import { alert } from '@oxyhq/bloom';
23
+ *
24
+ * alert('Sign out?', 'You will need to enter your password to sign in again.', [
25
+ * { text: 'Cancel', style: 'cancel' },
26
+ * { text: 'Sign out', style: 'destructive', onPress: doSignOut },
27
+ * ]);
28
+ * ```
29
+ */
30
+ export function alert(
31
+ title: string,
32
+ message?: string,
33
+ buttons?: AlertButton[],
34
+ ): void {
35
+ enqueueAlert({
36
+ title,
37
+ message,
38
+ buttons: resolveButtons(buttons),
39
+ });
40
+ }
41
+
42
+ export type { AlertButton, AlertButtonStyle } from './alert-store';
@@ -1,5 +1,9 @@
1
1
  import { createContext, useContext, useId, useMemo, useRef } from 'react';
2
- import type { DialogContextProps, DialogControlRefProps, DialogControlProps } from './types';
2
+ import type {
3
+ DialogContextProps,
4
+ DialogControlProps,
5
+ DialogControlRefProps,
6
+ } from './types';
3
7
 
4
8
  export const Context = createContext<DialogContextProps>({
5
9
  close: () => {},
@@ -11,6 +15,13 @@ export function useDialogContext(): DialogContextProps {
11
15
  return useContext(Context);
12
16
  }
13
17
 
18
+ /**
19
+ * Return a stable handle that can imperatively `open()` and `close()` a
20
+ * `<Dialog>` mounted with the same control.
21
+ *
22
+ * The handle survives across re-renders; mounting a different `<Dialog>`
23
+ * with the same control attaches the new instance via the internal ref.
24
+ */
14
25
  export function useDialogControl(): DialogControlProps {
15
26
  const id = useId();
16
27
  const control = useRef<DialogControlRefProps | null>({
@@ -22,8 +33,8 @@ export function useDialogControl(): DialogControlProps {
22
33
  () => ({
23
34
  id,
24
35
  ref: control,
25
- open: (options) => {
26
- control.current?.open(options);
36
+ open: () => {
37
+ control.current?.open();
27
38
  },
28
39
  close: (cb) => {
29
40
  control.current?.close(cb);
@@ -1,3 +1,15 @@
1
- export { Outer, Inner, ScrollableInner, Handle, Close, Backdrop } from './Dialog';
1
+ export { Dialog } from './Dialog';
2
+ export { BloomDialogProvider } from './BloomDialogProvider';
3
+ export { alert } from './alert';
2
4
  export { useDialogContext, useDialogControl } from './context';
3
- export type { DialogControlProps, DialogOuterProps, DialogInnerProps, DialogContextProps } from './types';
5
+ export type {
6
+ AlertButton,
7
+ AlertButtonStyle,
8
+ } from './alert-store';
9
+ export type {
10
+ DialogAction,
11
+ DialogActionColor,
12
+ DialogContextProps,
13
+ DialogControlProps,
14
+ DialogProps,
15
+ } from './types';
@@ -1,13 +1,25 @@
1
1
  // Web variant of the `./dialog` barrel.
2
2
  //
3
- // The default barrel (`./index.ts`) re-exports from `./Dialog`, which on
4
- // native uses `react-native-safe-area-context` and Bloom's own `BottomSheet`
5
- // primitive. The web fork (`./Dialog.web`) is a pure-DOM modal overlay that
6
- // depends only on `react-remove-scroll-bar` and the in-package `Portal`.
3
+ // The default barrel (`./index.ts`) re-exports from `./Dialog`, which uses
4
+ // bloom's `BottomSheet` (a native-only primitive built on
5
+ // react-native-gesture-handler + reanimated). The web fork (`./Dialog.web`)
6
+ // is a pure-DOM modal overlay that renders into the bloom Portal.
7
7
  //
8
- // Web bundlers select this file via the `"browser"` condition in
8
+ // Web bundlers select this file via the `"browser"` export condition in
9
9
  // `package.json`'s `exports['./dialog']`; native bundlers fall through to
10
- // the React Native build.
11
- export { Outer, Inner, ScrollableInner, Handle, Close, Backdrop } from './Dialog.web';
10
+ // the React Native build above.
11
+ export { Dialog, BLOOM_DIALOG_CSS } from './Dialog.web';
12
+ export { BloomDialogProvider } from './BloomDialogProvider.web';
13
+ export { alert } from './alert';
12
14
  export { useDialogContext, useDialogControl } from './context';
13
- export type { DialogControlProps, DialogOuterProps, DialogInnerProps, DialogContextProps } from './types';
15
+ export type {
16
+ AlertButton,
17
+ AlertButtonStyle,
18
+ } from './alert-store';
19
+ export type {
20
+ DialogAction,
21
+ DialogActionColor,
22
+ DialogContextProps,
23
+ DialogControlProps,
24
+ DialogProps,
25
+ } from './types';
@@ -1,7 +1,15 @@
1
- import type { ScrollViewProps, StyleProp, ViewStyle } from 'react-native';
1
+ import type { GestureResponderEvent, StyleProp, ViewStyle } from 'react-native';
2
2
 
3
+ /**
4
+ * Imperative open/close handle returned by `useDialogControl`.
5
+ *
6
+ * Consumers receive an instance of `DialogControlProps`, which is a stable
7
+ * object whose `open`/`close` methods proxy to whichever `Dialog` instance
8
+ * has currently registered itself via the internal ref. Re-rendering the
9
+ * dialog under the same control does not break the handle.
10
+ */
3
11
  export type DialogControlRefProps = {
4
- open: (options?: Record<string, unknown>) => void;
12
+ open: () => void;
5
13
  close: (callback?: () => void) => void;
6
14
  };
7
15
 
@@ -15,25 +23,74 @@ export type DialogContextProps = {
15
23
  isWithinDialog: boolean;
16
24
  };
17
25
 
18
- export type DialogOuterProps = {
26
+ /**
27
+ * Color of a declarative `DialogAction`. Maps to bloom's theme palette:
28
+ *
29
+ * - `'default'` -> theme primary (filled CTA)
30
+ * - `'cancel'` -> theme secondary (auto-dismiss, no `onPress` required)
31
+ * - `'destructive'` -> theme negative
32
+ */
33
+ export type DialogActionColor = 'default' | 'cancel' | 'destructive';
34
+
35
+ export type DialogAction = {
36
+ label: string;
37
+ onPress?: (e: GestureResponderEvent) => void;
38
+ color?: DialogActionColor;
39
+ disabled?: boolean;
40
+ /**
41
+ * Defaults to `true`. When `true`, the dialog closes (and runs the close
42
+ * animation) before `onPress` is invoked, which gives the surrounding
43
+ * screen transition a chance to start before the action's side effects
44
+ * (navigation, network, etc.) kick in. Set `false` to keep the dialog
45
+ * mounted (e.g. while an async confirmation is in flight).
46
+ */
47
+ shouldCloseOnPress?: boolean;
48
+ testID?: string;
49
+ };
50
+
51
+ /**
52
+ * Props accepted by the unified `<Dialog>` component.
53
+ *
54
+ * Three usage modes — pick whichever fits the call site:
55
+ *
56
+ * 1. **Declarative (`title` / `description` / `actions`).** Most common
57
+ * confirm/cancel surface. Bloom renders the title, description and
58
+ * action row for you.
59
+ *
60
+ * 2. **Custom children.** Pass any JSX as `children` and bloom renders it
61
+ * verbatim inside the dialog frame. Combine with `title` to keep the
62
+ * header consistent.
63
+ *
64
+ * 3. **Imperative `alert()`.** Bypass the JSX layer entirely — see the
65
+ * module-level `alert()` helper.
66
+ */
67
+ export type DialogProps = React.PropsWithChildren<{
19
68
  control: DialogControlProps;
69
+ /** Fires after the dialog has finished closing. */
20
70
  onClose?: () => void;
21
71
  testID?: string;
22
- webOptions?: {
23
- alignCenter?: boolean;
24
- };
72
+ /** Optional dialog header text. Rendered above `description` / `children`. */
73
+ title?: string;
74
+ /** Optional supporting copy, rendered below the title. */
75
+ description?: string;
25
76
  /**
26
- * @deprecated No-op since 0.3.12. Bloom's BottomSheet sizes to its content by
27
- * default (capped by safe-area `maxHeight`), so dialogs no longer expand to
28
- * fill the screen and a manual lock is unnecessary.
77
+ * Optional action row. When provided, bloom renders the appropriate
78
+ * confirm/cancel/destructive buttons for you. Order is preserved.
79
+ */
80
+ actions?: DialogAction[];
81
+ /**
82
+ * Style overrides applied to the inner content container on native (the
83
+ * floating bottom-sheet card) and to the modal panel on web.
29
84
  */
30
- preventExpansion?: boolean;
31
- };
32
-
33
- export type DialogInnerProps = React.PropsWithChildren<{
34
85
  style?: StyleProp<ViewStyle>;
86
+ /** Accessibility label, applied to the dialog role on web. */
35
87
  label?: string;
36
- header?: React.ReactNode;
37
- contentContainerStyle?: StyleProp<ViewStyle>;
38
- keyboardDismissMode?: ScrollViewProps['keyboardDismissMode'];
39
88
  }>;
89
+
90
+ /**
91
+ * Web-only options. Native uses bloom's `BottomSheet` underneath which has
92
+ * its own positioning model.
93
+ */
94
+ export type DialogWebOptions = {
95
+ alignCenter?: boolean;
96
+ };
package/src/index.ts CHANGED
@@ -18,8 +18,22 @@ export { type Props as IconProps, sizes as iconSizes, useCommonSVGProps } from '
18
18
 
19
19
  // Core components
20
20
  export * from './portal';
21
- export * as Dialog from './dialog';
22
- export * as Prompt from './prompt';
21
+ export {
22
+ Dialog,
23
+ BloomDialogProvider,
24
+ alert,
25
+ useDialogContext,
26
+ useDialogControl,
27
+ } from './dialog';
28
+ export type {
29
+ AlertButton,
30
+ AlertButtonStyle,
31
+ DialogAction,
32
+ DialogActionColor,
33
+ DialogContextProps,
34
+ DialogControlProps,
35
+ DialogProps,
36
+ } from './dialog';
23
37
  export * from './button';
24
38
  export * from './grouped-buttons';
25
39
  export * from './divider';
@@ -31,7 +45,7 @@ export * from './avatar';
31
45
  export * from './loading';
32
46
  export * as PromptInput from './prompt-input';
33
47
  export * from './switch';
34
- export * as Toast from './toast';
48
+ export { toast, type Toast } from './toast';
35
49
 
36
50
  // Typography
37
51
  export * as Typography from './typography';
package/src/index.web.ts CHANGED
@@ -23,8 +23,22 @@ export { type Props as IconProps, sizes as iconSizes, useCommonSVGProps } from '
23
23
 
24
24
  // Core components
25
25
  export * from './portal/index.web';
26
- export * as Dialog from './dialog/index.web';
27
- export * as Prompt from './prompt';
26
+ export {
27
+ Dialog,
28
+ BloomDialogProvider,
29
+ alert,
30
+ useDialogContext,
31
+ useDialogControl,
32
+ } from './dialog/index.web';
33
+ export type {
34
+ AlertButton,
35
+ AlertButtonStyle,
36
+ DialogAction,
37
+ DialogActionColor,
38
+ DialogContextProps,
39
+ DialogControlProps,
40
+ DialogProps,
41
+ } from './dialog/index.web';
28
42
  export * from './button';
29
43
  export * from './grouped-buttons';
30
44
  export * from './divider';
@@ -36,7 +50,7 @@ export * from './avatar';
36
50
  export * from './loading';
37
51
  export * as PromptInput from './prompt-input';
38
52
  export * from './switch';
39
- export * as Toast from './toast/index.web';
53
+ export { toast, type Toast } from './toast/index.web';
40
54
 
41
55
  // Typography
42
56
  export * as Typography from './typography';
@@ -4,7 +4,9 @@ import { Pressable, StyleSheet, View, type StyleProp, type ViewStyle } from 'rea
4
4
  import { useTheme } from '../theme/use-theme';
5
5
  import { Text } from '../typography';
6
6
  import { Button } from '../button';
7
- import * as Dialog from '../dialog';
7
+ import { useDialogControl } from '../dialog/context';
8
+ import { SheetShell } from '../dialog/SheetShell';
9
+ import type { DialogControlProps } from '../dialog/types';
8
10
  import {
9
11
  MenuContext,
10
12
  ItemContext,
@@ -20,17 +22,17 @@ import type {
20
22
  TriggerProps,
21
23
  } from './types';
22
24
 
23
- export type { DialogControlProps as MenuControlProps } from '../dialog';
24
- export { useDialogControl as useMenuControl } from '../dialog';
25
+ export type { DialogControlProps as MenuControlProps } from '../dialog/types';
26
+ export { useDialogControl as useMenuControl } from '../dialog/context';
25
27
  export { useMenuContext };
26
28
 
27
29
  export function Root({
28
30
  children,
29
31
  control,
30
32
  }: React.PropsWithChildren<{
31
- control?: Dialog.DialogControlProps;
33
+ control?: DialogControlProps;
32
34
  }>) {
33
- const defaultControl = Dialog.useDialogControl();
35
+ const defaultControl = useDialogControl();
34
36
  const context = useMemo<MenuContextType>(
35
37
  () => ({
36
38
  control: control ?? defaultControl,
@@ -83,20 +85,14 @@ export function Outer({
83
85
  const context = useMenuContext();
84
86
 
85
87
  return (
86
- <Dialog.Outer
87
- control={context.control}
88
- preventExpansion
89
- >
90
- <Dialog.Handle />
88
+ <SheetShell control={context.control} label="Menu">
91
89
  <MenuContext.Provider value={context}>
92
- <Dialog.ScrollableInner label="Menu">
93
- <View style={styles.outerContent}>
94
- {children}
95
- {showCancel && <Cancel />}
96
- </View>
97
- </Dialog.ScrollableInner>
90
+ <View style={styles.outerContent}>
91
+ {children}
92
+ {showCancel && <Cancel />}
93
+ </View>
98
94
  </MenuContext.Provider>
99
- </Dialog.Outer>
95
+ </SheetShell>
100
96
  );
101
97
  }
102
98
 
@@ -11,7 +11,9 @@ import { FlatList, Pressable, StyleSheet, View } from 'react-native';
11
11
  import { useTheme } from '../theme/use-theme';
12
12
  import { Text } from '../typography';
13
13
  import { Button } from '../button';
14
- import * as Dialog from '../dialog';
14
+ import { useDialogContext, useDialogControl } from '../dialog/context';
15
+ import { SheetShell } from '../dialog/SheetShell';
16
+ import type { DialogControlProps } from '../dialog/types';
15
17
  import { RadioIndicator } from '../radio-indicator';
16
18
  import { useInteractionState } from '../hooks/useInteractionState';
17
19
  import {
@@ -37,7 +39,7 @@ export { useItemContext };
37
39
  // ---------------------------------------------------------------------------
38
40
 
39
41
  type SelectContextValue = {
40
- control: Dialog.DialogControlProps;
42
+ control: DialogControlProps;
41
43
  } & Pick<RootProps, 'value' | 'onValueChange' | 'disabled'>;
42
44
 
43
45
  const SelectContext = createContext<SelectContextValue | null>(null);
@@ -61,7 +63,7 @@ function useSelectContext(): SelectContextValue {
61
63
  // ---------------------------------------------------------------------------
62
64
 
63
65
  export function Root({ children, value, onValueChange, disabled }: RootProps) {
64
- const control = Dialog.useDialogControl();
66
+ const control = useDialogControl();
65
67
  const valueStoreState = useState<unknown>(undefined);
66
68
 
67
69
  const ctx = useMemo<SelectContextValue>(
@@ -187,23 +189,21 @@ export function Content<T>({
187
189
  }, [items, context.value, valueExtractor, setStoredValue]);
188
190
 
189
191
  return (
190
- <Dialog.Outer control={control}>
191
- <ContentInner
192
- control={control}
193
- items={items}
194
- valueExtractor={valueExtractor}
195
- {...props}
196
- value={context.value}
197
- onValueChange={context.onValueChange}
198
- disabled={context.disabled}
199
- />
200
- </Dialog.Outer>
192
+ <ContentInner
193
+ control={control}
194
+ items={items}
195
+ valueExtractor={valueExtractor}
196
+ {...props}
197
+ value={context.value}
198
+ onValueChange={context.onValueChange}
199
+ disabled={context.disabled}
200
+ />
201
201
  );
202
202
  }
203
203
 
204
204
  type ContentInnerProps<T> = ContentProps<T> &
205
205
  Pick<RootProps, 'value' | 'onValueChange' | 'disabled'> & {
206
- control: Dialog.DialogControlProps;
206
+ control: DialogControlProps;
207
207
  };
208
208
 
209
209
  function ContentInner<T>({
@@ -234,26 +234,26 @@ function ContentInner<T>({
234
234
  );
235
235
 
236
236
  return (
237
- <SelectContext.Provider value={ctx}>
238
- <Dialog.Handle />
239
- <Dialog.Inner
240
- label={label}
241
- header={
242
- <View style={styles.contentHeader}>
243
- <Text style={[styles.contentHeaderText, { color: theme.colors.text }]}>
244
- {label}
245
- </Text>
246
- </View>
247
- }
248
- >
237
+ <SheetShell
238
+ control={control}
239
+ label={label}
240
+ header={
241
+ <View style={styles.contentHeader}>
242
+ <Text style={[styles.contentHeaderText, { color: theme.colors.text }]}>
243
+ {label}
244
+ </Text>
245
+ </View>
246
+ }
247
+ >
248
+ <SelectContext.Provider value={ctx}>
249
249
  <FlatList
250
250
  data={items}
251
251
  renderItem={render}
252
252
  keyExtractor={valueExtractor}
253
253
  style={styles.flatList}
254
254
  />
255
- </Dialog.Inner>
256
- </SelectContext.Provider>
255
+ </SelectContext.Provider>
256
+ </SheetShell>
257
257
  );
258
258
  }
259
259
 
@@ -267,7 +267,7 @@ function ContentInner<T>({
267
267
 
268
268
  export function Item({ children, value, label, style }: ItemProps) {
269
269
  const theme = useTheme();
270
- const { close } = Dialog.useDialogContext();
270
+ const { close } = useDialogContext();
271
271
  const { value: selectedValue, onValueChange } = useSelectContext();
272
272
  const { state: focused, onIn: onFocus, onOut: onBlur } = useInteractionState();
273
273
  const {
@@ -10,7 +10,7 @@ import {
10
10
  Text as ToastText,
11
11
  ToastConfigProvider,
12
12
  } from './Toast';
13
- import type { BaseToastOptions } from './types';
13
+ import type { BaseToastOptions, ToastType } from './types';
14
14
 
15
15
  export { DURATION } from './const';
16
16
  export { Action, Icon, Outer, Text, ToastConfigProvider } from './Toast';
@@ -33,21 +33,17 @@ function OuterWrapper({ children }: { children: React.ReactNode }) {
33
33
  }
34
34
 
35
35
  /**
36
- * Access the full Sonner API
36
+ * Direct access to the Sonner API. Use sparingly — `toast()` covers the
37
+ * common case and keeps the surface tied to bloom's themed look.
37
38
  */
38
39
  export const api = sonner;
39
40
 
40
- /**
41
- * Show a toast notification.
42
- *
43
- * Pass a string for a simple text toast, or a React element for a custom toast.
44
- */
45
- export function show(
41
+ function dispatch(
46
42
  content: React.ReactNode,
47
- { type = 'default', ...options }: BaseToastOptions = {},
48
- ) {
43
+ type: ToastType,
44
+ options: BaseToastOptions = {},
45
+ ): void {
49
46
  const id = nanoid();
50
-
51
47
  if (typeof content === 'string') {
52
48
  sonner.custom(
53
49
  <ToastConfigProvider id={id} type={type}>
@@ -80,6 +76,54 @@ export function show(
80
76
  }
81
77
  }
82
78
 
79
+ /**
80
+ * Show a toast notification.
81
+ *
82
+ * Pass a string for a simple text toast, or a React element for a custom
83
+ * toast. The optional `options` argument accepts the standard Sonner
84
+ * options plus a bloom `type` (defaults to `'default'`).
85
+ *
86
+ * ```ts
87
+ * toast('Saved');
88
+ * toast.success('Profile updated');
89
+ * toast.error('Network error', { duration: 5000 });
90
+ * toast.dismiss(id);
91
+ * ```
92
+ *
93
+ * Pre-typed variants (`toast.success`, `toast.error`, `toast.warning`,
94
+ * `toast.info`) are aliases for the corresponding `type`.
95
+ */
96
+ export interface ToastFn {
97
+ (content: React.ReactNode, options?: BaseToastOptions): void;
98
+ success: (content: React.ReactNode, options?: Omit<BaseToastOptions, 'type'>) => void;
99
+ error: (content: React.ReactNode, options?: Omit<BaseToastOptions, 'type'>) => void;
100
+ warning: (content: React.ReactNode, options?: Omit<BaseToastOptions, 'type'>) => void;
101
+ info: (content: React.ReactNode, options?: Omit<BaseToastOptions, 'type'>) => void;
102
+ dismiss: (id?: string | number) => void;
103
+ }
104
+
105
+ const toastImpl = ((content: React.ReactNode, options: BaseToastOptions = {}) => {
106
+ dispatch(content, options.type ?? 'default', options);
107
+ }) as ToastFn;
108
+
109
+ toastImpl.success = (content, options) => dispatch(content, 'success', options ?? {});
110
+ toastImpl.error = (content, options) => dispatch(content, 'error', options ?? {});
111
+ toastImpl.warning = (content, options) => dispatch(content, 'warning', options ?? {});
112
+ toastImpl.info = (content, options) => dispatch(content, 'info', options ?? {});
113
+ toastImpl.dismiss = (id) => sonner.dismiss(id);
114
+
115
+ export const toast: ToastFn = toastImpl;
116
+
117
+ /**
118
+ * Alias of `toast` kept for compatibility with the original 0.4.x surface
119
+ * where `show()` was the documented entry point. New code should prefer
120
+ * `toast()` directly.
121
+ */
122
+ export const show: ToastFn = toastImpl;
123
+
124
+ /** Re-export the Toast function type so callers can refer to it. */
125
+ export type Toast = ToastFn;
126
+
83
127
  const wrapperStyles = StyleSheet.create({
84
128
  container: {
85
129
  paddingHorizontal: 20,
@@ -9,7 +9,7 @@ import {
9
9
  Text as ToastText,
10
10
  ToastConfigProvider,
11
11
  } from './Toast';
12
- import type { BaseToastOptions } from './types';
12
+ import type { BaseToastOptions, ToastType } from './types';
13
13
 
14
14
  export { DURATION } from './const';
15
15
  export { Action, Icon, Outer, Text, ToastConfigProvider } from './Toast';
@@ -30,22 +30,15 @@ export function ToastOutlet() {
30
30
  );
31
31
  }
32
32
 
33
- /**
34
- * Access the full Sonner API
35
- */
33
+ /** Direct access to the underlying Sonner API. Use sparingly. */
36
34
  export const api: typeof sonner = sonner;
37
35
 
38
- /**
39
- * Show a toast notification.
40
- *
41
- * Pass a string for a simple text toast, or a React element for a custom toast.
42
- */
43
- export function show(
36
+ function dispatch(
44
37
  content: React.ReactNode,
45
- { type = 'default', ...options }: BaseToastOptions = {},
46
- ) {
38
+ type: ToastType,
39
+ options: BaseToastOptions = {},
40
+ ): void {
47
41
  const id = nanoid();
48
-
49
42
  if (typeof content === 'string') {
50
43
  sonner(
51
44
  <ToastConfigProvider id={id} type={type}>
@@ -79,3 +72,30 @@ export function show(
79
72
  );
80
73
  }
81
74
  }
75
+
76
+ /**
77
+ * Show a toast notification. Identical API to the native variant — see
78
+ * `./index.tsx` for the full usage docs.
79
+ */
80
+ export interface ToastFn {
81
+ (content: React.ReactNode, options?: BaseToastOptions): void;
82
+ success: (content: React.ReactNode, options?: Omit<BaseToastOptions, 'type'>) => void;
83
+ error: (content: React.ReactNode, options?: Omit<BaseToastOptions, 'type'>) => void;
84
+ warning: (content: React.ReactNode, options?: Omit<BaseToastOptions, 'type'>) => void;
85
+ info: (content: React.ReactNode, options?: Omit<BaseToastOptions, 'type'>) => void;
86
+ dismiss: (id?: string | number) => void;
87
+ }
88
+
89
+ const toastImpl = ((content: React.ReactNode, options: BaseToastOptions = {}) => {
90
+ dispatch(content, options.type ?? 'default', options);
91
+ }) as ToastFn;
92
+
93
+ toastImpl.success = (content, options) => dispatch(content, 'success', options ?? {});
94
+ toastImpl.error = (content, options) => dispatch(content, 'error', options ?? {});
95
+ toastImpl.warning = (content, options) => dispatch(content, 'warning', options ?? {});
96
+ toastImpl.info = (content, options) => dispatch(content, 'info', options ?? {});
97
+ toastImpl.dismiss = (id) => sonner.dismiss(id);
98
+
99
+ export const toast: ToastFn = toastImpl;
100
+ export const show: ToastFn = toastImpl;
101
+ export type Toast = ToastFn;