@wordpress/components 23.7.0 → 23.9.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 (274) hide show
  1. package/CHANGELOG.md +52 -6
  2. package/build/checkbox-control/index.js +2 -2
  3. package/build/checkbox-control/index.js.map +1 -1
  4. package/build/color-palette/index.native.js +12 -0
  5. package/build/color-palette/index.native.js.map +1 -1
  6. package/build/custom-gradient-picker/index.native.js +3 -1
  7. package/build/custom-gradient-picker/index.native.js.map +1 -1
  8. package/build/custom-gradient-picker/serializer.js +0 -4
  9. package/build/custom-gradient-picker/serializer.js.map +1 -1
  10. package/build/draggable/index.js +6 -1
  11. package/build/draggable/index.js.map +1 -1
  12. package/build/drop-zone/index.js +8 -8
  13. package/build/drop-zone/index.js.map +1 -1
  14. package/build/index.js.map +1 -1
  15. package/build/mobile/bottom-sheet/cell.native.js +6 -6
  16. package/build/mobile/bottom-sheet/cell.native.js.map +1 -1
  17. package/build/mobile/color-settings/palette.screen.native.js +0 -8
  18. package/build/mobile/color-settings/palette.screen.native.js.map +1 -1
  19. package/build/mobile/global-styles-context/utils.native.js +21 -4
  20. package/build/mobile/global-styles-context/utils.native.js.map +1 -1
  21. package/build/mobile/keyboard-aware-flat-list/index.android.js +0 -4
  22. package/build/mobile/keyboard-aware-flat-list/index.android.js.map +1 -1
  23. package/build/mobile/keyboard-aware-flat-list/index.ios.js +100 -55
  24. package/build/mobile/keyboard-aware-flat-list/index.ios.js.map +1 -1
  25. package/build/mobile/keyboard-aware-flat-list/use-keyboard-offset.native.js +82 -0
  26. package/build/mobile/keyboard-aware-flat-list/use-keyboard-offset.native.js.map +1 -0
  27. package/build/mobile/keyboard-aware-flat-list/use-scroll-to-text-input.native.js +85 -0
  28. package/build/mobile/keyboard-aware-flat-list/use-scroll-to-text-input.native.js.map +1 -0
  29. package/build/mobile/keyboard-aware-flat-list/use-text-input-caret-position.native.js +44 -0
  30. package/build/mobile/keyboard-aware-flat-list/use-text-input-caret-position.native.js.map +1 -0
  31. package/build/mobile/keyboard-aware-flat-list/use-text-input-offset.native.js +53 -0
  32. package/build/mobile/keyboard-aware-flat-list/use-text-input-offset.native.js.map +1 -0
  33. package/build/mobile/segmented-control/index.native.js +4 -2
  34. package/build/mobile/segmented-control/index.native.js.map +1 -1
  35. package/build/navigator/navigator-provider/component.js +4 -2
  36. package/build/navigator/navigator-provider/component.js.map +1 -1
  37. package/build/navigator/navigator-screen/component.js +4 -3
  38. package/build/navigator/navigator-screen/component.js.map +1 -1
  39. package/build/popover/index.js +1 -8
  40. package/build/popover/index.js.map +1 -1
  41. package/build/private-apis.js +4 -1
  42. package/build/private-apis.js.map +1 -1
  43. package/build/query-controls/author-select.js +2 -1
  44. package/build/query-controls/author-select.js.map +1 -1
  45. package/build/query-controls/category-select.js +3 -1
  46. package/build/query-controls/category-select.js.map +1 -1
  47. package/build/query-controls/index.js +7 -1
  48. package/build/query-controls/index.js.map +1 -1
  49. package/build/sandbox/index.native.js +55 -29
  50. package/build/sandbox/index.native.js.map +1 -1
  51. package/build/slot-fill/index.js +20 -7
  52. package/build/slot-fill/index.js.map +1 -1
  53. package/build/spinner/styles.js +4 -4
  54. package/build/spinner/styles.js.map +1 -1
  55. package/build/tree-grid/index.js +3 -3
  56. package/build/tree-grid/index.js.map +1 -1
  57. package/build/view/component.js +1 -2
  58. package/build/view/component.js.map +1 -1
  59. package/build-module/checkbox-control/index.js +2 -2
  60. package/build-module/checkbox-control/index.js.map +1 -1
  61. package/build-module/color-palette/index.native.js +13 -1
  62. package/build-module/color-palette/index.native.js.map +1 -1
  63. package/build-module/custom-gradient-picker/index.native.js +3 -1
  64. package/build-module/custom-gradient-picker/index.native.js.map +1 -1
  65. package/build-module/custom-gradient-picker/serializer.js +0 -4
  66. package/build-module/custom-gradient-picker/serializer.js.map +1 -1
  67. package/build-module/draggable/index.js +6 -1
  68. package/build-module/draggable/index.js.map +1 -1
  69. package/build-module/drop-zone/index.js +8 -8
  70. package/build-module/drop-zone/index.js.map +1 -1
  71. package/build-module/index.js.map +1 -1
  72. package/build-module/mobile/bottom-sheet/cell.native.js +6 -5
  73. package/build-module/mobile/bottom-sheet/cell.native.js.map +1 -1
  74. package/build-module/mobile/color-settings/palette.screen.native.js +0 -8
  75. package/build-module/mobile/color-settings/palette.screen.native.js.map +1 -1
  76. package/build-module/mobile/global-styles-context/utils.native.js +21 -3
  77. package/build-module/mobile/global-styles-context/utils.native.js.map +1 -1
  78. package/build-module/mobile/keyboard-aware-flat-list/index.android.js +0 -4
  79. package/build-module/mobile/keyboard-aware-flat-list/index.android.js.map +1 -1
  80. package/build-module/mobile/keyboard-aware-flat-list/index.ios.js +97 -54
  81. package/build-module/mobile/keyboard-aware-flat-list/index.ios.js.map +1 -1
  82. package/build-module/mobile/keyboard-aware-flat-list/use-keyboard-offset.native.js +73 -0
  83. package/build-module/mobile/keyboard-aware-flat-list/use-keyboard-offset.native.js.map +1 -0
  84. package/build-module/mobile/keyboard-aware-flat-list/use-scroll-to-text-input.native.js +76 -0
  85. package/build-module/mobile/keyboard-aware-flat-list/use-scroll-to-text-input.native.js.map +1 -0
  86. package/build-module/mobile/keyboard-aware-flat-list/use-text-input-caret-position.native.js +33 -0
  87. package/build-module/mobile/keyboard-aware-flat-list/use-text-input-caret-position.native.js.map +1 -0
  88. package/build-module/mobile/keyboard-aware-flat-list/use-text-input-offset.native.js +40 -0
  89. package/build-module/mobile/keyboard-aware-flat-list/use-text-input-offset.native.js.map +1 -0
  90. package/build-module/mobile/segmented-control/index.native.js +4 -2
  91. package/build-module/mobile/segmented-control/index.native.js.map +1 -1
  92. package/build-module/navigator/navigator-provider/component.js +4 -2
  93. package/build-module/navigator/navigator-provider/component.js.map +1 -1
  94. package/build-module/navigator/navigator-screen/component.js +4 -3
  95. package/build-module/navigator/navigator-screen/component.js.map +1 -1
  96. package/build-module/popover/index.js +1 -8
  97. package/build-module/popover/index.js.map +1 -1
  98. package/build-module/private-apis.js +3 -1
  99. package/build-module/private-apis.js.map +1 -1
  100. package/build-module/query-controls/author-select.js +2 -1
  101. package/build-module/query-controls/author-select.js.map +1 -1
  102. package/build-module/query-controls/category-select.js +3 -1
  103. package/build-module/query-controls/category-select.js.map +1 -1
  104. package/build-module/query-controls/index.js +7 -2
  105. package/build-module/query-controls/index.js.map +1 -1
  106. package/build-module/sandbox/index.native.js +56 -31
  107. package/build-module/sandbox/index.native.js.map +1 -1
  108. package/build-module/slot-fill/index.js +16 -6
  109. package/build-module/slot-fill/index.js.map +1 -1
  110. package/build-module/spinner/styles.js +4 -4
  111. package/build-module/spinner/styles.js.map +1 -1
  112. package/build-module/tree-grid/index.js +3 -3
  113. package/build-module/tree-grid/index.js.map +1 -1
  114. package/build-module/view/component.js +1 -2
  115. package/build-module/view/component.js.map +1 -1
  116. package/build-style/style-rtl.css +26 -16
  117. package/build-style/style.css +26 -16
  118. package/build-types/angle-picker-control/styles/angle-picker-control-styles.d.ts +1 -1
  119. package/build-types/border-box-control/border-box-control/hook.d.ts +2 -2
  120. package/build-types/border-box-control/border-box-control-linked-button/hook.d.ts +2 -2
  121. package/build-types/border-box-control/border-box-control-split-controls/hook.d.ts +2 -2
  122. package/build-types/border-box-control/border-box-control-visualizer/hook.d.ts +2 -2
  123. package/build-types/border-control/border-control/hook.d.ts +2 -2
  124. package/build-types/border-control/border-control-dropdown/hook.d.ts +2 -2
  125. package/build-types/border-control/border-control-style-picker/hook.d.ts +2 -2
  126. package/build-types/box-control/styles/box-control-styles.d.ts +5 -5
  127. package/build-types/button/deprecated.d.ts +8 -8
  128. package/build-types/card/card/hook.d.ts +2 -2
  129. package/build-types/card/card-body/hook.d.ts +2 -2
  130. package/build-types/card/card-divider/hook.d.ts +2 -2
  131. package/build-types/card/card-footer/hook.d.ts +2 -2
  132. package/build-types/card/card-header/hook.d.ts +2 -2
  133. package/build-types/card/card-media/hook.d.ts +2 -2
  134. package/build-types/checkbox-control/index.d.ts.map +1 -1
  135. package/build-types/color-palette/styles.d.ts +1 -1
  136. package/build-types/color-picker/styles.d.ts +7 -7
  137. package/build-types/combobox-control/styles.d.ts +1 -1
  138. package/build-types/custom-gradient-picker/serializer.d.ts +1 -5
  139. package/build-types/custom-gradient-picker/serializer.d.ts.map +1 -1
  140. package/build-types/custom-gradient-picker/types.d.ts +0 -2
  141. package/build-types/custom-gradient-picker/types.d.ts.map +1 -1
  142. package/build-types/date-time/date/styles.d.ts +2 -2
  143. package/build-types/date-time/date-time/styles.d.ts +1 -1
  144. package/build-types/date-time/time/styles.d.ts +8 -8
  145. package/build-types/draggable/index.d.ts +1 -1
  146. package/build-types/draggable/index.d.ts.map +1 -1
  147. package/build-types/draggable/stories/index.d.ts +8 -0
  148. package/build-types/draggable/stories/index.d.ts.map +1 -1
  149. package/build-types/draggable/types.d.ts +7 -0
  150. package/build-types/draggable/types.d.ts.map +1 -1
  151. package/build-types/drop-zone/index.d.ts.map +1 -1
  152. package/build-types/elevation/hook.d.ts +2 -2
  153. package/build-types/external-link/styles/external-link-styles.d.ts +1 -1
  154. package/build-types/flex/flex/hook.d.ts +2 -2
  155. package/build-types/flex/flex-block/hook.d.ts +2 -2
  156. package/build-types/flex/flex-item/hook.d.ts +2 -2
  157. package/build-types/focal-point-picker/styles/focal-point-picker-style.d.ts +2 -2
  158. package/build-types/form-token-field/styles.d.ts +1 -1
  159. package/build-types/grid/hook.d.ts +2 -2
  160. package/build-types/h-stack/hook.d.ts +2 -2
  161. package/build-types/heading/hook.d.ts +2 -2
  162. package/build-types/index.d.ts +129 -0
  163. package/build-types/index.d.ts.map +1 -0
  164. package/build-types/input-control/styles/input-control-styles.d.ts +2 -2
  165. package/build-types/item-group/item/hook.d.ts +2 -2
  166. package/build-types/item-group/item-group/hook.d.ts +2 -2
  167. package/build-types/navigation/styles/navigation-styles.d.ts +2 -2
  168. package/build-types/navigator/navigator-back-button/component.d.ts +1 -1
  169. package/build-types/navigator/navigator-back-button/hook.d.ts +3 -3
  170. package/build-types/navigator/navigator-button/component.d.ts +1 -1
  171. package/build-types/navigator/navigator-button/hook.d.ts +3 -3
  172. package/build-types/navigator/navigator-provider/component.d.ts.map +1 -1
  173. package/build-types/navigator/navigator-screen/component.d.ts +1 -1
  174. package/build-types/navigator/navigator-screen/component.d.ts.map +1 -1
  175. package/build-types/navigator/navigator-to-parent-button/component.d.ts +1 -1
  176. package/build-types/navigator/stories/index.d.ts +1 -0
  177. package/build-types/navigator/stories/index.d.ts.map +1 -1
  178. package/build-types/navigator/types.d.ts +2 -2
  179. package/build-types/navigator/types.d.ts.map +1 -1
  180. package/build-types/number-control/index.d.ts +2 -2
  181. package/build-types/number-control/stories/index.d.ts +2 -2
  182. package/build-types/palette-edit/styles.d.ts +18 -12
  183. package/build-types/palette-edit/styles.d.ts.map +1 -1
  184. package/build-types/popover/index.d.ts +1 -1
  185. package/build-types/popover/index.d.ts.map +1 -1
  186. package/build-types/popover/stories/e2e/index.d.ts +1 -1
  187. package/build-types/private-apis.d.ts +2 -3
  188. package/build-types/private-apis.d.ts.map +1 -1
  189. package/build-types/query-controls/author-select.d.ts.map +1 -1
  190. package/build-types/query-controls/category-select.d.ts.map +1 -1
  191. package/build-types/query-controls/index.d.ts.map +1 -1
  192. package/build-types/range-control/index.d.ts +1 -1
  193. package/build-types/range-control/styles/range-control-styles.d.ts +2 -2
  194. package/build-types/resizable-box/index.d.ts +1 -1
  195. package/build-types/resizable-box/resize-tooltip/index.d.ts +1 -1
  196. package/build-types/resizable-box/stories/index.d.ts +2 -2
  197. package/build-types/scrollable/hook.d.ts +2 -2
  198. package/build-types/search-control/index.d.ts +1 -1
  199. package/build-types/search-control/stories/index.d.ts +2 -2
  200. package/build-types/slot-fill/index.d.ts +13 -1
  201. package/build-types/slot-fill/index.d.ts.map +1 -1
  202. package/build-types/spacer/hook.d.ts +2 -2
  203. package/build-types/spinner/index.d.ts +1 -1
  204. package/build-types/spinner/styles.d.ts.map +1 -1
  205. package/build-types/surface/hook.d.ts +2 -2
  206. package/build-types/text/hook.d.ts +2 -2
  207. package/build-types/text-control/index.d.ts +1 -1
  208. package/build-types/toolbar/toolbar-button/index.d.ts +8 -8
  209. package/build-types/tools-panel/tools-panel/hook.d.ts +2 -2
  210. package/build-types/tools-panel/tools-panel-header/hook.d.ts +2 -2
  211. package/build-types/tools-panel/tools-panel-item/hook.d.ts +2 -2
  212. package/build-types/tree-grid/index.d.ts.map +1 -1
  213. package/build-types/truncate/hook.d.ts +2 -2
  214. package/build-types/ui/context/wordpress-component.d.ts +1 -1
  215. package/build-types/ui/context/wordpress-component.d.ts.map +1 -1
  216. package/build-types/ui/control-group/hook.d.ts +2 -2
  217. package/build-types/ui/control-label/hook.d.ts +2 -2
  218. package/build-types/ui/form-group/form-group.d.ts +2 -2
  219. package/build-types/ui/form-group/use-form-group.d.ts +2 -2
  220. package/build-types/unit-control/index.d.ts +1 -1
  221. package/build-types/unit-control/styles/unit-control-styles.d.ts +2 -2
  222. package/build-types/v-stack/hook.d.ts +2 -2
  223. package/build-types/view/component.d.ts +1 -1
  224. package/build-types/view/component.d.ts.map +1 -1
  225. package/package.json +22 -22
  226. package/src/autocomplete/README.md +4 -2
  227. package/src/checkbox-control/index.tsx +6 -2
  228. package/src/color-palette/index.native.js +20 -1
  229. package/src/color-picker/test/index.tsx +99 -99
  230. package/src/custom-gradient-picker/index.native.js +1 -1
  231. package/src/custom-gradient-picker/serializer.ts +2 -6
  232. package/src/custom-gradient-picker/types.ts +0 -18
  233. package/src/dimension-control/README.md +1 -1
  234. package/src/draggable/README.md +8 -1
  235. package/src/draggable/index.tsx +6 -1
  236. package/src/draggable/stories/index.tsx +69 -33
  237. package/src/draggable/types.ts +7 -0
  238. package/src/drop-zone/index.tsx +12 -8
  239. package/src/drop-zone/style.scss +1 -1
  240. package/src/{index.js → index.ts} +1 -0
  241. package/src/mobile/bottom-sheet/cell.native.js +4 -5
  242. package/src/mobile/color-settings/palette.screen.native.js +0 -7
  243. package/src/mobile/global-styles-context/utils.native.js +18 -3
  244. package/src/mobile/keyboard-aware-flat-list/index.android.js +0 -4
  245. package/src/mobile/keyboard-aware-flat-list/index.ios.js +118 -67
  246. package/src/mobile/keyboard-aware-flat-list/test/use-keyboard-offset.native.js +203 -0
  247. package/src/mobile/keyboard-aware-flat-list/test/use-scroll-to-text-input.native.js +140 -0
  248. package/src/mobile/keyboard-aware-flat-list/test/use-text-input-caret-position.native.js +82 -0
  249. package/src/mobile/keyboard-aware-flat-list/test/use-text-input-offset.native.js +147 -0
  250. package/src/mobile/keyboard-aware-flat-list/use-keyboard-offset.native.js +87 -0
  251. package/src/mobile/keyboard-aware-flat-list/use-scroll-to-text-input.native.js +105 -0
  252. package/src/mobile/keyboard-aware-flat-list/use-text-input-caret-position.native.js +36 -0
  253. package/src/mobile/keyboard-aware-flat-list/use-text-input-offset.native.js +54 -0
  254. package/src/mobile/segmented-control/index.native.js +2 -2
  255. package/src/modal/style.scss +20 -12
  256. package/src/navigator/navigator-provider/component.tsx +2 -0
  257. package/src/navigator/navigator-screen/component.tsx +5 -2
  258. package/src/navigator/stories/index.tsx +68 -0
  259. package/src/navigator/test/index.tsx +52 -0
  260. package/src/navigator/types.ts +2 -1
  261. package/src/popover/index.tsx +2 -15
  262. package/src/{private-apis.js → private-apis.ts} +2 -0
  263. package/src/query-controls/author-select.tsx +1 -0
  264. package/src/query-controls/category-select.tsx +1 -0
  265. package/src/query-controls/index.tsx +4 -2
  266. package/src/sandbox/index.native.js +78 -37
  267. package/src/slot-fill/index.js +14 -6
  268. package/src/snackbar/style.scss +2 -1
  269. package/src/spinner/styles.ts +2 -0
  270. package/src/tree-grid/index.tsx +7 -2
  271. package/src/ui/context/wordpress-component.ts +1 -1
  272. package/src/view/component.tsx +2 -2
  273. package/tsconfig.json +3 -4
  274. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,82 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { renderHook } from '@testing-library/react-native';
