@wordpress/components 28.7.0 → 28.8.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 (240) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/build/box-control/all-input-control.js +1 -2
  3. package/build/box-control/all-input-control.js.map +1 -1
  4. package/build/box-control/utils.js +1 -1
  5. package/build/box-control/utils.js.map +1 -1
  6. package/build/card/card/component.js +2 -2
  7. package/build/card/card/component.js.map +1 -1
  8. package/build/card/styles.js +18 -18
  9. package/build/card/styles.js.map +1 -1
  10. package/build/combobox-control/index.js +3 -1
  11. package/build/combobox-control/index.js.map +1 -1
  12. package/build/combobox-control/types.js.map +1 -1
  13. package/build/composite/context.js +1 -1
  14. package/build/composite/context.js.map +1 -1
  15. package/build/composite/group-label.js +1 -1
  16. package/build/composite/group-label.js.map +1 -1
  17. package/build/composite/group.js +1 -1
  18. package/build/composite/group.js.map +1 -1
  19. package/build/composite/hover.js +1 -1
  20. package/build/composite/hover.js.map +1 -1
  21. package/build/composite/index.js +17 -26
  22. package/build/composite/index.js.map +1 -1
  23. package/build/composite/item.js +1 -1
  24. package/build/composite/item.js.map +1 -1
  25. package/build/composite/legacy/index.js +59 -8
  26. package/build/composite/legacy/index.js.map +1 -1
  27. package/build/composite/row.js +1 -1
  28. package/build/composite/row.js.map +1 -1
  29. package/build/composite/typeahead.js +1 -1
  30. package/build/composite/typeahead.js.map +1 -1
  31. package/build/composite/types.js.map +1 -1
  32. package/build/custom-select-control-v2/styles.js +9 -9
  33. package/build/custom-select-control-v2/styles.js.map +1 -1
  34. package/build/date-time/date/index.js +1 -1
  35. package/build/date-time/date/index.js.map +1 -1
  36. package/build/date-time/date/styles.js +35 -24
  37. package/build/date-time/date/styles.js.map +1 -1
  38. package/build/date-time/date/use-lilius/index.js +163 -0
  39. package/build/date-time/date/use-lilius/index.js.map +1 -0
  40. package/build/dropdown-menu-v2/styles.js +17 -17
  41. package/build/dropdown-menu-v2/styles.js.map +1 -1
  42. package/build/index.js +7 -0
  43. package/build/index.js.map +1 -1
  44. package/build/modal/index.js +27 -12
  45. package/build/modal/index.js.map +1 -1
  46. package/build/modal/types.js.map +1 -1
  47. package/build/modal/use-modal-exit-animation.js +75 -0
  48. package/build/modal/use-modal-exit-animation.js.map +1 -0
  49. package/build/navigator/navigator-screen/component.js +5 -0
  50. package/build/navigator/navigator-screen/component.js.map +1 -1
  51. package/build/private-apis.js +0 -9
  52. package/build/private-apis.js.map +1 -1
  53. package/build/range-control/styles/range-control-styles.js +28 -28
  54. package/build/range-control/styles/range-control-styles.js.map +1 -1
  55. package/build/slot-fill/index.js +1 -0
  56. package/build/slot-fill/index.js.map +1 -1
  57. package/build/tabs/styles.js +3 -3
  58. package/build/tabs/styles.js.map +1 -1
  59. package/build/tabs/tablist.js +5 -4
  60. package/build/tabs/tablist.js.map +1 -1
  61. package/build/utils/config-values.js +4 -5
  62. package/build/utils/config-values.js.map +1 -1
  63. package/build/utils/element-rect.js +73 -105
  64. package/build/utils/element-rect.js.map +1 -1
  65. package/build-module/box-control/all-input-control.js +2 -2
  66. package/build-module/box-control/all-input-control.js.map +1 -1
  67. package/build-module/box-control/utils.js +1 -1
  68. package/build-module/box-control/utils.js.map +1 -1
  69. package/build-module/card/card/component.js +2 -2
  70. package/build-module/card/card/component.js.map +1 -1
  71. package/build-module/card/styles.js +18 -18
  72. package/build-module/card/styles.js.map +1 -1
  73. package/build-module/combobox-control/index.js +3 -1
  74. package/build-module/combobox-control/index.js.map +1 -1
  75. package/build-module/combobox-control/types.js.map +1 -1
  76. package/build-module/composite/context.js +1 -1
  77. package/build-module/composite/context.js.map +1 -1
  78. package/build-module/composite/group-label.js +1 -1
  79. package/build-module/composite/group-label.js.map +1 -1
  80. package/build-module/composite/group.js +1 -1
  81. package/build-module/composite/group.js.map +1 -1
  82. package/build-module/composite/hover.js +1 -1
  83. package/build-module/composite/hover.js.map +1 -1
  84. package/build-module/composite/index.js +17 -26
  85. package/build-module/composite/index.js.map +1 -1
  86. package/build-module/composite/item.js +1 -1
  87. package/build-module/composite/item.js.map +1 -1
  88. package/build-module/composite/legacy/index.js +56 -8
  89. package/build-module/composite/legacy/index.js.map +1 -1
  90. package/build-module/composite/row.js +1 -1
  91. package/build-module/composite/row.js.map +1 -1
  92. package/build-module/composite/typeahead.js +1 -1
  93. package/build-module/composite/typeahead.js.map +1 -1
  94. package/build-module/composite/types.js.map +1 -1
  95. package/build-module/custom-select-control-v2/styles.js +9 -9
  96. package/build-module/custom-select-control-v2/styles.js.map +1 -1
  97. package/build-module/date-time/date/index.js +1 -2
  98. package/build-module/date-time/date/index.js.map +1 -1
  99. package/build-module/date-time/date/styles.js +31 -24
  100. package/build-module/date-time/date/styles.js.map +1 -1
  101. package/build-module/date-time/date/use-lilius/index.js +158 -0
  102. package/build-module/date-time/date/use-lilius/index.js.map +1 -0
  103. package/build-module/dropdown-menu-v2/styles.js +17 -17
  104. package/build-module/dropdown-menu-v2/styles.js.map +1 -1
  105. package/build-module/index.js +1 -0
  106. package/build-module/index.js.map +1 -1
  107. package/build-module/modal/index.js +29 -12
  108. package/build-module/modal/index.js.map +1 -1
  109. package/build-module/modal/types.js.map +1 -1
  110. package/build-module/modal/use-modal-exit-animation.js +68 -0
  111. package/build-module/modal/use-modal-exit-animation.js.map +1 -0
  112. package/build-module/navigator/navigator-screen/component.js +4 -0
  113. package/build-module/navigator/navigator-screen/component.js.map +1 -1
  114. package/build-module/private-apis.js +0 -9
  115. package/build-module/private-apis.js.map +1 -1
  116. package/build-module/range-control/styles/range-control-styles.js +28 -28
  117. package/build-module/range-control/styles/range-control-styles.js.map +1 -1
  118. package/build-module/slot-fill/index.js +1 -0
  119. package/build-module/slot-fill/index.js.map +1 -1
  120. package/build-module/tabs/styles.js +3 -3
  121. package/build-module/tabs/styles.js.map +1 -1
  122. package/build-module/tabs/tablist.js +5 -4
  123. package/build-module/tabs/tablist.js.map +1 -1
  124. package/build-module/utils/config-values.js +4 -5
  125. package/build-module/utils/config-values.js.map +1 -1
  126. package/build-module/utils/element-rect.js +74 -105
  127. package/build-module/utils/element-rect.js.map +1 -1
  128. package/build-style/style-rtl.css +51 -10
  129. package/build-style/style.css +51 -10
  130. package/build-types/box-control/all-input-control.d.ts.map +1 -1
  131. package/build-types/box-control/utils.d.ts +1 -1
  132. package/build-types/box-control/utils.d.ts.map +1 -1
  133. package/build-types/button-group/stories/index.story.d.ts +2 -2
  134. package/build-types/button-group/stories/index.story.d.ts.map +1 -1
  135. package/build-types/combobox-control/index.d.ts.map +1 -1
  136. package/build-types/combobox-control/stories/index.story.d.ts +4 -0
  137. package/build-types/combobox-control/stories/index.story.d.ts.map +1 -1
  138. package/build-types/combobox-control/types.d.ts +4 -0
  139. package/build-types/combobox-control/types.d.ts.map +1 -1
  140. package/build-types/composite/context.d.ts.map +1 -1
  141. package/build-types/composite/index.d.ts +36 -24
  142. package/build-types/composite/index.d.ts.map +1 -1
  143. package/build-types/composite/legacy/index.d.ts +25 -2
  144. package/build-types/composite/legacy/index.d.ts.map +1 -1
  145. package/build-types/composite/legacy/stories/index.story.d.ts.map +1 -1
  146. package/build-types/composite/stories/index.story.d.ts +9 -9
  147. package/build-types/composite/stories/index.story.d.ts.map +1 -1
  148. package/build-types/composite/types.d.ts +11 -10
  149. package/build-types/composite/types.d.ts.map +1 -1
  150. package/build-types/custom-select-control-v2/styles.d.ts.map +1 -1
  151. package/build-types/date-time/date/index.d.ts +0 -3
  152. package/build-types/date-time/date/index.d.ts.map +1 -1
  153. package/build-types/date-time/date/styles.d.ts.map +1 -1
  154. package/build-types/date-time/date/test/use-lilius.d.ts +2 -0
  155. package/build-types/date-time/date/test/use-lilius.d.ts.map +1 -0
  156. package/build-types/date-time/date/use-lilius/index.d.ts +169 -0
  157. package/build-types/date-time/date/use-lilius/index.d.ts.map +1 -0
  158. package/build-types/index.d.ts +1 -0
  159. package/build-types/index.d.ts.map +1 -1
  160. package/build-types/modal/index.d.ts.map +1 -1
  161. package/build-types/modal/stories/index.story.d.ts +3 -0
  162. package/build-types/modal/stories/index.story.d.ts.map +1 -1
  163. package/build-types/modal/types.d.ts +6 -10
  164. package/build-types/modal/types.d.ts.map +1 -1
  165. package/build-types/modal/use-modal-exit-animation.d.ts +9 -0
  166. package/build-types/modal/use-modal-exit-animation.d.ts.map +1 -0
  167. package/build-types/navigator/navigator-screen/component.d.ts.map +1 -1
  168. package/build-types/private-apis.d.ts.map +1 -1
  169. package/build-types/range-control/styles/range-control-styles.d.ts.map +1 -1
  170. package/build-types/slot-fill/index.d.ts +3 -0
  171. package/build-types/slot-fill/index.d.ts.map +1 -1
  172. package/build-types/tabs/styles.d.ts.map +1 -1
  173. package/build-types/tabs/tablist.d.ts.map +1 -1
  174. package/build-types/utils/config-values.d.ts +0 -1
  175. package/build-types/utils/element-rect.d.ts +32 -74
  176. package/build-types/utils/element-rect.d.ts.map +1 -1
  177. package/package.json +19 -20
  178. package/src/box-control/README.md +7 -0
  179. package/src/box-control/all-input-control.tsx +2 -3
  180. package/src/box-control/utils.ts +1 -1
  181. package/src/button-group/stories/index.story.tsx +10 -15
  182. package/src/card/card/component.tsx +1 -1
  183. package/src/card/styles.ts +1 -1
  184. package/src/card/test/__snapshots__/index.tsx.snap +54 -54
  185. package/src/combobox-control/README.md +7 -0
  186. package/src/combobox-control/index.tsx +2 -0
  187. package/src/combobox-control/test/index.tsx +40 -0
  188. package/src/combobox-control/types.ts +4 -0
  189. package/src/composite/README.md +5 -24
  190. package/src/composite/{context.ts → context.tsx} +1 -2
  191. package/src/composite/group-label.tsx +1 -1
  192. package/src/composite/group.tsx +1 -1
  193. package/src/composite/hover.tsx +1 -1
  194. package/src/composite/index.tsx +17 -28
  195. package/src/composite/item.tsx +1 -1
  196. package/src/composite/legacy/index.tsx +72 -11
  197. package/src/composite/legacy/stories/index.story.tsx +2 -1
  198. package/src/composite/legacy/test/index.tsx +57 -1
  199. package/src/composite/row.tsx +1 -1
  200. package/src/composite/stories/index.story.tsx +185 -169
  201. package/src/composite/typeahead.tsx +1 -1
  202. package/src/composite/types.ts +13 -15
  203. package/src/custom-select-control-v2/styles.ts +1 -0
  204. package/src/date-time/date/index.tsx +1 -1
  205. package/src/date-time/date/styles.ts +31 -11
  206. package/src/date-time/date/test/use-lilius.ts +417 -0
  207. package/src/date-time/date/use-lilius/index.ts +394 -0
  208. package/src/dropdown-menu-v2/styles.ts +1 -1
  209. package/src/form-toggle/style.scss +1 -0
  210. package/src/index.ts +1 -0
  211. package/src/modal/index.tsx +42 -19
  212. package/src/modal/stories/index.story.tsx +8 -14
  213. package/src/modal/style.scss +30 -8
  214. package/src/modal/types.ts +6 -18
  215. package/src/modal/use-modal-exit-animation.ts +99 -0
  216. package/src/navigator/navigator-screen/component.tsx +7 -0
  217. package/src/navigator/test/index.tsx +8 -0
  218. package/src/popover/style.scss +3 -2
  219. package/src/private-apis.ts +0 -9
  220. package/src/range-control/styles/range-control-styles.ts +1 -0
  221. package/src/resizable-box/style.scss +1 -1
  222. package/src/select-control/README.md +2 -2
  223. package/src/slot-fill/index.tsx +1 -0
  224. package/src/snackbar/style.scss +1 -1
  225. package/src/tabs/styles.ts +40 -11
  226. package/src/tabs/tablist.tsx +5 -4
  227. package/src/tooltip/style.scss +1 -0
  228. package/src/utils/config-values.js +4 -5
  229. package/src/utils/element-rect.ts +93 -130
  230. package/tsconfig.tsbuildinfo +1 -1
  231. package/build/composite/store.js +0 -54
  232. package/build/composite/store.js.map +0 -1
  233. package/build-module/composite/store.js +0 -46
  234. package/build-module/composite/store.js.map +0 -1
  235. package/build-types/composite/store.d.ts +0 -25
  236. package/build-types/composite/store.d.ts.map +0 -1
  237. package/build-types/composite/stories/utils.d.ts +0 -29
  238. package/build-types/composite/stories/utils.d.ts.map +0 -1
  239. package/src/composite/store.ts +0 -46
  240. package/src/composite/stories/utils.tsx +0 -76
