@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.
- package/README.md +133 -90
- package/lib/commonjs/bottom-sheet/index.js +341 -98
- package/lib/commonjs/bottom-sheet/index.js.map +1 -1
- package/lib/commonjs/context-menu/index.js +18 -19
- package/lib/commonjs/context-menu/index.js.map +1 -1
- package/lib/commonjs/dialog/BloomDialogProvider.js +61 -0
- package/lib/commonjs/dialog/BloomDialogProvider.js.map +1 -0
- package/lib/commonjs/dialog/BloomDialogProvider.web.js +45 -0
- package/lib/commonjs/dialog/BloomDialogProvider.web.js.map +1 -0
- package/lib/commonjs/dialog/Dialog.js +197 -100
- package/lib/commonjs/dialog/Dialog.js.map +1 -1
- package/lib/commonjs/dialog/Dialog.web.js +194 -84
- package/lib/commonjs/dialog/Dialog.web.js.map +1 -1
- package/lib/commonjs/dialog/SheetShell.js +149 -0
- package/lib/commonjs/dialog/SheetShell.js.map +1 -0
- package/lib/commonjs/dialog/alert-store.js +116 -0
- package/lib/commonjs/dialog/alert-store.js.map +1 -0
- package/lib/commonjs/dialog/alert.js +38 -0
- package/lib/commonjs/dialog/alert.js.map +1 -0
- package/lib/commonjs/dialog/context.js +10 -2
- package/lib/commonjs/dialog/context.js.map +1 -1
- package/lib/commonjs/dialog/index.js +8 -24
- package/lib/commonjs/dialog/index.js.map +1 -1
- package/lib/commonjs/dialog/index.web.js +10 -20
- package/lib/commonjs/dialog/index.web.js.map +1 -1
- package/lib/commonjs/index.js +101 -66
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.web.js +101 -66
- package/lib/commonjs/index.web.js.map +1 -1
- package/lib/commonjs/menu/index.js +21 -23
- package/lib/commonjs/menu/index.js.map +1 -1
- package/lib/commonjs/select/index.js +26 -27
- package/lib/commonjs/select/index.js.map +1 -1
- package/lib/commonjs/toast/index.js +42 -13
- package/lib/commonjs/toast/index.js.map +1 -1
- package/lib/commonjs/toast/index.web.js +19 -15
- package/lib/commonjs/toast/index.web.js.map +1 -1
- package/lib/module/bottom-sheet/index.js +341 -98
- package/lib/module/bottom-sheet/index.js.map +1 -1
- package/lib/module/context-menu/index.js +15 -16
- package/lib/module/context-menu/index.js.map +1 -1
- package/lib/module/dialog/BloomDialogProvider.js +57 -0
- package/lib/module/dialog/BloomDialogProvider.js.map +1 -0
- package/lib/module/dialog/BloomDialogProvider.web.js +41 -0
- package/lib/module/dialog/BloomDialogProvider.web.js.map +1 -0
- package/lib/module/dialog/Dialog.js +199 -87
- package/lib/module/dialog/Dialog.js.map +1 -1
- package/lib/module/dialog/Dialog.web.js +195 -70
- package/lib/module/dialog/Dialog.web.js.map +1 -1
- package/lib/module/dialog/SheetShell.js +143 -0
- package/lib/module/dialog/SheetShell.js.map +1 -0
- package/lib/module/dialog/alert-store.js +107 -0
- package/lib/module/dialog/alert-store.js.map +1 -0
- package/lib/module/dialog/alert.js +35 -0
- package/lib/module/dialog/alert.js.map +1 -0
- package/lib/module/dialog/context.js +10 -2
- package/lib/module/dialog/context.js.map +1 -1
- package/lib/module/dialog/index.js +3 -1
- package/lib/module/dialog/index.js.map +1 -1
- package/lib/module/dialog/index.web.js +9 -7
- package/lib/module/dialog/index.web.js.map +1 -1
- package/lib/module/index.js +2 -3
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js +2 -3
- package/lib/module/index.web.js.map +1 -1
- package/lib/module/menu/index.js +11 -13
- package/lib/module/menu/index.js.map +1 -1
- package/lib/module/select/index.js +27 -28
- package/lib/module/select/index.js.map +1 -1
- package/lib/module/toast/index.js +41 -11
- package/lib/module/toast/index.js.map +1 -1
- package/lib/module/toast/index.web.js +18 -13
- package/lib/module/toast/index.web.js.map +1 -1
- package/lib/typescript/commonjs/__tests__/Dialog.test.d.ts +2 -0
- package/lib/typescript/commonjs/__tests__/Dialog.test.d.ts.map +1 -0
- package/lib/typescript/commonjs/bottom-sheet/index.d.ts +47 -1
- package/lib/typescript/commonjs/bottom-sheet/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/context-menu/index.d.ts +4 -3
- package/lib/typescript/commonjs/context-menu/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/dialog/BloomDialogProvider.d.ts +27 -0
- package/lib/typescript/commonjs/dialog/BloomDialogProvider.d.ts.map +1 -0
- package/lib/typescript/commonjs/dialog/BloomDialogProvider.web.d.ts +15 -0
- package/lib/typescript/commonjs/dialog/BloomDialogProvider.web.d.ts.map +1 -0
- package/lib/typescript/commonjs/dialog/Dialog.d.ts +37 -10
- package/lib/typescript/commonjs/dialog/Dialog.d.ts.map +1 -1
- package/lib/typescript/commonjs/dialog/Dialog.web.d.ts +26 -10
- package/lib/typescript/commonjs/dialog/Dialog.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/dialog/SheetShell.d.ts +31 -0
- package/lib/typescript/commonjs/dialog/SheetShell.d.ts.map +1 -0
- package/lib/typescript/commonjs/dialog/alert-store.d.ts +70 -0
- package/lib/typescript/commonjs/dialog/alert-store.d.ts.map +1 -0
- package/lib/typescript/commonjs/dialog/alert.d.ts +27 -0
- package/lib/typescript/commonjs/dialog/alert.d.ts.map +1 -0
- package/lib/typescript/commonjs/dialog/context.d.ts +7 -0
- package/lib/typescript/commonjs/dialog/context.d.ts.map +1 -1
- package/lib/typescript/commonjs/dialog/index.d.ts +5 -2
- package/lib/typescript/commonjs/dialog/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/dialog/index.web.d.ts +5 -2
- package/lib/typescript/commonjs/dialog/index.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/dialog/types.d.ts +70 -15
- package/lib/typescript/commonjs/dialog/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +3 -3
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.web.d.ts +3 -3
- package/lib/typescript/commonjs/index.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/menu/index.d.ts +4 -4
- package/lib/typescript/commonjs/menu/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/select/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/toast/index.d.ts +32 -3
- package/lib/typescript/commonjs/toast/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/toast/index.web.d.ts +14 -7
- package/lib/typescript/commonjs/toast/index.web.d.ts.map +1 -1
- package/lib/typescript/module/__tests__/Dialog.test.d.ts +2 -0
- package/lib/typescript/module/__tests__/Dialog.test.d.ts.map +1 -0
- package/lib/typescript/module/bottom-sheet/index.d.ts +47 -1
- package/lib/typescript/module/bottom-sheet/index.d.ts.map +1 -1
- package/lib/typescript/module/context-menu/index.d.ts +4 -3
- package/lib/typescript/module/context-menu/index.d.ts.map +1 -1
- package/lib/typescript/module/dialog/BloomDialogProvider.d.ts +27 -0
- package/lib/typescript/module/dialog/BloomDialogProvider.d.ts.map +1 -0
- package/lib/typescript/module/dialog/BloomDialogProvider.web.d.ts +15 -0
- package/lib/typescript/module/dialog/BloomDialogProvider.web.d.ts.map +1 -0
- package/lib/typescript/module/dialog/Dialog.d.ts +37 -10
- package/lib/typescript/module/dialog/Dialog.d.ts.map +1 -1
- package/lib/typescript/module/dialog/Dialog.web.d.ts +26 -10
- package/lib/typescript/module/dialog/Dialog.web.d.ts.map +1 -1
- package/lib/typescript/module/dialog/SheetShell.d.ts +31 -0
- package/lib/typescript/module/dialog/SheetShell.d.ts.map +1 -0
- package/lib/typescript/module/dialog/alert-store.d.ts +70 -0
- package/lib/typescript/module/dialog/alert-store.d.ts.map +1 -0
- package/lib/typescript/module/dialog/alert.d.ts +27 -0
- package/lib/typescript/module/dialog/alert.d.ts.map +1 -0
- package/lib/typescript/module/dialog/context.d.ts +7 -0
- package/lib/typescript/module/dialog/context.d.ts.map +1 -1
- package/lib/typescript/module/dialog/index.d.ts +5 -2
- package/lib/typescript/module/dialog/index.d.ts.map +1 -1
- package/lib/typescript/module/dialog/index.web.d.ts +5 -2
- package/lib/typescript/module/dialog/index.web.d.ts.map +1 -1
- package/lib/typescript/module/dialog/types.d.ts +70 -15
- package/lib/typescript/module/dialog/types.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +3 -3
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/index.web.d.ts +3 -3
- package/lib/typescript/module/index.web.d.ts.map +1 -1
- package/lib/typescript/module/menu/index.d.ts +4 -4
- package/lib/typescript/module/menu/index.d.ts.map +1 -1
- package/lib/typescript/module/select/index.d.ts.map +1 -1
- package/lib/typescript/module/toast/index.d.ts +32 -3
- package/lib/typescript/module/toast/index.d.ts.map +1 -1
- package/lib/typescript/module/toast/index.web.d.ts +14 -7
- package/lib/typescript/module/toast/index.web.d.ts.map +1 -1
- package/package.json +3 -14
- package/src/__tests__/BottomSheet.test.tsx +149 -2
- package/src/__tests__/Dialog.test.tsx +177 -0
- package/src/bottom-sheet/index.tsx +367 -83
- package/src/context-menu/index.tsx +12 -12
- package/src/dialog/BloomDialogProvider.tsx +61 -0
- package/src/dialog/BloomDialogProvider.web.tsx +46 -0
- package/src/dialog/Dialog.tsx +217 -64
- package/src/dialog/Dialog.web.tsx +240 -75
- package/src/dialog/SheetShell.tsx +154 -0
- package/src/dialog/alert-store.ts +126 -0
- package/src/dialog/alert.ts +42 -0
- package/src/dialog/context.ts +14 -3
- package/src/dialog/index.ts +14 -2
- package/src/dialog/index.web.ts +20 -8
- package/src/dialog/types.ts +73 -16
- package/src/index.ts +17 -3
- package/src/index.web.ts +17 -3
- package/src/menu/index.tsx +13 -17
- package/src/select/index.tsx +30 -30
- package/src/toast/index.tsx +55 -11
- package/src/toast/index.web.tsx +33 -13
- package/lib/commonjs/prompt/Prompt.js +0 -267
- package/lib/commonjs/prompt/Prompt.js.map +0 -1
- package/lib/commonjs/prompt/index.js +0 -61
- package/lib/commonjs/prompt/index.js.map +0 -1
- package/lib/module/prompt/Prompt.js +0 -250
- package/lib/module/prompt/Prompt.js.map +0 -1
- package/lib/module/prompt/index.js +0 -4
- package/lib/module/prompt/index.js.map +0 -1
- package/lib/typescript/commonjs/prompt/Prompt.d.ts +0 -42
- package/lib/typescript/commonjs/prompt/Prompt.d.ts.map +0 -1
- package/lib/typescript/commonjs/prompt/index.d.ts +0 -3
- package/lib/typescript/commonjs/prompt/index.d.ts.map +0 -1
- package/lib/typescript/module/prompt/Prompt.d.ts +0 -42
- package/lib/typescript/module/prompt/Prompt.d.ts.map +0 -1
- package/lib/typescript/module/prompt/index.d.ts +0 -3
- package/lib/typescript/module/prompt/index.d.ts.map +0 -1
- package/src/prompt/Prompt.tsx +0 -247
- 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';
|
package/src/dialog/context.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { createContext, useContext, useId, useMemo, useRef } from 'react';
|
|
2
|
-
import type {
|
|
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: (
|
|
26
|
-
control.current?.open(
|
|
36
|
+
open: () => {
|
|
37
|
+
control.current?.open();
|
|
27
38
|
},
|
|
28
39
|
close: (cb) => {
|
|
29
40
|
control.current?.close(cb);
|
package/src/dialog/index.ts
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
-
export {
|
|
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 {
|
|
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';
|
package/src/dialog/index.web.ts
CHANGED
|
@@ -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
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
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 {
|
|
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 {
|
|
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';
|
package/src/dialog/types.ts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
|
-
import type {
|
|
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: (
|
|
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
|
-
|
|
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
|
-
|
|
23
|
-
|
|
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
|
-
*
|
|
27
|
-
*
|
|
28
|
-
|
|
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
|
|
22
|
-
|
|
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
|
|
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
|
|
27
|
-
|
|
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
|
|
53
|
+
export { toast, type Toast } from './toast/index.web';
|
|
40
54
|
|
|
41
55
|
// Typography
|
|
42
56
|
export * as Typography from './typography';
|
package/src/menu/index.tsx
CHANGED
|
@@ -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
|
|
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?:
|
|
33
|
+
control?: DialogControlProps;
|
|
32
34
|
}>) {
|
|
33
|
-
const defaultControl =
|
|
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
|
-
<
|
|
87
|
-
control={context.control}
|
|
88
|
-
preventExpansion
|
|
89
|
-
>
|
|
90
|
-
<Dialog.Handle />
|
|
88
|
+
<SheetShell control={context.control} label="Menu">
|
|
91
89
|
<MenuContext.Provider value={context}>
|
|
92
|
-
<
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
</View>
|
|
97
|
-
</Dialog.ScrollableInner>
|
|
90
|
+
<View style={styles.outerContent}>
|
|
91
|
+
{children}
|
|
92
|
+
{showCancel && <Cancel />}
|
|
93
|
+
</View>
|
|
98
94
|
</MenuContext.Provider>
|
|
99
|
-
</
|
|
95
|
+
</SheetShell>
|
|
100
96
|
);
|
|
101
97
|
}
|
|
102
98
|
|
package/src/select/index.tsx
CHANGED
|
@@ -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
|
|
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:
|
|
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 =
|
|
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
|
-
<
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
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:
|
|
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
|
-
<
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
<
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
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
|
-
</
|
|
256
|
-
</
|
|
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 } =
|
|
270
|
+
const { close } = useDialogContext();
|
|
271
271
|
const { value: selectedValue, onValueChange } = useSelectContext();
|
|
272
272
|
const { state: focused, onIn: onFocus, onOut: onBlur } = useInteractionState();
|
|
273
273
|
const {
|
package/src/toast/index.tsx
CHANGED
|
@@ -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
|
-
*
|
|
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
|
-
|
|
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,
|
package/src/toast/index.web.tsx
CHANGED
|
@@ -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
|
-
|
|
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;
|