5
+
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import RCTAztecView from '@wordpress/react-native-aztec';
10
+
11
+ /**
12
+ * Internal dependencies
13
+ */
14
+ import useTextInputCaretPosition from '../use-text-input-caret-position';
15
+
16
+ describe( 'useTextInputCaretPosition', () => {
17
+ let addCaretChangeListenerSpy;
18
+ let removeCaretChangeListenerSpy;
19
+
20
+ beforeAll( () => {
21
+ addCaretChangeListenerSpy = jest.spyOn(
22
+ RCTAztecView.InputState,
23
+ 'addCaretChangeListener'
24
+ );
25
+ removeCaretChangeListenerSpy = jest.spyOn(
26
+ RCTAztecView.InputState,
27
+ 'removeCaretChangeListener'
28
+ );
29
+ } );
30
+
31
+ beforeEach( () => {
32
+ addCaretChangeListenerSpy.mockClear();
33
+ removeCaretChangeListenerSpy.mockClear();
34
+ } );
35
+
36
+ it( 'should add and remove caret change listener correctly', () => {
37
+ // Arrange
38
+ const scrollEnabled = true;
39
+
40
+ // Act
41
+ const { unmount } = renderHook( () =>
42
+ useTextInputCaretPosition( scrollEnabled )
43
+ );
44
+ unmount();
45
+
46
+ // Assert
47
+ expect( addCaretChangeListenerSpy ).toHaveBeenCalledTimes( 1 );
48
+ expect( removeCaretChangeListenerSpy ).toHaveBeenCalledTimes( 1 );
49
+ } );
50
+
51
+ it( 'should add caret change listener when scroll is enabled', () => {
52
+ // Arrange
53
+ const scrollEnabled = true;
54
+
55
+ // Act
56
+ renderHook( () => useTextInputCaretPosition( scrollEnabled ) );
57
+
58
+ // Assert
59
+ expect( addCaretChangeListenerSpy ).toHaveBeenCalledTimes( 1 );
60
+ expect( removeCaretChangeListenerSpy ).not.toHaveBeenCalled();
61
+ } );
62
+
63
+ it( 'should remove caret change listener when scroll is enabled and then changed to disabled', () => {
64
+ // Arrange
65
+ const { rerender } = renderHook(
66
+ ( props ) => useTextInputCaretPosition( props.scrollEnabled ),
67
+ {
68
+ initialProps: { scrollEnabled: true },
69
+ }
70
+ );
71
+
72
+ // Assert
73
+ expect( addCaretChangeListenerSpy ).toHaveBeenCalled();
74
+
75
+ // Act
76
+ rerender( { scrollEnabled: false } );
77
+
78
+ // Assert
79
+ expect( removeCaretChangeListenerSpy ).toHaveBeenCalled();
80
+ expect( addCaretChangeListenerSpy ).toHaveBeenCalledTimes( 1 );
81
+ } );
82
+ } );
@@ -0,0 +1,147 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { renderHook } from '@testing-library/react-native';
5
+
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import RCTAztecView from '@wordpress/react-native-aztec';
10
+
11
+ /**
12
+ * Internal dependencies
13
+ */
14
+ import useTextInputOffset from '../use-text-input-offset';
15
+
16
+ jest.mock( '@wordpress/react-native-aztec', () => ( {
17
+ InputState: {
18
+ getCurrentFocusedElement: jest.fn(),
19
+ },
20
+ } ) );
21
+
22
+ describe( 'useTextInputOffset', () => {
23
+ afterEach( () => {
24
+ jest.clearAllMocks();
25
+ } );
26
+
27
+ it( 'should return a function', () => {
28
+ // Arrange
29
+ const scrollViewRef = { current: {} };
30
+ const scrollEnabled = true;
31
+
32
+ // Act
33
+ const { result } = renderHook( () =>
34
+ useTextInputOffset( scrollEnabled, scrollViewRef )
35
+ );
36
+
37
+ // Assert
38
+ expect( result.current[ 0 ] ).toBeInstanceOf( Function );
39
+ } );
40
+
41
+ it( 'should return null when scrollViewRef.current is null', async () => {
42
+ // Arrange
43
+ const scrollViewRef = { current: null };
44
+ const scrollEnabled = true;
45
+
46
+ // Act
47
+ const { result } = renderHook( () =>
48
+ useTextInputOffset( scrollEnabled, scrollViewRef )
49
+ );
50
+ const getTextInputOffset = result.current[ 0 ];
51
+
52
+ // Assert
53
+ const offset = await getTextInputOffset();
54
+ expect( offset ).toBeNull();
55
+ } );
56
+
57
+ it( 'should return null when textInput is null', async () => {
58
+ // Arrange
59
+ const scrollViewRef = { current: {} };
60
+ const scrollEnabled = true;
61
+ RCTAztecView.InputState.getCurrentFocusedElement.mockReturnValue(
62
+ null
63
+ );
64
+
65
+ // Act
66
+ const { result } = renderHook( () =>
67
+ useTextInputOffset( scrollEnabled, scrollViewRef )
68
+ );
69
+ const getTextInputOffset = result.current[ 0 ];
70
+
71
+ // Assert
72
+ const offset = await getTextInputOffset();
73
+ expect( offset ).toBeNull();
74
+ } );
75
+
76
+ it( 'should return null when scroll is not enabled', async () => {
77
+ // Arrange
78
+ const scrollViewRef = { current: {} };
79
+ const scrollEnabled = false;
80
+
81
+ // Act
82
+ const { result } = renderHook( () =>
83
+ useTextInputOffset( scrollEnabled, scrollViewRef )
84
+ );
85
+ const getTextInputOffset = result.current[ 0 ];
86
+
87
+ // Assert
88
+ const offset = await getTextInputOffset();
89
+ expect( offset ).toBeNull();
90
+ } );
91
+
92
+ it( 'should return correct offset value when caretY is not null', async () => {
93
+ // Arrange
94
+ const scrollViewRef = { current: {} };
95
+ const scrollEnabled = true;
96
+ const x = 0;
97
+ const y = 10;
98
+ const width = 0;
99
+ const height = 100;
100
+ const textInput = {
101
+ measureLayout: jest.fn( ( _, callback ) => {
102
+ callback( x, y, width, height );
103
+ } ),
104
+ };
105
+ RCTAztecView.InputState.getCurrentFocusedElement.mockReturnValue(
106
+ textInput
107
+ );
108
+
109
+ // Act
110
+ const { result } = renderHook( () =>
111
+ useTextInputOffset( scrollEnabled, scrollViewRef )
112
+ );
113
+ const getTextInputOffset = result.current[ 0 ];
114
+
115
+ // Assert
116
+ const offset = await getTextInputOffset( { caretY: 10 } );
117
+ expect( offset ).toBe( 20 );
118
+ } );
119
+
120
+ it( 'should return correct offset value when caretY is -1', async () => {
121
+ // Arrange
122
+ const scrollViewRef = { current: {} };
123
+ const scrollEnabled = true;
124
+ const x = 0;
125
+ const y = 10;
126
+ const width = 0;
127
+ const height = 100;
128
+ const textInput = {
129
+ measureLayout: jest.fn( ( _, callback ) => {
130
+ callback( x, y, width, height );
131
+ } ),
132
+ };
133
+ RCTAztecView.InputState.getCurrentFocusedElement.mockReturnValue(
134
+ textInput
135
+ );
136
+
137
+ // Act
138
+ const { result } = renderHook( () =>
139
+ useTextInputOffset( scrollEnabled, scrollViewRef )
140
+ );
141
+ const getTextInputOffset = result.current[ 0 ];
142
+
143
+ // Assert
144
+ const offset = await getTextInputOffset( { caretY: -1 } );
145
+ expect( offset ).toBe( 110 );
146
+ } );
147
+ } );
@@ -0,0 +1,87 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+
5
+ import { Keyboard } from 'react-native';
6
+
7
+ /**
8
+ * WordPress dependencies
9
+ */
10
+ import { useEffect, useCallback, useState, useRef } from '@wordpress/element';
11
+
12
+ /**
13
+ * Hook that adds Keyboard listeners to get the offset space
14
+ * when the keyboard is opened, taking into account focused AztecViews.
15
+ *
16
+ * @param {boolean} scrollEnabled Whether the scroll is enabled or not.
17
+ * @param {Function} shouldPreventAutomaticScroll Whether to prevent scrolling when there's a Keyboard offset set.
18
+ * @return {[number]} Keyboard offset.
19
+ */
20
+ export default function useKeyboardOffset(
21
+ scrollEnabled,
22
+ shouldPreventAutomaticScroll
23
+ ) {
24
+ const [ keyboardOffset, setKeyboardOffset ] = useState( 0 );
25
+ const timeoutRef = useRef();
26
+
27
+ const onKeyboardDidHide = useCallback( () => {
28
+ if ( shouldPreventAutomaticScroll() ) {
29
+ clearTimeout( timeoutRef.current );
30
+ return;
31
+ }
32
+
33
+ // A timeout is being used to delay resetting the offset in cases
34
+ // where the focus is changed to a different TextInput.
35
+ clearTimeout( timeoutRef.current );
36
+ timeoutRef.current = setTimeout( () => {
37
+ setKeyboardOffset( 0 );
38
+ }, 200 );
39
+ }, [ shouldPreventAutomaticScroll ] );
40
+
41
+ const onKeyboardDidShow = useCallback( ( { endCoordinates } ) => {
42
+ clearTimeout( timeoutRef.current );
43
+ setKeyboardOffset( endCoordinates.height );
44
+ }, [] );
45
+
46
+ const onKeyboardWillShow = useCallback( () => {
47
+ clearTimeout( timeoutRef.current );
48
+ }, [] );
49
+
50
+ useEffect( () => {
51
+ let willShowSubscription;
52
+ let showSubscription;
53
+ let hideSubscription;
54
+
55
+ if ( scrollEnabled ) {
56
+ willShowSubscription = Keyboard.addListener(
57
+ 'keyboardWillShow',
58
+ onKeyboardWillShow
59
+ );
60
+ showSubscription = Keyboard.addListener(
61
+ 'keyboardDidShow',
62
+ onKeyboardDidShow
63
+ );
64
+ hideSubscription = Keyboard.addListener(
65
+ 'keyboardDidHide',
66
+ onKeyboardDidHide
67
+ );
68
+ } else {
69
+ willShowSubscription?.remove();
70
+ showSubscription?.remove();
71
+ hideSubscription?.remove();
72
+ }
73
+
74
+ return () => {
75
+ clearTimeout( timeoutRef.current );
76
+ willShowSubscription?.remove();
77
+ showSubscription?.remove();
78
+ hideSubscription?.remove();
79
+ };
80
+ }, [
81
+ onKeyboardDidHide,
82
+ onKeyboardDidShow,
83
+ onKeyboardWillShow,
84
+ scrollEnabled,
85
+ ] );
86
+ return [ keyboardOffset ];
87
+ }
@@ -0,0 +1,105 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { useSafeAreaInsets } from 'react-native-safe-area-context';
5
+
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import { useCallback } from '@wordpress/element';
10
+
11
+ const DEFAULT_FONT_SIZE = 16;
12
+
13
+ /** @typedef {import('@wordpress/element').RefObject} RefObject */
14
+ /** @typedef {import('react-native-reanimated').SharedValue} SharedValue */
15
+ /**
16
+ * Hook to scroll to the currently focused TextInput
17
+ * depending on where the caret is placed taking into
18
+ * account the Keyboard and the Header.
19
+ *
20
+ * @param {number} extraScrollHeight Extra space to not overlap the content.
21
+ * @param {number} keyboardOffset Keyboard space offset.
22
+ * @param {boolean} scrollEnabled Whether the scroll is enabled or not.
23
+ * @param {RefObject} scrollViewMeasurements ScrollView Layout measurements.
24
+ * @param {RefObject} scrollViewRef ScrollView reference.
25
+ * @param {SharedValue} scrollViewYOffset Current offset position of the ScrollView.
26
+ * @return {Function[]} Function to scroll to the current TextInput's offset.
27
+ */
28
+ export default function useScrollToTextInput(
29
+ extraScrollHeight,
30
+ keyboardOffset,
31
+ scrollEnabled,
32
+ scrollViewMeasurements,
33
+ scrollViewRef,
34
+ scrollViewYOffset
35
+ ) {
36
+ const { top, bottom } = useSafeAreaInsets();
37
+ const insets = top + bottom;
38
+
39
+ /**
40
+ * Function to scroll to the current TextInput's offset.
41
+ *
42
+ * @param {Object} caret The caret position data of the currently focused TextInput.
43
+ * @param {number} caret.caretHeight The height of the caret.
44
+ * @param {number} textInputOffset The offset calculated with the caret's Y coordinate + the
45
+ * TextInput's Y coord or height value.
46
+ */
47
+ const scrollToTextInputOffset = useCallback(
48
+ ( caret, textInputOffset ) => {
49
+ const { caretHeight = DEFAULT_FONT_SIZE } = caret ?? {};
50
+
51
+ if (
52
+ ! scrollViewRef.current ||
53
+ ! scrollEnabled ||
54
+ ! scrollViewMeasurements.current
55
+ ) {
56
+ return;
57
+ }
58
+ const currentScrollViewYOffset = Math.max(
59
+ 0,
60
+ scrollViewYOffset.value
61
+ );
62
+
63
+ // Scroll up.
64
+ if ( textInputOffset < currentScrollViewYOffset ) {
65
+ scrollViewRef.current.scrollTo( {
66
+ y: textInputOffset,
67
+ animated: true,
68
+ } );
69
+ return;
70
+ }
71
+
72
+ const availableScreenSpace = Math.abs(
73
+ Math.floor(
74
+ scrollViewMeasurements.current.height -
75
+ ( keyboardOffset + extraScrollHeight + caretHeight )
76
+ )
77
+ );
78
+ const maxOffset = Math.floor(
79
+ currentScrollViewYOffset + availableScreenSpace
80
+ );
81
+
82
+ const isAtTheTop =
83
+ textInputOffset < scrollViewMeasurements.current.y + insets;
84
+
85
+ // Scroll down.
86
+ if ( textInputOffset > maxOffset && ! isAtTheTop ) {
87
+ scrollViewRef.current.scrollTo( {
88
+ y: textInputOffset - availableScreenSpace,
89
+ animated: true,
90
+ } );
91
+ }
92
+ },
93
+ [
94
+ extraScrollHeight,
95
+ insets,
96
+ keyboardOffset,
97
+ scrollEnabled,
98
+ scrollViewMeasurements,
99
+ scrollViewRef,
100
+ scrollViewYOffset,
101
+ ]
102
+ );
103
+
104
+ return [ scrollToTextInputOffset ];
105
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import RCTAztecView from '@wordpress/react-native-aztec';
5
+ import { useCallback, useEffect, useState } from '@wordpress/element';
6
+
7
+ /**
8
+ * Hook that listens to caret changes from AztecView TextInputs.
9
+ *
10
+ * @param {boolean} scrollEnabled Whether the scroll is enabled or not.
11
+ * @return {[number]} Current caret's data.
12
+ */
13
+ export default function useTextInputCaretPosition( scrollEnabled ) {
14
+ const [ currentCaretData, setCurrentCaretData ] = useState();
15
+
16
+ const onCaretChange = useCallback( ( caret ) => {
17
+ setCurrentCaretData( caret );
18
+ }, [] );
19
+
20
+ useEffect( () => {
21
+ if ( scrollEnabled ) {
22
+ RCTAztecView.InputState.addCaretChangeListener( onCaretChange );
23
+ } else {
24
+ RCTAztecView.InputState.removeCaretChangeListener( onCaretChange );
25
+ }
26
+
27
+ return () => {
28
+ if ( scrollEnabled ) {
29
+ RCTAztecView.InputState.removeCaretChangeListener(
30
+ onCaretChange
31
+ );
32
+ }
33
+ };
34
+ }, [ scrollEnabled, onCaretChange ] );
35
+ return [ currentCaretData ];
36
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import RCTAztecView from '@wordpress/react-native-aztec';
5
+ import { useCallback } from '@wordpress/element';
6
+
7
+ /** @typedef {import('@wordpress/element').RefObject} RefObject */
8
+ /**
9
+ * Hook that calculates the currently focused TextInput's current
10
+ * caret Y coordinate position.
11
+ *
12
+ * @param {boolean} scrollEnabled Whether the scroll is enabled or not.
13
+ * @param {RefObject} scrollViewRef ScrollView reference.
14
+ * @return {[Function]} Function to get the current TextInput's offset.
15
+ */
16
+ export default function useTextInputOffset( scrollEnabled, scrollViewRef ) {
17
+ const getTextInputOffset = useCallback(
18
+ async ( caret ) => {
19
+ const { caretY = null } = caret ?? {};
20
+ const textInput =
21
+ RCTAztecView.InputState.getCurrentFocusedElement();
22
+
23
+ return new Promise( ( resolve ) => {
24
+ if (
25
+ scrollViewRef.current &&
26
+ textInput &&
27
+ scrollEnabled &&
28
+ caretY !== null
29
+ ) {
30
+ textInput.measureLayout(
31
+ scrollViewRef.current,
32
+ ( _x, y, _width, height ) => {
33
+ const caretYOffset =
34
+ // For cases where the caretY value is -1
35
+ // we use the y + height value, e.g the current
36
+ // character index is not valid or out of bounds
37
+ // see https://github.com/wordpress-mobile/AztecEditor-iOS/blob/4d0522d67b0056ac211466caaa76936cc5b4f947/Aztec/Classes/TextKit/TextView.swift#L762
38
+ caretY >= 0 && caretY < height
39
+ ? y + caretY
40
+ : y + height;
41
+ resolve( Math.round( Math.abs( caretYOffset ) ) );
42
+ },
43
+ () => resolve( null )
44
+ );
45
+ } else {
46
+ resolve( null );
47
+ }
48
+ } );
49
+ },
50
+ [ scrollEnabled, scrollViewRef ]
51
+ );
52
+
53
+ return [ getTextInputOffset ];
54
+ }
@@ -140,8 +140,8 @@ const SegmentedControls = ( {
140
140
  styles.selectedDark
141
141
  );
142
142
 
143
- const width = segmentsDimensions[ activeSegmentIndex ].width;
144
- const height = segmentsDimensions[ activeSegmentIndex ].height;
143
+ const width = segmentsDimensions[ activeSegmentIndex ]?.width;
144
+ const height = segmentsDimensions[ activeSegmentIndex ]?.height;
145
145
 
146
146
  const outlineStyle = [ styles.outline, isIOS && styles.outlineIOS ];
147
147
 
@@ -16,31 +16,39 @@
16
16
  // The modal window element.
17
17
  .components-modal__frame {
18
18
  // Use the entire viewport on smaller screens.
19
- margin: 0;
19
+ margin: $grid-unit-50 0 0 0;
20
20
  width: 100%;
21
21
  background: $white;
22
22
  box-shadow: $shadow-modal;
23
- border-radius: $radius-block-ui;
23
+ border-radius: $grid-unit-10 $grid-unit-10 0 0;
24
24
  overflow: hidden;
25
25
  // Have the content element fill the vertical space yet not overflow.
26
26
  display: flex;
27
+ // Animate the modal frame/contents appearing on the page.
28
+ animation: components-modal__appear-animation 0.1s ease-out;
29
+ animation-fill-mode: forwards;
30
+ @include reduce-motion("animation");
27
31
 
28
32
  // Show a centered modal on bigger screens.
29
33
  @include break-small() {
34
+ border-radius: $grid-unit-10;
30
35
  margin: auto;
31
36
  width: auto;
32
37
  min-width: $modal-min-width;
33
38
  max-width: calc(100% - #{$grid-unit-20 * 2});
34
39
  max-height: calc(100% - #{$header-height * 2});
35
40
 
36
- // Animate the modal frame/contents appearing on the page.
37
- animation: components-modal__appear-animation 0.1s ease-out;
38
- animation-fill-mode: forwards;
39
- @include reduce-motion("animation");
40
-
41
41
  &.is-full-screen {
42
- width: 90vw;
43
- min-height: 90vh;
42
+ @include break-small() {
43
+ width: calc(100% - #{ $grid-unit-20 * 2 });
44
+ height: calc(100% - #{ $grid-unit-20 * 2 });
45
+ max-height: none;
46
+ }
47
+ @include break-medium() {
48
+ width: calc(100% - #{ $grid-unit-50 * 2 });
49
+ height: calc(100% - #{ $grid-unit-50 * 2 });
50
+ max-width: none;
51
+ }
44
52
  }
45
53
  }
46
54
 
@@ -64,12 +72,12 @@
64
72
  .components-modal__header {
65
73
  box-sizing: border-box;
66
74
  border-bottom: $border-width solid transparent;
67
- padding: 0 $grid-unit-40;
75
+ padding: $grid-unit-30 $grid-unit-40 $grid-unit-15;
68
76
  display: flex;
69
77
  flex-direction: row;
70
78
  justify-content: space-between;
71
79
  align-items: center;
72
- height: $header-height + $grid-unit-20;
80
+ height: $header-height + $grid-unit-15;
73
81
  width: 100%;
74
82
  z-index: z-index(".components-modal__header");
75
83
  position: absolute;
@@ -121,7 +129,7 @@
121
129
  // Modal contents.
122
130
  .components-modal__content {
123
131
  flex: 1;
124
- margin-top: $header-height + $grid-unit-20;
132
+ margin-top: $header-height + $grid-unit-15;
125
133
  padding: 0 $grid-unit-40 $grid-unit-40;
126
134
  overflow: auto;
127
135
 
@@ -147,6 +147,7 @@ function UnconnectedNavigatorProvider(
147
147
  const {
148
148
  focusTargetSelector,
149
149
  isBack = false,
150
+ skipFocus = false,
150
151
  ...restOptions
151
152
  } = options;
152
153
 
@@ -168,6 +169,7 @@ function UnconnectedNavigatorProvider(
168
169
  path,
169
170
  isBack,
170
171
  hasRestoredFocus: false,
172
+ skipFocus,
171
173
  };
172
174
 
173
175
  if ( prevLocationHistory.length < 1 ) {
@@ -43,7 +43,7 @@ const animationExitDelay = 0;
43
43
  // as some of them would overlap with HTML props (e.g. `onAnimationStart`, ...)
44
44
  type Props = Omit<
45
45
  WordPressComponentProps< NavigatorScreenProps, 'div', false >,
46
- keyof MotionProps
46
+ Exclude< keyof MotionProps, 'style' | 'children' >
47
47
  >;
48
48
 
49
49
  function UnconnectedNavigatorScreen(
@@ -100,11 +100,13 @@ function UnconnectedNavigatorScreen(
100
100
  // - when the screen becomes visible
101
101
  // - if the wrapper ref has been assigned
102
102
  // - if focus hasn't already been restored for the current location
103
+ // - if the `skipFocus` option is not set to `true`. This is useful when we trigger the navigation outside of NavigatorScreen.
103
104
  if (
104
105
  isInitialLocation ||
105
106
  ! isMatch ||
106
107
  ! wrapperRef.current ||
107
- locationRef.current.hasRestoredFocus
108
+ locationRef.current.hasRestoredFocus ||
109
+ location.skipFocus
108
110
  ) {
109
111
  return;
110
112
  }
@@ -143,6 +145,7 @@ function UnconnectedNavigatorScreen(
143
145
  isMatch,
144
146
  location.isBack,
145
147
  location.focusTargetSelector,
148
+ location.skipFocus,
146
149
  ] );
147
150
 
148
151
  const mergedWrapperRef = useMergeRefs( [ forwardedRef, wrapperRef ] );