@oxyhq/bloom 0.14.0 → 0.15.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 (144) hide show
  1. package/lib/commonjs/dialog/CenteredDialog.js +2 -0
  2. package/lib/commonjs/dialog/CenteredDialog.js.map +1 -1
  3. package/lib/commonjs/dialog/CenteredDialog.web.js +2 -0
  4. package/lib/commonjs/dialog/CenteredDialog.web.js.map +1 -1
  5. package/lib/commonjs/dialog/Dialog.js +337 -43
  6. package/lib/commonjs/dialog/Dialog.js.map +1 -1
  7. package/lib/commonjs/dialog/Dialog.web.js +414 -63
  8. package/lib/commonjs/dialog/Dialog.web.js.map +1 -1
  9. package/lib/commonjs/dialog/index.js +6 -0
  10. package/lib/commonjs/dialog/index.js.map +1 -1
  11. package/lib/commonjs/dialog/index.web.js +6 -0
  12. package/lib/commonjs/dialog/index.web.js.map +1 -1
  13. package/lib/commonjs/dialog/placement.js +104 -0
  14. package/lib/commonjs/dialog/placement.js.map +1 -0
  15. package/lib/commonjs/index.js +7 -0
  16. package/lib/commonjs/index.js.map +1 -1
  17. package/lib/commonjs/index.web.js +7 -0
  18. package/lib/commonjs/index.web.js.map +1 -1
  19. package/lib/commonjs/responsive-sheet/ResponsiveSheet.js +63 -266
  20. package/lib/commonjs/responsive-sheet/ResponsiveSheet.js.map +1 -1
  21. package/lib/commonjs/responsive-sheet/ResponsiveSheet.web.js +84 -0
  22. package/lib/commonjs/responsive-sheet/ResponsiveSheet.web.js.map +1 -0
  23. package/lib/commonjs/responsive-sheet/index.web.js +3 -3
  24. package/lib/commonjs/responsive-sheet/index.web.js.map +1 -1
  25. package/lib/module/dialog/CenteredDialog.js +2 -0
  26. package/lib/module/dialog/CenteredDialog.js.map +1 -1
  27. package/lib/module/dialog/CenteredDialog.web.js +2 -0
  28. package/lib/module/dialog/CenteredDialog.web.js.map +1 -1
  29. package/lib/module/dialog/Dialog.js +336 -46
  30. package/lib/module/dialog/Dialog.js.map +1 -1
  31. package/lib/module/dialog/Dialog.web.js +412 -65
  32. package/lib/module/dialog/Dialog.web.js.map +1 -1
  33. package/lib/module/dialog/index.js +1 -1
  34. package/lib/module/dialog/index.js.map +1 -1
  35. package/lib/module/dialog/index.web.js +1 -1
  36. package/lib/module/dialog/index.web.js.map +1 -1
  37. package/lib/module/dialog/placement.js +100 -0
  38. package/lib/module/dialog/placement.js.map +1 -0
  39. package/lib/module/index.js +1 -1
  40. package/lib/module/index.js.map +1 -1
  41. package/lib/module/index.web.js +1 -1
  42. package/lib/module/index.web.js.map +1 -1
  43. package/lib/module/responsive-sheet/ResponsiveSheet.js +63 -266
  44. package/lib/module/responsive-sheet/ResponsiveSheet.js.map +1 -1
  45. package/lib/module/responsive-sheet/ResponsiveSheet.web.js +77 -0
  46. package/lib/module/responsive-sheet/ResponsiveSheet.web.js.map +1 -0
  47. package/lib/module/responsive-sheet/index.web.js +7 -9
  48. package/lib/module/responsive-sheet/index.web.js.map +1 -1
  49. package/lib/typescript/commonjs/dialog/CenteredDialog.d.ts +2 -0
  50. package/lib/typescript/commonjs/dialog/CenteredDialog.d.ts.map +1 -1
  51. package/lib/typescript/commonjs/dialog/CenteredDialog.web.d.ts +2 -0
  52. package/lib/typescript/commonjs/dialog/CenteredDialog.web.d.ts.map +1 -1
  53. package/lib/typescript/commonjs/dialog/Dialog.d.ts +18 -15
  54. package/lib/typescript/commonjs/dialog/Dialog.d.ts.map +1 -1
  55. package/lib/typescript/commonjs/dialog/Dialog.web.d.ts +18 -5
  56. package/lib/typescript/commonjs/dialog/Dialog.web.d.ts.map +1 -1
  57. package/lib/typescript/commonjs/dialog/centered-dialog-types.d.ts +4 -0
  58. package/lib/typescript/commonjs/dialog/centered-dialog-types.d.ts.map +1 -1
  59. package/lib/typescript/commonjs/dialog/index.d.ts +2 -2
  60. package/lib/typescript/commonjs/dialog/index.d.ts.map +1 -1
  61. package/lib/typescript/commonjs/dialog/index.web.d.ts +2 -2
  62. package/lib/typescript/commonjs/dialog/index.web.d.ts.map +1 -1
  63. package/lib/typescript/commonjs/dialog/placement.d.ts +71 -0
  64. package/lib/typescript/commonjs/dialog/placement.d.ts.map +1 -0
  65. package/lib/typescript/commonjs/dialog/types.d.ts +66 -3
  66. package/lib/typescript/commonjs/dialog/types.d.ts.map +1 -1
  67. package/lib/typescript/commonjs/index.d.ts +2 -2
  68. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  69. package/lib/typescript/commonjs/index.web.d.ts +2 -2
  70. package/lib/typescript/commonjs/index.web.d.ts.map +1 -1
  71. package/lib/typescript/commonjs/responsive-sheet/ResponsiveSheet.d.ts +15 -19
  72. package/lib/typescript/commonjs/responsive-sheet/ResponsiveSheet.d.ts.map +1 -1
  73. package/lib/typescript/commonjs/responsive-sheet/ResponsiveSheet.web.d.ts +16 -0
  74. package/lib/typescript/commonjs/responsive-sheet/ResponsiveSheet.web.d.ts.map +1 -0
  75. package/lib/typescript/commonjs/responsive-sheet/index.web.d.ts +1 -1
  76. package/lib/typescript/commonjs/responsive-sheet/index.web.d.ts.map +1 -1
  77. package/lib/typescript/commonjs/responsive-sheet/types.d.ts +5 -2
  78. package/lib/typescript/commonjs/responsive-sheet/types.d.ts.map +1 -1
  79. package/lib/typescript/module/dialog/CenteredDialog.d.ts +2 -0
  80. package/lib/typescript/module/dialog/CenteredDialog.d.ts.map +1 -1
  81. package/lib/typescript/module/dialog/CenteredDialog.web.d.ts +2 -0
  82. package/lib/typescript/module/dialog/CenteredDialog.web.d.ts.map +1 -1
  83. package/lib/typescript/module/dialog/Dialog.d.ts +18 -15
  84. package/lib/typescript/module/dialog/Dialog.d.ts.map +1 -1
  85. package/lib/typescript/module/dialog/Dialog.web.d.ts +18 -5
  86. package/lib/typescript/module/dialog/Dialog.web.d.ts.map +1 -1
  87. package/lib/typescript/module/dialog/centered-dialog-types.d.ts +4 -0
  88. package/lib/typescript/module/dialog/centered-dialog-types.d.ts.map +1 -1
  89. package/lib/typescript/module/dialog/index.d.ts +2 -2
  90. package/lib/typescript/module/dialog/index.d.ts.map +1 -1
  91. package/lib/typescript/module/dialog/index.web.d.ts +2 -2
  92. package/lib/typescript/module/dialog/index.web.d.ts.map +1 -1
  93. package/lib/typescript/module/dialog/placement.d.ts +71 -0
  94. package/lib/typescript/module/dialog/placement.d.ts.map +1 -0
  95. package/lib/typescript/module/dialog/types.d.ts +66 -3
  96. package/lib/typescript/module/dialog/types.d.ts.map +1 -1
  97. package/lib/typescript/module/index.d.ts +2 -2
  98. package/lib/typescript/module/index.d.ts.map +1 -1
  99. package/lib/typescript/module/index.web.d.ts +2 -2
  100. package/lib/typescript/module/index.web.d.ts.map +1 -1
  101. package/lib/typescript/module/responsive-sheet/ResponsiveSheet.d.ts +15 -19
  102. package/lib/typescript/module/responsive-sheet/ResponsiveSheet.d.ts.map +1 -1
  103. package/lib/typescript/module/responsive-sheet/ResponsiveSheet.web.d.ts +16 -0
  104. package/lib/typescript/module/responsive-sheet/ResponsiveSheet.web.d.ts.map +1 -0
  105. package/lib/typescript/module/responsive-sheet/index.web.d.ts +1 -1
  106. package/lib/typescript/module/responsive-sheet/index.web.d.ts.map +1 -1
  107. package/lib/typescript/module/responsive-sheet/types.d.ts +5 -2
  108. package/lib/typescript/module/responsive-sheet/types.d.ts.map +1 -1
  109. package/package.json +1 -1
  110. package/src/__tests__/DialogPlacement.test.tsx +144 -0
  111. package/src/__tests__/ResponsiveSheet.test.tsx +36 -52
  112. package/src/dialog/CenteredDialog.tsx +2 -0
  113. package/src/dialog/CenteredDialog.web.tsx +2 -0
  114. package/src/dialog/Dialog.tsx +407 -50
  115. package/src/dialog/Dialog.web.tsx +490 -75
  116. package/src/dialog/centered-dialog-types.ts +4 -0
  117. package/src/dialog/index.ts +4 -1
  118. package/src/dialog/index.web.ts +4 -1
  119. package/src/dialog/placement.ts +113 -0
  120. package/src/dialog/types.ts +69 -3
  121. package/src/index.ts +4 -0
  122. package/src/index.web.ts +4 -0
  123. package/src/responsive-sheet/ResponsiveSheet.tsx +58 -297
  124. package/src/responsive-sheet/ResponsiveSheet.web.tsx +76 -0
  125. package/src/responsive-sheet/index.web.ts +7 -9
  126. package/src/responsive-sheet/types.ts +5 -2
  127. package/lib/commonjs/responsive-sheet/ResponsiveSheet.native.js +0 -226
  128. package/lib/commonjs/responsive-sheet/ResponsiveSheet.native.js.map +0 -1
  129. package/lib/commonjs/responsive-sheet/const.js +0 -60
  130. package/lib/commonjs/responsive-sheet/const.js.map +0 -1
  131. package/lib/module/responsive-sheet/ResponsiveSheet.native.js +0 -219
  132. package/lib/module/responsive-sheet/ResponsiveSheet.native.js.map +0 -1
  133. package/lib/module/responsive-sheet/const.js +0 -56
  134. package/lib/module/responsive-sheet/const.js.map +0 -1
  135. package/lib/typescript/commonjs/responsive-sheet/ResponsiveSheet.native.d.ts +0 -20
  136. package/lib/typescript/commonjs/responsive-sheet/ResponsiveSheet.native.d.ts.map +0 -1
  137. package/lib/typescript/commonjs/responsive-sheet/const.d.ts +0 -43
  138. package/lib/typescript/commonjs/responsive-sheet/const.d.ts.map +0 -1
  139. package/lib/typescript/module/responsive-sheet/ResponsiveSheet.native.d.ts +0 -20
  140. package/lib/typescript/module/responsive-sheet/ResponsiveSheet.native.d.ts.map +0 -1
  141. package/lib/typescript/module/responsive-sheet/const.d.ts +0 -43
  142. package/lib/typescript/module/responsive-sheet/const.d.ts.map +0 -1
  143. package/src/responsive-sheet/ResponsiveSheet.native.tsx +0 -257
  144. package/src/responsive-sheet/const.ts +0 -53
