@oxyhq/bloom 0.16.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 (39) hide show
  1. package/lib/commonjs/dialog/Dialog.js +38 -150
  2. package/lib/commonjs/dialog/Dialog.js.map +1 -1
  3. package/lib/commonjs/dialog/Dialog.web.js +55 -193
  4. package/lib/commonjs/dialog/Dialog.web.js.map +1 -1
  5. package/lib/commonjs/dialog/DialogBottomSheet.js +205 -0
  6. package/lib/commonjs/dialog/DialogBottomSheet.js.map +1 -0
  7. package/lib/commonjs/dialog/DialogContent.js +155 -0
  8. package/lib/commonjs/dialog/DialogContent.js.map +1 -0
  9. package/lib/module/dialog/Dialog.js +41 -153
  10. package/lib/module/dialog/Dialog.js.map +1 -1
  11. package/lib/module/dialog/Dialog.web.js +57 -195
  12. package/lib/module/dialog/Dialog.web.js.map +1 -1
  13. package/lib/module/dialog/DialogBottomSheet.js +200 -0
  14. package/lib/module/dialog/DialogBottomSheet.js.map +1 -0
  15. package/lib/module/dialog/DialogContent.js +148 -0
  16. package/lib/module/dialog/DialogContent.js.map +1 -0
  17. package/lib/typescript/commonjs/dialog/Dialog.d.ts +1 -1
  18. package/lib/typescript/commonjs/dialog/Dialog.d.ts.map +1 -1
  19. package/lib/typescript/commonjs/dialog/Dialog.web.d.ts +11 -8
  20. package/lib/typescript/commonjs/dialog/Dialog.web.d.ts.map +1 -1
  21. package/lib/typescript/commonjs/dialog/DialogBottomSheet.d.ts +29 -0
  22. package/lib/typescript/commonjs/dialog/DialogBottomSheet.d.ts.map +1 -0
  23. package/lib/typescript/commonjs/dialog/DialogContent.d.ts +32 -0
  24. package/lib/typescript/commonjs/dialog/DialogContent.d.ts.map +1 -0
  25. package/lib/typescript/module/dialog/Dialog.d.ts +1 -1
  26. package/lib/typescript/module/dialog/Dialog.d.ts.map +1 -1
  27. package/lib/typescript/module/dialog/Dialog.web.d.ts +11 -8
  28. package/lib/typescript/module/dialog/Dialog.web.d.ts.map +1 -1
  29. package/lib/typescript/module/dialog/DialogBottomSheet.d.ts +29 -0
  30. package/lib/typescript/module/dialog/DialogBottomSheet.d.ts.map +1 -0
  31. package/lib/typescript/module/dialog/DialogContent.d.ts +32 -0
  32. package/lib/typescript/module/dialog/DialogContent.d.ts.map +1 -0
  33. package/package.json +1 -1
  34. package/src/__tests__/BottomSheetGesture.test.tsx +135 -0
  35. package/src/__tests__/DialogBottomSheet.test.tsx +130 -0
  36. package/src/dialog/Dialog.tsx +34 -166
  37. package/src/dialog/Dialog.web.tsx +46 -206
  38. package/src/dialog/DialogBottomSheet.tsx +235 -0
  39. package/src/dialog/DialogContent.tsx +157 -0