@@ -0,0 +1,394 @@
1
+ /**
2
+ * This source is a local copy of the use-lilius library, since the original
3
+ * library is not actively maintained.
4
+ * @see https://github.com/WordPress/gutenberg/discussions/64968
5
+ *
6
+ * use-lilius@2.0.5
7
+ * https://github.com/Avarios/use-lilius
8
+ *
9
+ * The MIT License (MIT)
10
+ *
11
+ * Copyright (c) 2021-Present Danny Tatom
12
+ *
13
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
14
+ * of this software and associated documentation files (the "Software"), to deal
15
+ * in the Software without restriction, including without limitation the rights
16
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
+ * copies of the Software, and to permit persons to whom the Software is
18
+ * furnished to do so, subject to the following conditions:
19
+ *
20
+ * The above copyright notice and this permission notice shall be included in all
21
+ * copies or substantial portions of the Software.
22
+ *
23
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
+ * SOFTWARE.
30
+ */
31
+
32
+ /**
33
+ * External dependencies
34
+ */
35
+ import {
36
+ addMonths,
37
+ addYears,
38
+ eachDayOfInterval,
39
+ eachMonthOfInterval,
40
+ eachWeekOfInterval,
41
+ endOfMonth,
42
+ endOfWeek,
43
+ isAfter,
44
+ isBefore,
45
+ isEqual,
46
+ set,
47
+ setMonth,
48
+ setYear,
49
+ startOfMonth,
50
+ startOfToday,
51
+ startOfWeek,
52
+ subMonths,
53
+ subYears,
54
+ } from 'date-fns';
55
+
56
+ /**
57
+ * WordPress dependencies
58
+ */
59
+ import { useCallback, useMemo, useState } from '@wordpress/element';
60
+
61
+ export enum Month {
62
+ JANUARY,
63
+ FEBRUARY,
64
+ MARCH,
65
+ APRIL,
66
+ MAY,
67
+ JUNE,
68
+ JULY,
69
+ AUGUST,
70
+ SEPTEMBER,
71
+ OCTOBER,
72
+ NOVEMBER,
73
+ DECEMBER,
74
+ }
75
+
76
+ export enum Day {
77
+ SUNDAY,
78
+ MONDAY,
79
+ TUESDAY,
80
+ WEDNESDAY,
81
+ THURSDAY,
82
+ FRIDAY,
83
+ SATURDAY,
84
+ }
85
+
86
+ export interface Options {
87
+ /**
88
+ * What day a week starts on within the calendar matrix.
89
+ *
90
+ * @default Day.SUNDAY
91
+ */
92
+ weekStartsOn?: Day;
93
+
94
+ /**
95
+ * The initial viewing date.
96
+ *
97
+ * @default new Date()
98
+ */
99
+ viewing?: Date;
100
+
101
+ /**
102
+ * The initial date(s) selection.
103
+ *
104
+ * @default []
105
+ */
106
+ selected?: Date[];
107
+
108
+ /**
109
+ * The number of months in the calendar.
110
+ *
111
+ * @default 1
112
+ */
113
+ numberOfMonths?: number;
114
+ }
115
+
116
+ export interface Returns {
117
+ /**
118
+ * Returns a copy of the given date with the time set to 00:00:00:00.
119
+ */
120
+ clearTime: ( date: Date ) => Date;
121
+
122
+ /**
123
+ * Returns whether or not a date is between 2 other dates (inclusive).
124
+ */
125
+ inRange: ( date: Date, min: Date, max: Date ) => boolean;
126
+
127
+ /**
128
+ * The date represented in the calendar matrix. Note that
129
+ * the month and year are the only parts used.
130
+ */
131
+ viewing: Date;
132
+
133
+ /**
134
+ * Set the date represented in the calendar matrix. Note that
135
+ * the month and year are the only parts used.
136
+ */
137
+ setViewing: React.Dispatch< React.SetStateAction< Date > >;
138
+
139
+ /**
140
+ * Set the viewing date to today.
141
+ */
142
+ viewToday: () => void;
143
+
144
+ /**
145
+ * Set the viewing date to the given month.
146
+ */
147
+ viewMonth: ( month: Month ) => void;
148
+
149
+ /**
150
+ * Set the viewing date to the month before the current.
151
+ */
152
+ viewPreviousMonth: () => void;
153
+
154
+ /**
155
+ * Set the viewing date to the month after the current.
156
+ */
157
+ viewNextMonth: () => void;
158
+
159
+ /**
160
+ * Set the viewing date to the given year.
161
+ */
162
+ viewYear: ( year: number ) => void;
163
+
164
+ /**
165
+ * Set the viewing date to the year before the current.
166
+ */
167
+ viewPreviousYear: () => void;
168
+
169
+ /**
170
+ * Set the viewing date to the year after the current.
171
+ */
172
+ viewNextYear: () => void;
173
+
174
+ /**
175
+ * The dates currently selected.
176
+ */
177
+ selected: Date[];
178
+
179
+ /**
180
+ * Override the currently selected dates.
181
+ */
182
+ setSelected: React.Dispatch< React.SetStateAction< Date[] > >;
183
+
184
+ /**
185
+ * Reset the selected dates to [].
186
+ */
187
+ clearSelected: () => void;
188
+
189
+ /**
190
+ * Determine whether or not a date has been selected.
191
+ */
192
+ isSelected: ( date: Date ) => boolean;
193
+
194
+ /**
195
+ * Select one or more dates.
196
+ */
197
+ select: ( date: Date | Date[], replaceExisting?: boolean ) => void;
198
+
199
+ /**
200
+ * Deselect one or more dates.
201
+ */
202
+ deselect: ( date: Date | Date[] ) => void;
203
+
204
+ /**
205
+ * Toggle the selection of a date.
206
+ */
207
+ toggle: ( date: Date, replaceExisting?: boolean ) => void;
208
+
209
+ /**
210
+ * Select a range of dates (inclusive).
211
+ */
212
+ selectRange: ( start: Date, end: Date, replaceExisting?: boolean ) => void;
213
+
214
+ /**
215
+ * Deselect a range of dates (inclusive).
216
+ */
217
+ deselectRange: ( start: Date, end: Date ) => void;
218
+
219
+ /**
220
+ * A matrix of days based on the current viewing date.
221
+ */
222
+ calendar: Date[][][];
223
+ }
224
+
225
+ const inRange = ( date: Date, min: Date, max: Date ) =>
226
+ ( isEqual( date, min ) || isAfter( date, min ) ) &&
227
+ ( isEqual( date, max ) || isBefore( date, max ) );
228
+
229
+ const clearTime = ( date: Date ) =>
230
+ set( date, { hours: 0, minutes: 0, seconds: 0, milliseconds: 0 } );
231
+
232
+ export const useLilius = ( {
233
+ weekStartsOn = Day.SUNDAY,
234
+ viewing: initialViewing = new Date(),
235
+ selected: initialSelected = [],
236
+ numberOfMonths = 1,
237
+ }: Options = {} ): Returns => {
238
+ const [ viewing, setViewing ] = useState< Date >( initialViewing );
239
+
240
+ const viewToday = useCallback(
241
+ () => setViewing( startOfToday() ),
242
+ [ setViewing ]
243
+ );
244
+
245
+ const viewMonth = useCallback(
246
+ ( month: Month ) => setViewing( ( v ) => setMonth( v, month ) ),
247
+ []
248
+ );
249
+
250
+ const viewPreviousMonth = useCallback(
251
+ () => setViewing( ( v ) => subMonths( v, 1 ) ),
252
+ []
253
+ );
254
+
255
+ const viewNextMonth = useCallback(
256
+ () => setViewing( ( v ) => addMonths( v, 1 ) ),
257
+ []
258
+ );
259
+
260
+ const viewYear = useCallback(
261
+ ( year: number ) => setViewing( ( v ) => setYear( v, year ) ),
262
+ []
263
+ );
264
+
265
+ const viewPreviousYear = useCallback(
266
+ () => setViewing( ( v ) => subYears( v, 1 ) ),
267
+ []
268
+ );
269
+
270
+ const viewNextYear = useCallback(
271
+ () => setViewing( ( v ) => addYears( v, 1 ) ),
272
+ []
273
+ );
274
+
275
+ const [ selected, setSelected ] = useState< Date[] >(
276
+ initialSelected.map( clearTime )
277
+ );
278
+
279
+ const clearSelected = () => setSelected( [] );
280
+
281
+ const isSelected = useCallback(
282
+ ( date: Date ) =>
283
+ selected.findIndex( ( s ) => isEqual( s, date ) ) > -1,
284
+ [ selected ]
285
+ );
286
+
287
+ const select = useCallback(
288
+ ( date: Date | Date[], replaceExisting?: boolean ) => {
289
+ if ( replaceExisting ) {
290
+ setSelected( Array.isArray( date ) ? date : [ date ] );
291
+ } else {
292
+ setSelected( ( selectedItems ) =>
293
+ selectedItems.concat(
294
+ Array.isArray( date ) ? date : [ date ]
295
+ )
296
+ );
297
+ }
298
+ },
299
+ []
300
+ );
301
+
302
+ const deselect = useCallback(
303
+ ( date: Date | Date[] ) =>
304
+ setSelected( ( selectedItems ) =>
305
+ Array.isArray( date )
306
+ ? selectedItems.filter(
307
+ ( s ) =>
308
+ ! date
309
+ .map( ( d ) => d.getTime() )
310
+ .includes( s.getTime() )
311
+ )
312
+ : selectedItems.filter( ( s ) => ! isEqual( s, date ) )
313
+ ),
314
+ []
315
+ );
316
+
317
+ const toggle = useCallback(
318
+ ( date: Date, replaceExisting?: boolean ) =>
319
+ isSelected( date )
320
+ ? deselect( date )
321
+ : select( date, replaceExisting ),
322
+ [ deselect, isSelected, select ]
323
+ );
324
+
325
+ const selectRange = useCallback(
326
+ ( start: Date, end: Date, replaceExisting?: boolean ) => {
327
+ if ( replaceExisting ) {
328
+ setSelected( eachDayOfInterval( { start, end } ) );
329
+ } else {
330
+ setSelected( ( selectedItems ) =>
331
+ selectedItems.concat( eachDayOfInterval( { start, end } ) )
332
+ );
333
+ }
334
+ },
335
+ []
336
+ );
337
+
338
+ const deselectRange = useCallback( ( start: Date, end: Date ) => {
339
+ setSelected( ( selectedItems ) =>
340
+ selectedItems.filter(
341
+ ( s ) =>
342
+ ! eachDayOfInterval( { start, end } )
343
+ .map( ( d ) => d.getTime() )
344
+ .includes( s.getTime() )
345
+ )
346
+ );
347
+ }, [] );
348
+
349
+ const calendar = useMemo< Date[][][] >(
350
+ () =>
351
+ eachMonthOfInterval( {
352
+ start: startOfMonth( viewing ),
353
+ end: endOfMonth( addMonths( viewing, numberOfMonths - 1 ) ),
354
+ } ).map( ( month ) =>
355
+ eachWeekOfInterval(
356
+ {
357
+ start: startOfMonth( month ),
358
+ end: endOfMonth( month ),
359
+ },
360
+ { weekStartsOn }
361
+ ).map( ( week ) =>
362
+ eachDayOfInterval( {
363
+ start: startOfWeek( week, { weekStartsOn } ),
364
+ end: endOfWeek( week, { weekStartsOn } ),
365
+ } )
366
+ )
367
+ ),
368
+ [ viewing, weekStartsOn, numberOfMonths ]
369
+ );
370
+
371
+ return {
372
+ clearTime,
373
+ inRange,
374
+ viewing,
375
+ setViewing,
376
+ viewToday,
377
+ viewMonth,
378
+ viewPreviousMonth,
379
+ viewNextMonth,
380
+ viewYear,
381
+ viewPreviousYear,
382
+ viewNextYear,
383
+ selected,
384
+ setSelected,
385
+ clearSelected,
386
+ isSelected,
387
+ select,
388
+ deselect,
389
+ toggle,
390
+ selectRange,
391
+ deselectRange,
392
+ calendar,
393
+ };
394
+ };
@@ -37,7 +37,7 @@ const DIVIDER_COLOR = COLORS.theme.gray[ 200 ];
37
37
  const LIGHTER_TEXT_COLOR = COLORS.theme.gray[ 700 ];