@@ -1 +1 @@
1
- {"version":3,"file":"index.web.d.ts","sourceRoot":"","sources":["../../../../src/responsive-sheet/index.web.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,eAAe,EAAE,gCAAgC,EAAE,MAAM,mBAAmB,CAAC;AACtF,YAAY,EACV,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.web.d.ts","sourceRoot":"","sources":["../../../../src/responsive-sheet/index.web.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,eAAe,EAAE,gCAAgC,EAAE,MAAM,uBAAuB,CAAC;AAC1F,YAAY,EACV,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,SAAS,CAAC"}
@@ -14,11 +14,14 @@ export interface ResponsiveSheetInset {
14
14
  right?: number;
15
15
  }
16
16
  /**
17
+ * @deprecated Use `<Dialog placement={{ base: 'bottom', md: 'left' }}>` from
18
+ * `@oxyhq/bloom/dialog` instead. `ResponsiveSheet` is now a thin wrapper over
19
+ * `<Dialog>` retained for the migration window.
20
+ *
17
21
  * A responsive overlay sheet: an anchored side-sheet on wide screens and a
18
22
  * bottom-sheet (with drag handle) on small screens, switching by viewport
19
23
  * width. It is a plain controlled component — the host drives `open`/`onClose`
20
- * from its own state. It renders in place (no portal) so the host can scope it
21
- * inside a themed/positioned subtree.
24
+ * from its own state.
22
25
  */
23
26
  export interface ResponsiveSheetProps {
24
27
  /** Whether the sheet is open. Controlled by the host. */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/responsive-sheet/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzD,gDAAgD;AAChD,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,OAAO,CAAC;AAEnD;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACnC,yDAAyD;IACzD,IAAI,EAAE,OAAO,CAAC;IACd,4EAA4E;IAC5E,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,yDAAyD;IACzD,IAAI,CAAC,EAAE,mBAAmB,CAAC;IAC3B,8FAA8F;IAC9F,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+EAA+E;IAC/E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uFAAuF;IACvF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oFAAoF;IACpF,KAAK,CAAC,EAAE,oBAAoB,CAAC;IAC7B,kFAAkF;IAClF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,yEAAyE;IACzE,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,+EAA+E;IAC/E,UAAU,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAClC,gDAAgD;IAChD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uEAAuE;IACvE,cAAc,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACtC,4EAA4E;IAC5E,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,+EAA+E;IAC/E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,QAAQ,EAAE,SAAS,CAAC;CACrB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/responsive-sheet/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzD,gDAAgD;AAChD,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,OAAO,CAAC;AAEnD;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,oBAAoB;IACnC,yDAAyD;IACzD,IAAI,EAAE,OAAO,CAAC;IACd,4EAA4E;IAC5E,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,yDAAyD;IACzD,IAAI,CAAC,EAAE,mBAAmB,CAAC;IAC3B,8FAA8F;IAC9F,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+EAA+E;IAC/E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uFAAuF;IACvF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oFAAoF;IACpF,KAAK,CAAC,EAAE,oBAAoB,CAAC;IAC7B,kFAAkF;IAClF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,yEAAyE;IACzE,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,+EAA+E;IAC/E,UAAU,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAClC,gDAAgD;IAChD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uEAAuE;IACvE,cAAc,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACtC,4EAA4E;IAC5E,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,+EAA+E;IAC/E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,QAAQ,EAAE,SAAS,CAAC;CACrB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxyhq/bloom",
3
- "version": "0.14.0",
3
+ "version": "0.15.0",
4
4
  "description": "Bloom UI — Oxy ecosystem component library for React Native + Expo + Web",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
@@ -0,0 +1,144 @@
1
+ import React from 'react';
2
+ import { Text } from 'react-native';
3
+ import { act, fireEvent, render } from '@testing-library/react-native';
4
+
5
+ import { Dialog } from '../dialog';
6
+ import {
7
+ BREAKPOINT_MD,
8
+ useResolvedPlacement,
9
+ type DialogPlacement,
10
+ type ResponsiveDialogPlacement,
11
+ } from '../dialog/placement';
12
+ import { BloomThemeProvider } from '../theme/BloomThemeProvider';
13
+
14
+ // The RN test mock reports a 375px-wide viewport (below every breakpoint), so a
15
+ // responsive `placement` map resolves to its `base`.
16
+ const MOCK_VIEWPORT_WIDTH = 375;
17
+
18
+ function renderWithTheme(ui: React.ReactElement) {
19
+ return render(
20
+ <BloomThemeProvider mode="light" colorPreset="teal">
21
+ {ui}
22
+ </BloomThemeProvider>,
23
+ );
24
+ }
25
+
26
+ /** Capture `useResolvedPlacement`'s output for a given input. */
27
+ function ResolveProbe({
28
+ placement,
29
+ onResolve,
30
+ }: {
31
+ placement: ResponsiveDialogPlacement | undefined;
32
+ onResolve: (p: DialogPlacement) => void;
33
+ }) {
34
+ const resolved = useResolvedPlacement(placement);
35
+ onResolve(resolved);
36
+ return null;
37
+ }
38
+
39
+ function resolve(placement: ResponsiveDialogPlacement | undefined): DialogPlacement {
40
+ let captured: DialogPlacement = 'center';
41
+ renderWithTheme(
42
+ <ResolveProbe placement={placement} onResolve={(p) => { captured = p; }} />,
43
+ );
44
+ return captured;
45
+ }
46
+
47
+ describe('useResolvedPlacement', () => {
48
+ it('defaults to center when placement is undefined', () => {
49
+ expect(resolve(undefined)).toBe('center');
50
+ });
51
+
52
+ it('returns a plain string placement unchanged', () => {
53
+ expect(resolve('left')).toBe('left');
54
+ expect(resolve('right')).toBe('right');
55
+ expect(resolve('bottom')).toBe('bottom');
56
+ expect(resolve('center')).toBe('center');
57
+ });
58
+
59
+ it('resolves a responsive map to base below the first breakpoint', () => {
60
+ // Sanity: the mock viewport is narrower than md, so md/lg/xl never apply.
61
+ expect(MOCK_VIEWPORT_WIDTH).toBeLessThan(BREAKPOINT_MD);
62
+ expect(resolve({ base: 'bottom', md: 'left' })).toBe('bottom');
63
+ expect(resolve({ base: 'bottom', md: 'center' })).toBe('bottom');
64
+ expect(resolve({ base: 'bottom', sm: 'right', lg: 'center' })).toBe('bottom');
65
+ });
66
+
67
+ it('ignores higher breakpoint keys that exceed the viewport width', () => {
68
+ // Only `base` applies at 375px wide; the `xl` override does not engage.
69
+ expect(resolve({ base: 'right', xl: 'left' })).toBe('right');
70
+ });
71
+ });
72
+
73
+ describe('Dialog controlled open mode', () => {
74
+ it('does not render content while open is false', () => {
75
+ const { queryByText } = renderWithTheme(
76
+ <Dialog open={false} onClose={() => {}} title="Controlled">
77
+ <Text>Controlled body</Text>
78
+ </Dialog>,
79
+ );
80
+ expect(queryByText('Controlled body')).toBeNull();
81
+ });
82
+
83
+ it('renders content when open flips to true (no control needed)', () => {
84
+ const { getByText, rerender } = renderWithTheme(
85
+ <Dialog open={false} onClose={() => {}} title="Controlled">
86
+ <Text>Controlled body</Text>
87
+ </Dialog>,
88
+ );
89
+ rerender(
90
+ <BloomThemeProvider mode="light" colorPreset="teal">
91
+ <Dialog open onClose={() => {}} title="Controlled">
92
+ <Text>Controlled body</Text>
93
+ </Dialog>
94
+ </BloomThemeProvider>,
95
+ );
96
+ expect(getByText('Controlled body')).toBeTruthy();
97
+ expect(getByText('Controlled')).toBeTruthy();
98
+ });
99
+
100
+ it('unmounts after open flips back to false and the close settles', () => {
101
+ jest.useFakeTimers();
102
+ try {
103
+ const { getByText, queryByText, rerender } = renderWithTheme(
104
+ <Dialog open onClose={() => {}} title="Controlled">
105
+ <Text>Controlled body</Text>
106
+ </Dialog>,
107
+ );
108
+ expect(getByText('Controlled body')).toBeTruthy();
109
+
110
+ rerender(
111
+ <BloomThemeProvider mode="light" colorPreset="teal">
112
+ <Dialog open={false} onClose={() => {}} title="Controlled">
113
+ <Text>Controlled body</Text>
114
+ </Dialog>
115
+ </BloomThemeProvider>,
116
+ );
117
+ act(() => {
118
+ jest.advanceTimersByTime(500);
119
+ });
120
+ expect(queryByText('Controlled body')).toBeNull();
121
+ } finally {
122
+ jest.useRealTimers();
123
+ }
124
+ });
125
+
126
+ it('requests close via onClose exactly once when an action is pressed (no double-fire)', () => {
127
+ const onClose = jest.fn();
128
+ const { getByText } = renderWithTheme(
129
+ <Dialog
130
+ open
131
+ onClose={onClose}
132
+ title="Controlled"
133
+ actions={[{ label: 'Done' }]}
134
+ />,
135
+ );
136
+ act(() => {
137
+ fireEvent.press(getByText('Done'));
138
+ });
139
+ // In controlled mode the action's close() requests dismissal via onClose
140
+ // once; the host (not the dialog) then flips `open`. It must not fire the
141
+ // close-completion onClose a second time.
142
+ expect(onClose).toHaveBeenCalledTimes(1);
143
+ });
144
+ });
@@ -1,8 +1,8 @@
1
1
  import React from 'react';
2
2
  import { Text } from 'react-native';
3
- import { act, fireEvent, render } from '@testing-library/react-native';
3
+ import { act, render } from '@testing-library/react-native';
4
4
 
5
- import { ResponsiveSheet, RESPONSIVE_SHEET_BACKDROP_TESTID } from '../responsive-sheet';
5
+ import { ResponsiveSheet } from '../responsive-sheet';
6
6
  import { BloomThemeProvider } from '../theme/BloomThemeProvider';
7
7
 
8
8
  function renderWithTheme(ui: React.ReactElement) {
@@ -13,9 +13,25 @@ function renderWithTheme(ui: React.ReactElement) {
13
13
  );
14
14
  }
15
15
 
16
+ function rerenderWithTheme(
17
+ rerender: ReturnType<typeof render>['rerender'],
18
+ ui: React.ReactElement,
19
+ ) {
20
+ rerender(
21
+ <BloomThemeProvider mode="light" colorPreset="teal">
22
+ {ui}
23
+ </BloomThemeProvider>,
24
+ );
25
+ }
26
+
16
27
  const LABEL = 'Filters sheet';
17
28
 
18
- describe('ResponsiveSheet', () => {
29
+ // `ResponsiveSheet` is now a deprecated thin wrapper over `<Dialog>`. These
30
+ // tests verify the controlled wrapper contract it still owns (open/close
31
+ // presence + delegation). The jest env reports a 375px-wide viewport (below
32
+ // the default `md` breakpoint) so the wrapper resolves to the bottom-sheet
33
+ // placement, which delegates to bloom's `BottomSheet`.
34
+ describe('ResponsiveSheet (deprecated Dialog wrapper)', () => {
19
35
  it('renders children when open', () => {
20
36
  const { getByText } = renderWithTheme(
21
37
  <ResponsiveSheet open onClose={() => {}} label={LABEL}>
@@ -34,45 +50,7 @@ describe('ResponsiveSheet', () => {
34
50
  expect(queryByText('Sheet body')).toBeNull();
35
51
  });
36
52
 
37
- // The backdrop animates its opacity from 0 -> BACKDROP_OPACITY on enter, so
38
- // RNTL treats it as accessibility-hidden during the synchronous first frame.
39
- // `includeHiddenElements` lets us assert its (real, interactive) press
40
- // behavior without depending on the enter transition having committed.
41
- const HIDDEN = { includeHiddenElements: true } as const;
42
-
43
- it('calls onClose when the backdrop is pressed (default dismissOnBackdrop)', () => {
44
- const onClose = jest.fn();
45
- const { getByTestId } = renderWithTheme(
46
- <ResponsiveSheet open onClose={onClose} label={LABEL}>
47
- <Text>Sheet body</Text>
48
- </ResponsiveSheet>,
49
- );
50
- fireEvent.press(getByTestId(RESPONSIVE_SHEET_BACKDROP_TESTID, HIDDEN));
51
- expect(onClose).toHaveBeenCalledTimes(1);
52
- });
53
-
54
- it('does NOT call onClose on backdrop press when dismissOnBackdrop is false', () => {
55
- const onClose = jest.fn();
56
- const { getByTestId } = renderWithTheme(
57
- <ResponsiveSheet open onClose={onClose} label={LABEL} dismissOnBackdrop={false}>
58
- <Text>Sheet body</Text>
59
- </ResponsiveSheet>,
60
- );
61
- fireEvent.press(getByTestId(RESPONSIVE_SHEET_BACKDROP_TESTID, HIDDEN));
62
- expect(onClose).not.toHaveBeenCalled();
63
- });
64
-
65
- it('labels the panel and the dismiss backdrop distinctly', () => {
66
- const { getByLabelText } = renderWithTheme(
67
- <ResponsiveSheet open onClose={() => {}} label={LABEL}>
68
- <Text>Sheet body</Text>
69
- </ResponsiveSheet>,
70
- );
71
- expect(getByLabelText(LABEL, HIDDEN)).toBeTruthy();
72
- expect(getByLabelText(`Dismiss ${LABEL}`, HIDDEN)).toBeTruthy();
73
- });
74
-
75
- it('keeps the panel mounted through the exit transition after closing', () => {
53
+ it('unmounts the body after a controlled close settles', () => {
76
54
  jest.useFakeTimers();
77
55
  try {
78
56
  const { getByText, queryByText, rerender } = renderWithTheme(
@@ -82,23 +60,29 @@ describe('ResponsiveSheet', () => {
82
60
  );
83
61
  expect(getByText('Sheet body')).toBeTruthy();
84
62
 
85
- rerender(
86
- <BloomThemeProvider mode="light" colorPreset="teal">
87
- <ResponsiveSheet open={false} onClose={() => {}} label={LABEL}>
88
- <Text>Sheet body</Text>
89
- </ResponsiveSheet>
90
- </BloomThemeProvider>,
63
+ rerenderWithTheme(
64
+ rerender,
65
+ <ResponsiveSheet open={false} onClose={() => {}} label={LABEL}>
66
+ <Text>Sheet body</Text>
67
+ </ResponsiveSheet>,
91
68
  );
92
- // Still mounted immediately after close (exit transition in flight).
93
- expect(getByText('Sheet body')).toBeTruthy();
94
69
 
95
- // After the transition duration it unmounts.
70
+ // After the close animation/fallback settles the body is gone.
96
71
  act(() => {
97
- jest.advanceTimersByTime(400);
72
+ jest.advanceTimersByTime(500);
98
73
  });
99
74
  expect(queryByText('Sheet body')).toBeNull();
100
75
  } finally {
101
76
  jest.useRealTimers();
102
77
  }
103
78
  });
79
+
80
+ it('forwards a custom label to the dialog surface', () => {
81
+ const { getByLabelText } = renderWithTheme(
82
+ <ResponsiveSheet open onClose={() => {}} label={LABEL}>
83
+ <Text>Sheet body</Text>
84
+ </ResponsiveSheet>,
85
+ );
86
+ expect(getByLabelText(LABEL)).toBeTruthy();
87
+ });
104
88
  });
@@ -26,6 +26,8 @@ const CLOSE_HIT_SLOP = { top: 8, bottom: 8, left: 8, right: 8 } as const;
26
26
  export const CENTERED_DIALOG_BACKDROP_TESTID = 'bloom-centered-dialog-backdrop';
27
27
 
28
28
  /**
29
+ * @deprecated Use `<Dialog placement="center">` instead.
30
+ *
29
31
  * Native variant of `<CenteredDialog>`.
30
32
  *
31
33
  * A controlled, centered modal: a transparent RN `Modal` (fade animation,
@@ -27,6 +27,8 @@ export const CENTERED_DIALOG_BACKDROP_TESTID = 'bloom-centered-dialog-backdrop';
27
27
  const stopPropagation = (e: { stopPropagation: () => void }) => e.stopPropagation();
28
28
 
29
29
  /**
30
+ * @deprecated Use `<Dialog placement="center">` instead.
31
+ *
30
32
  * Web variant of `<CenteredDialog>`.
31
33
  *
32
34
  * A centered modal card rendered into the Bloom Portal at the end of