@@ -0,0 +1,157 @@
1
+ import React, { useCallback } from 'react';
2
+ import {
3
+ Text,
4
+ TouchableOpacity,
5
+ View,
6
+ type GestureResponderEvent,
7
+ } from 'react-native';
8
+
9
+ import type { ThemeColors } from '../theme/types';
10
+ import { useTheme } from '../theme/use-theme';
11
+ import { useDialogContext } from './context';
12
+ import type { DialogAction, DialogActionColor } from './types';
13
+
14
+ /**
15
+ * Shared dialog content primitives used by every `<Dialog>` placement on both
16
+ * platforms — the centered panel, the side-sheets, and the `BottomSheet`-backed
17
+ * bottom placement. Keeping them here is the single source of truth for the
18
+ * declarative `title` / `description` / `actions` chrome, so the surfaces never
19
+ * drift in spacing, typography, or action-button behaviour.
20
+ */
21
+
22
+ /**
23
+ * Renders the dialog's body: optional declarative title + description, any
24
+ * `children`, then the action row. The `titleId`/`descriptionId` are wired by
25
+ * the caller onto the dialog role element for `aria-labelledby` /
26
+ * `aria-describedby`.
27
+ */
28
+ export function DialogBody({
29
+ titleId,
30
+ descriptionId,
31
+ title,
32
+ description,
33
+ actions,
34
+ children,
35
+ }: {
36
+ titleId: string;
37
+ descriptionId: string;
38
+ title?: string;
39
+ description?: string;
40
+ actions?: DialogAction[];
41
+ children?: React.ReactNode;
42
+ }) {
43
+ const theme = useTheme();
44
+ return (
45
+ <>
46
+ {title ? (
47
+ <Text
48
+ nativeID={titleId}
49
+ style={{
50
+ fontSize: 22,
51
+ fontWeight: '600',
52
+ color: theme.colors.text,
53
+ paddingBottom: description ? 4 : 16,
54
+ lineHeight: 30,
55
+ }}
56
+ >
57
+ {title}
58
+ </Text>
59
+ ) : null}
60
+ {description ? (
61
+ <Text
62
+ nativeID={descriptionId}
63
+ style={{
64
+ fontSize: 16,
65
+ color: theme.colors.textSecondary,
66
+ paddingBottom: 16,
67
+ lineHeight: 22,
68
+ }}
69
+ >
70
+ {description}
71
+ </Text>
72
+ ) : null}
73
+ {children}
74
+ {actions && actions.length > 0 ? <ActionRow actions={actions} /> : null}
75
+ </>
76
+ );
77
+ }
78
+
79
+ export function ActionRow({ actions }: { actions: DialogAction[] }) {
80
+ return (
81
+ <View style={{ width: '100%', gap: 8, justifyContent: 'flex-end' }}>
82
+ {actions.map((action, idx) => (
83
+ <ActionButton key={`${action.label}-${idx}`} action={action} />
84
+ ))}
85
+ </View>
86
+ );
87
+ }
88
+
89
+ function ActionButton({ action }: { action: DialogAction }) {
90
+ const { close } = useDialogContext();
91
+ const theme = useTheme();
92
+ const color: DialogActionColor = action.color ?? 'default';
93
+ const shouldCloseOnPress = action.shouldCloseOnPress ?? true;
94
+
95
+ const { background, foreground } = getActionPalette(color, theme.colors);
96
+
97
+ const handlePress = useCallback(
98
+ (e: GestureResponderEvent) => {
99
+ const onPress = action.onPress;
100
+ if (color === 'cancel') {
101
+ // Cancel always dismisses; consumer's onPress (rare) runs after.
102
+ close(onPress ? () => onPress(e) : undefined);
103
+ return;
104
+ }
105
+ if (shouldCloseOnPress) {
106
+ close(onPress ? () => onPress(e) : undefined);
107
+ } else {
108
+ onPress?.(e);
109
+ }
110
+ },
111
+ [action.onPress, close, color, shouldCloseOnPress],
112
+ );
113
+
114
+ return (
115
+ <TouchableOpacity
116
+ style={{
117
+ borderRadius: 9999,
118
+ alignItems: 'center',
119
+ justifyContent: 'center',
120
+ backgroundColor: background,
121
+ opacity: action.disabled ? 0.5 : 1,
122
+ paddingVertical: 12,
123
+ paddingHorizontal: 24,
124
+ }}
125
+ onPress={handlePress}
126
+ disabled={action.disabled}
127
+ activeOpacity={0.7}
128
+ testID={action.testID}
129
+ >
130
+ <Text style={{ fontSize: 16, fontWeight: '500', color: foreground }}>
131
+ {action.label}
132
+ </Text>
133
+ </TouchableOpacity>
134
+ );
135
+ }
136
+
137
+ export function getActionPalette(
138
+ color: DialogActionColor,
139
+ colors: ThemeColors,
140
+ ): { background: string; foreground: string } {
141
+ switch (color) {
142
+ case 'destructive':
143
+ return {
144
+ background: colors.negative,
145
+ foreground: colors.negativeForeground,
146
+ };
147
+ case 'cancel':
148
+ return { background: colors.contrast50, foreground: colors.text };
149
+ case 'default':
150
+ return { background: colors.primary, foreground: colors.primaryForeground };
151
+ /* c8 ignore next 3 -- TS exhaustiveness check guards this branch */
152
+ default: {
153
+ const _exhaustive: never = color;
154
+ return { background: colors.primary, foreground: colors.primaryForeground };
155
+ }
156
+ }
157
+ }