38
38
  const LIGHT_BACKGROUND_COLOR = COLORS.theme.gray[ 100 ];
39
39
  const TOOLBAR_VARIANT_BORDER_COLOR = COLORS.theme.foreground;
40
- const DEFAULT_BOX_SHADOW = `0 0 0 ${ CONFIG.borderWidth } ${ DEFAULT_BORDER_COLOR }, ${ CONFIG.elevationXSmall }`;
40
+ const DEFAULT_BOX_SHADOW = `0 0 0 ${ CONFIG.borderWidth } ${ DEFAULT_BORDER_COLOR }, ${ CONFIG.elevationMedium }`;
41
41
  const TOOLBAR_VARIANT_BOX_SHADOW = `0 0 0 ${ CONFIG.borderWidth } ${ TOOLBAR_VARIANT_BORDER_COLOR }`;
42
42
 
43
43
  const GRID_TEMPLATE_COLS = 'minmax( 0, max-content ) 1fr';
@@ -60,6 +60,7 @@ $transition-duration: 0.2s;
60
60
  $transition-duration background-color ease-out;
61
61
  @include reduce-motion("transition");
62
62
  background-color: $gray-900;
63
+ box-shadow: $elevation-x-small;
63
64
 
64
65
  // Transparent border acts as a fill in Windows High Contrast Mode.
65
66
  border: math.div($toggle-thumb-size, 2) solid transparent;
package/src/index.ts CHANGED
@@ -66,6 +66,7 @@ export {
66
66
  CompositeItem as __unstableCompositeItem,
67
67
  useCompositeState as __unstableUseCompositeState,
68
68
  } from './composite/legacy';
69
+ export { Composite } from './composite';
69
70
  export { ConfirmDialog as __experimentalConfirmDialog } from './confirm-dialog';
70
71
  export { default as CustomSelectControl } from './custom-select-control';
71
72
  export { default as Dashicon } from './dashicon';
@@ -2,7 +2,6 @@
2
2
  * External dependencies
3
3
  */
4
4
  import clsx from 'clsx';
5
- import type { ForwardedRef, KeyboardEvent, RefObject, UIEvent } from 'react';
6
5
 
7
6
  /**
8
7
  * WordPress dependencies
@@ -37,10 +36,12 @@ import Button from '../button';
37
36
  import StyleProvider from '../style-provider';
38
37
  import type { ModalProps } from './types';
39
38
  import { withIgnoreIMEEvents } from '../utils/with-ignore-ime-events';
39
+ import { Spacer } from '../spacer';
40
+ import { useModalExitAnimation } from './use-modal-exit-animation';
40
41
 
41
42
  // Used to track and dismiss the prior modal when another opens unless nested.
42
43
  type Dismissers = Set<
43
- RefObject< ModalProps[ 'onRequestClose' ] | undefined >
44
+ React.RefObject< ModalProps[ 'onRequestClose' ] | undefined >
44
45
  >;
45
46
  const ModalContext = createContext< Dismissers >( new Set() );
46
47
 
@@ -49,7 +50,7 @@ const bodyOpenClasses = new Map< string, number >();
49
50
 
50
51
  function UnforwardedModal(
51
52
  props: ModalProps,
52
- forwardedRef: ForwardedRef< HTMLDivElement >
53
+ forwardedRef: React.ForwardedRef< HTMLDivElement >
53
54
  ) {
54
55
  const {
55
56
  bodyOpenClassName = 'modal-open',
@@ -69,7 +70,7 @@ function UnforwardedModal(
69
70
  closeButtonLabel,
70
71
  children,
71
72
  style,
72
- overlayClassName,
73
+ overlayClassName: overlayClassnameProp,
73
74
  className,
74
75
  contentLabel,
75
76
  onKeyDown,
@@ -183,6 +184,9 @@ function UnforwardedModal(
183
184
  };
184
185
  }, [ bodyOpenClassName ] );
185
186
 
187
+ const { closeModal, frameRef, frameStyle, overlayClassname } =
188
+ useModalExitAnimation();
189
+
186
190
  // Calls the isContentScrollable callback when the Modal children container resizes.
187
191
  useLayoutEffect( () => {
188
192
  if ( ! window.ResizeObserver || ! childrenContainerRef.current ) {
@@ -199,21 +203,21 @@ function UnforwardedModal(
199
203
  };
200
204
  }, [ isContentScrollable, childrenContainerRef ] );
201
205
 
202
- function handleEscapeKeyDown( event: KeyboardEvent< HTMLDivElement > ) {
206
+ function handleEscapeKeyDown(
207
+ event: React.KeyboardEvent< HTMLDivElement >
208
+ ) {
203
209
  if (
204
210
  shouldCloseOnEsc &&
205
211
  ( event.code === 'Escape' || event.key === 'Escape' ) &&
206
212
  ! event.defaultPrevented
207
213
  ) {
208
214
  event.preventDefault();
209
- if ( onRequestClose ) {
210
- onRequestClose( event );
211
- }
215
+ closeModal().then( () => onRequestClose( event ) );
212
216
  }
213
217
  }
214
218
 
215
219
  const onContentContainerScroll = useCallback(
216
- ( e: UIEvent< HTMLDivElement > ) => {
220
+ ( e: React.UIEvent< HTMLDivElement > ) => {
217
221
  const scrollY = e?.currentTarget?.scrollTop ?? -1;
218
222
 
219
223
  if ( ! hasScrolledContent && scrollY > 0 ) {
@@ -247,7 +251,7 @@ function UnforwardedModal(
247
251
  const isSameTarget = target === pressTarget;
248
252
  pressTarget = null;
249
253
  if ( button === 0 && isSameTarget ) {
250
- onRequestClose();
254
+ closeModal().then( () => onRequestClose() );
251
255
  }
252
256
  },
253
257
  };
@@ -258,7 +262,8 @@ function UnforwardedModal(
258
262
  ref={ useMergeRefs( [ ref, forwardedRef ] ) }
259
263
  className={ clsx(
260
264
  'components-modal__screen-overlay',
261
- overlayClassName
265
+ overlayClassname,
266
+ overlayClassnameProp
262
267
  ) }
263
268
  onKeyDown={ withIgnoreIMEEvents( handleEscapeKeyDown ) }
264
269
  { ...( shouldCloseOnClickOutside ? overlayPressHandlers : {} ) }
@@ -270,8 +275,12 @@ function UnforwardedModal(
270
275
  sizeClass,
271
276
  className
272
277
  ) }
273
- style={ style }
278
+ style={ {
279
+ ...frameStyle,
280
+ ...style,
281
+ } }
274
282
  ref={ useMergeRefs( [
283
+ frameRef,
275
284
  constrainedTabbingRef,
276
285
  focusReturnRef,
277
286
  focusOnMount !== 'firstContentElement'
@@ -323,13 +332,27 @@ function UnforwardedModal(
323
332
  </div>
324
333
  { headerActions }
325
334
  { isDismissible && (
326
- <Button
327
- onClick={ onRequestClose }
328
- icon={ close }
329
- label={
330
- closeButtonLabel || __( 'Close' )
331
- }
332
- />
335
+ <>
336
+ <Spacer
337
+ marginBottom={ 0 }
338
+ marginLeft={ 3 }
339
+ />
340
+ <Button
341
+ size="small"
342
+ onClick={ (
343
+ event: React.MouseEvent< HTMLButtonElement >
344
+ ) =>
345
+ closeModal().then( () =>
346
+ onRequestClose( event )
347
+ )
348
+ }
349
+ icon={ close }
350
+ label={
351
+ closeButtonLabel ||
352
+ __( 'Close' )
353
+ }
354
+ />
355
+ </>
333
356
  ) }
334
357
  </div>
335
358
  ) }
@@ -7,7 +7,7 @@ import type { StoryFn, Meta } from '@storybook/react';
7
7
  * WordPress dependencies
8
8
  */
9
9
  import { useState } from '@wordpress/element';
10
- import { starEmpty, starFilled } from '@wordpress/icons';
10
+ import { fullscreen } from '@wordpress/icons';
11
11
 
12
12
  /**
13
13
  * Internal dependencies
@@ -103,22 +103,16 @@ WithsizeSmall.args = {
103
103
  };
104
104
  WithsizeSmall.storyName = 'With size: small';
105
105
 
106
- const LikeButton = () => {
107
- const [ isLiked, setIsLiked ] = useState( false );
108
- return (
109
- <Button
110
- icon={ isLiked ? starFilled : starEmpty }
111
- label="Like"
112
- onClick={ () => setIsLiked( ! isLiked ) }
113
- />
114
- );
115
- };
116
-
106
+ /**
107
+ * The `headerActions` prop can be used to add auxiliary actions to the header, for example a fullscreen mode toggle.
108
+ */
117
109
  export const WithHeaderActions: StoryFn< typeof Modal > = Template.bind( {} );
118
110
  WithHeaderActions.args = {
119
111
  ...Default.args,
120
- headerActions: <LikeButton />,
121
- isDismissible: false,
112
+ headerActions: (
113
+ <Button icon={ fullscreen } label="Fullscreen mode" size="small" />
114
+ ),
115
+ children: <div style={ { height: '200px' } } />,
122
116
  };
123
117
  WithHeaderActions.parameters = {
124
118
  ...Default.parameters,
@@ -8,8 +8,15 @@
8
8
  background-color: rgba($black, 0.35);
9
9
  z-index: z-index(".components-modal__screen-overlay");
10
10
  display: flex;
11
- // This animates the appearance of the white background.
12
- @include edit-post__fade-in-animation();
11
+ // This animates the appearance of the backdrop.
12
+ @include animation__fade-in();
13
+
14
+ &.is-animating-out {
15
+ // Note: it's important that the fade-out animation doesn't end after the
16
+ // modal frame's disappear animation, because the component will be removed
17
+ // from the DOM when that animation ends.
18
+ @include animation__fade-out($delay: 80ms);
19
+ }
13
20
  }
14
21
 
15
22
  // The modal window element.
@@ -25,10 +32,17 @@
25
32
  // Have the content element fill the vertical space yet not overflow.
26
33
  display: flex;
27
34
  // Animate the modal frame/contents appearing on the page.
28
- animation: components-modal__appear-animation 0.26s cubic-bezier(0.29, 0, 0, 1);
35
+ animation-name: components-modal__appear-animation;
36
+ animation-duration: var(--modal-frame-animation-duration);
29
37
  animation-fill-mode: forwards;
38
+ animation-timing-function: cubic-bezier(0.29, 0, 0, 1);
30
39
  @include reduce-motion("animation");
31
40
 
41
+ .components-modal__screen-overlay.is-animating-out & {
42
+ animation-name: components-modal__disappear-animation;
43
+ animation-timing-function: cubic-bezier(1, 0, 0.2, 1);
44
+ }
45
+
32
46
  // Show a centered modal on bigger screens.
33
47
  @include break-small() {
34
48
  border-radius: $radius-large;
@@ -88,6 +102,19 @@
88
102
  }
89
103
  }
90
104
 
105
+ // Note: this animation is also used in the animationend JS event listener.
106
+ // Make sure that the animation name is kept in sync across the two files.
107
+ @keyframes components-modal__disappear-animation {
108
+ from {
109
+ opacity: 1;
110
+ transform: scale(1);
111
+ }
112
+ to {
113
+ opacity: 0;
114
+ transform: scale(0.9);
115
+ }
116
+ }
117
+
91
118
  // Fix header to the top so it is always there to provide context to the modal
92
119
  // if the content needs to be scrolled (for example, on the keyboard shortcuts
93
120
  // modal screen).
@@ -116,11 +143,6 @@
116
143
  margin: 0;
117
144
  }
118
145
 
119
- .components-button {
120
- position: relative;
121
- left: $grid-unit-10;
122
- }
123
-
124
146
  .components-modal__content.has-scrolled-content:not(.hide-header) & {
125
147
  border-bottom-color: $gray-300;
126
148
  }