@transferwise/components 46.144.1 → 46.146.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 (209) hide show
  1. package/build/calendar/Calendar.js +159 -0
  2. package/build/calendar/Calendar.js.map +1 -0
  3. package/build/{dateLookup/DateLookup.messages.js → calendar/Calendar.messages.js} +1 -1
  4. package/build/calendar/Calendar.messages.js.map +1 -0
  5. package/build/{dateLookup/DateLookup.messages.mjs → calendar/Calendar.messages.mjs} +1 -1
  6. package/build/calendar/Calendar.messages.mjs.map +1 -0
  7. package/build/calendar/Calendar.mjs +155 -0
  8. package/build/calendar/Calendar.mjs.map +1 -0
  9. package/build/{dateLookup → calendar}/dateHeader/DateHeader.js +4 -4
  10. package/build/calendar/dateHeader/DateHeader.js.map +1 -0
  11. package/build/{dateLookup → calendar}/dateHeader/DateHeader.mjs +1 -1
  12. package/build/calendar/dateHeader/DateHeader.mjs.map +1 -0
  13. package/build/{dateLookup → calendar}/dayCalendar/DayCalendar.js +2 -2
  14. package/build/calendar/dayCalendar/DayCalendar.js.map +1 -0
  15. package/build/{dateLookup → calendar}/dayCalendar/DayCalendar.mjs +1 -1
  16. package/build/calendar/dayCalendar/DayCalendar.mjs.map +1 -0
  17. package/build/calendar/dayCalendar/table/DayCalendarTable.js.map +1 -0
  18. package/build/calendar/dayCalendar/table/DayCalendarTable.mjs.map +1 -0
  19. package/build/calendar/getFocusableTime/getFocusableTime.js.map +1 -0
  20. package/build/calendar/getFocusableTime/getFocusableTime.mjs.map +1 -0
  21. package/build/calendar/getStartOfDay/getStartOfDay.js.map +1 -0
  22. package/build/calendar/getStartOfDay/getStartOfDay.mjs.map +1 -0
  23. package/build/{dateLookup → calendar}/monthCalendar/MonthCalendar.js +2 -2
  24. package/build/calendar/monthCalendar/MonthCalendar.js.map +1 -0
  25. package/build/{dateLookup → calendar}/monthCalendar/MonthCalendar.mjs +1 -1
  26. package/build/calendar/monthCalendar/MonthCalendar.mjs.map +1 -0
  27. package/build/calendar/monthCalendar/table/MonthCalendarTable.js.map +1 -0
  28. package/build/calendar/monthCalendar/table/MonthCalendarTable.mjs.map +1 -0
  29. package/build/{dateLookup → calendar}/tableLink/TableLink.js +2 -2
  30. package/build/calendar/tableLink/TableLink.js.map +1 -0
  31. package/build/{dateLookup → calendar}/tableLink/TableLink.mjs +1 -1
  32. package/build/calendar/tableLink/TableLink.mjs.map +1 -0
  33. package/build/{dateLookup → calendar}/yearCalendar/YearCalendar.js +2 -2
  34. package/build/calendar/yearCalendar/YearCalendar.js.map +1 -0
  35. package/build/{dateLookup → calendar}/yearCalendar/YearCalendar.mjs +1 -1
  36. package/build/calendar/yearCalendar/YearCalendar.mjs.map +1 -0
  37. package/build/calendar/yearCalendar/table/YearCalendarTable.js.map +1 -0
  38. package/build/calendar/yearCalendar/table/YearCalendarTable.mjs.map +1 -0
  39. package/build/dateLookup/DateLookup.js +28 -168
  40. package/build/dateLookup/DateLookup.js.map +1 -1
  41. package/build/dateLookup/DateLookup.mjs +29 -169
  42. package/build/dateLookup/DateLookup.mjs.map +1 -1
  43. package/build/index.js +2 -0
  44. package/build/index.js.map +1 -1
  45. package/build/index.mjs +1 -0
  46. package/build/index.mjs.map +1 -1
  47. package/build/main.css +624 -688
  48. package/build/prompt/InfoPrompt/InfoPrompt.js +1 -1
  49. package/build/prompt/InfoPrompt/InfoPrompt.js.map +1 -1
  50. package/build/prompt/InfoPrompt/InfoPrompt.mjs +2 -2
  51. package/build/prompt/InfoPrompt/InfoPrompt.mjs.map +1 -1
  52. package/build/sentimentSurface/SentimentSurface.js +9 -2
  53. package/build/sentimentSurface/SentimentSurface.js.map +1 -1
  54. package/build/sentimentSurface/SentimentSurface.mjs +9 -2
  55. package/build/sentimentSurface/SentimentSurface.mjs.map +1 -1
  56. package/build/styles/calendar/Calendar.css +83 -0
  57. package/build/styles/dateLookup/DateLookup.css +0 -90
  58. package/build/styles/main.css +624 -688
  59. package/build/styles/sentimentSurface/SentimentSurface.css +325 -337
  60. package/build/types/calendar/Calendar.d.ts +13 -0
  61. package/build/types/calendar/Calendar.d.ts.map +1 -0
  62. package/build/types/{dateLookup/DateLookup.messages.d.ts → calendar/Calendar.messages.d.ts} +1 -1
  63. package/build/types/calendar/Calendar.messages.d.ts.map +1 -0
  64. package/build/types/calendar/dateHeader/DateHeader.d.ts.map +1 -0
  65. package/build/types/calendar/dateHeader/index.d.ts.map +1 -0
  66. package/build/types/calendar/dayCalendar/DayCalendar.d.ts.map +1 -0
  67. package/build/types/calendar/dayCalendar/index.d.ts.map +1 -0
  68. package/build/types/calendar/dayCalendar/table/DayCalendarTable.d.ts.map +1 -0
  69. package/build/types/calendar/dayCalendar/table/index.d.ts.map +1 -0
  70. package/build/types/calendar/getFocusableTime/getFocusableTime.d.ts.map +1 -0
  71. package/build/types/calendar/getStartOfDay/getStartOfDay.d.ts.map +1 -0
  72. package/build/types/calendar/getStartOfDay/index.d.ts.map +1 -0
  73. package/build/types/calendar/index.d.ts +3 -0
  74. package/build/types/calendar/index.d.ts.map +1 -0
  75. package/build/types/{dateLookup → calendar}/monthCalendar/MonthCalendar.d.ts +1 -1
  76. package/build/types/calendar/monthCalendar/MonthCalendar.d.ts.map +1 -0
  77. package/build/types/calendar/monthCalendar/index.d.ts.map +1 -0
  78. package/build/types/{dateLookup → calendar}/monthCalendar/table/MonthCalendarTable.d.ts +1 -1
  79. package/build/types/calendar/monthCalendar/table/MonthCalendarTable.d.ts.map +1 -0
  80. package/build/types/calendar/monthCalendar/table/index.d.ts.map +1 -0
  81. package/build/types/calendar/tableLink/TableLink.d.ts.map +1 -0
  82. package/build/types/calendar/tableLink/index.d.ts.map +1 -0
  83. package/build/types/{dateLookup → calendar}/yearCalendar/YearCalendar.d.ts +1 -1
  84. package/build/types/calendar/yearCalendar/YearCalendar.d.ts.map +1 -0
  85. package/build/types/calendar/yearCalendar/index.d.ts.map +1 -0
  86. package/build/types/{dateLookup → calendar}/yearCalendar/table/YearCalendarTable.d.ts +1 -1
  87. package/build/types/calendar/yearCalendar/table/YearCalendarTable.d.ts.map +1 -0
  88. package/build/types/calendar/yearCalendar/table/index.d.ts.map +1 -0
  89. package/build/types/dateLookup/DateLookup.d.ts +2 -26
  90. package/build/types/dateLookup/DateLookup.d.ts.map +1 -1
  91. package/build/types/index.d.ts +2 -0
  92. package/build/types/index.d.ts.map +1 -1
  93. package/build/types/prompt/InfoPrompt/InfoPrompt.d.ts +3 -2
  94. package/build/types/prompt/InfoPrompt/InfoPrompt.d.ts.map +1 -1
  95. package/build/types/sentimentSurface/SentimentSurface.d.ts.map +1 -1
  96. package/package.json +2 -2
  97. package/src/calendar/Calendar.css +83 -0
  98. package/src/calendar/Calendar.less +79 -0
  99. package/src/calendar/Calendar.story.tsx +92 -0
  100. package/src/calendar/Calendar.test.tsx +138 -0
  101. package/src/calendar/Calendar.tsx +165 -0
  102. package/src/{dateLookup → calendar}/dateHeader/DateHeader.tsx +1 -1
  103. package/src/{dateLookup → calendar}/dayCalendar/DayCalendar.tsx +1 -1
  104. package/src/calendar/index.ts +2 -0
  105. package/src/{dateLookup → calendar}/monthCalendar/MonthCalendar.tsx +2 -2
  106. package/src/{dateLookup → calendar}/monthCalendar/table/MonthCalendarTable.tsx +1 -1
  107. package/src/{dateLookup → calendar}/tableLink/TableLink.tsx +1 -1
  108. package/src/{dateLookup → calendar}/yearCalendar/YearCalendar.tsx +2 -2
  109. package/src/{dateLookup → calendar}/yearCalendar/table/YearCalendarTable.tsx +1 -1
  110. package/src/criticalBanner/CriticalCommsBanner.test.tsx +1 -1
  111. package/src/dateLookup/DateLookup.css +0 -90
  112. package/src/dateLookup/DateLookup.less +0 -91
  113. package/src/dateLookup/DateLookup.test.tsx +0 -124
  114. package/src/dateLookup/DateLookup.tsx +31 -161
  115. package/src/index.ts +2 -0
  116. package/src/main.css +624 -688
  117. package/src/main.less +1 -0
  118. package/src/prompt/InfoPrompt/InfoPrompt.story.tsx +42 -0
  119. package/src/prompt/InfoPrompt/InfoPrompt.test.tsx +65 -1
  120. package/src/prompt/InfoPrompt/InfoPrompt.tsx +15 -4
  121. package/src/sentimentSurface/SentimentSurface.css +325 -337
  122. package/src/sentimentSurface/SentimentSurface.docs.mdx +2 -0
  123. package/src/sentimentSurface/SentimentSurface.less +2 -322
  124. package/src/sentimentSurface/SentimentSurface.story.tsx +4 -0
  125. package/src/sentimentSurface/SentimentSurface.test.story.tsx +1 -5
  126. package/src/sentimentSurface/SentimentSurface.test.tsx +84 -3
  127. package/src/sentimentSurface/SentimentSurface.tsx +10 -2
  128. package/build/dateLookup/DateLookup.messages.js.map +0 -1
  129. package/build/dateLookup/DateLookup.messages.mjs.map +0 -1
  130. package/build/dateLookup/dateHeader/DateHeader.js.map +0 -1
  131. package/build/dateLookup/dateHeader/DateHeader.mjs.map +0 -1
  132. package/build/dateLookup/dayCalendar/DayCalendar.js.map +0 -1
  133. package/build/dateLookup/dayCalendar/DayCalendar.mjs.map +0 -1
  134. package/build/dateLookup/dayCalendar/table/DayCalendarTable.js.map +0 -1
  135. package/build/dateLookup/dayCalendar/table/DayCalendarTable.mjs.map +0 -1
  136. package/build/dateLookup/getFocusableTime/getFocusableTime.js.map +0 -1
  137. package/build/dateLookup/getFocusableTime/getFocusableTime.mjs.map +0 -1
  138. package/build/dateLookup/getStartOfDay/getStartOfDay.js.map +0 -1
  139. package/build/dateLookup/getStartOfDay/getStartOfDay.mjs.map +0 -1
  140. package/build/dateLookup/monthCalendar/MonthCalendar.js.map +0 -1
  141. package/build/dateLookup/monthCalendar/MonthCalendar.mjs.map +0 -1
  142. package/build/dateLookup/monthCalendar/table/MonthCalendarTable.js.map +0 -1
  143. package/build/dateLookup/monthCalendar/table/MonthCalendarTable.mjs.map +0 -1
  144. package/build/dateLookup/tableLink/TableLink.js.map +0 -1
  145. package/build/dateLookup/tableLink/TableLink.mjs.map +0 -1
  146. package/build/dateLookup/yearCalendar/YearCalendar.js.map +0 -1
  147. package/build/dateLookup/yearCalendar/YearCalendar.mjs.map +0 -1
  148. package/build/dateLookup/yearCalendar/table/YearCalendarTable.js.map +0 -1
  149. package/build/dateLookup/yearCalendar/table/YearCalendarTable.mjs.map +0 -1
  150. package/build/types/dateLookup/DateLookup.messages.d.ts.map +0 -1
  151. package/build/types/dateLookup/dateHeader/DateHeader.d.ts.map +0 -1
  152. package/build/types/dateLookup/dateHeader/index.d.ts.map +0 -1
  153. package/build/types/dateLookup/dayCalendar/DayCalendar.d.ts.map +0 -1
  154. package/build/types/dateLookup/dayCalendar/index.d.ts.map +0 -1
  155. package/build/types/dateLookup/dayCalendar/table/DayCalendarTable.d.ts.map +0 -1
  156. package/build/types/dateLookup/dayCalendar/table/index.d.ts.map +0 -1
  157. package/build/types/dateLookup/getFocusableTime/getFocusableTime.d.ts.map +0 -1
  158. package/build/types/dateLookup/getStartOfDay/getStartOfDay.d.ts.map +0 -1
  159. package/build/types/dateLookup/getStartOfDay/index.d.ts.map +0 -1
  160. package/build/types/dateLookup/monthCalendar/MonthCalendar.d.ts.map +0 -1
  161. package/build/types/dateLookup/monthCalendar/index.d.ts.map +0 -1
  162. package/build/types/dateLookup/monthCalendar/table/MonthCalendarTable.d.ts.map +0 -1
  163. package/build/types/dateLookup/monthCalendar/table/index.d.ts.map +0 -1
  164. package/build/types/dateLookup/tableLink/TableLink.d.ts.map +0 -1
  165. package/build/types/dateLookup/tableLink/index.d.ts.map +0 -1
  166. package/build/types/dateLookup/yearCalendar/YearCalendar.d.ts.map +0 -1
  167. package/build/types/dateLookup/yearCalendar/index.d.ts.map +0 -1
  168. package/build/types/dateLookup/yearCalendar/table/YearCalendarTable.d.ts.map +0 -1
  169. package/build/types/dateLookup/yearCalendar/table/index.d.ts.map +0 -1
  170. /package/build/{dateLookup → calendar}/dayCalendar/table/DayCalendarTable.js +0 -0
  171. /package/build/{dateLookup → calendar}/dayCalendar/table/DayCalendarTable.mjs +0 -0
  172. /package/build/{dateLookup → calendar}/getFocusableTime/getFocusableTime.js +0 -0
  173. /package/build/{dateLookup → calendar}/getFocusableTime/getFocusableTime.mjs +0 -0
  174. /package/build/{dateLookup → calendar}/getStartOfDay/getStartOfDay.js +0 -0
  175. /package/build/{dateLookup → calendar}/getStartOfDay/getStartOfDay.mjs +0 -0
  176. /package/build/{dateLookup → calendar}/monthCalendar/table/MonthCalendarTable.js +0 -0
  177. /package/build/{dateLookup → calendar}/monthCalendar/table/MonthCalendarTable.mjs +0 -0
  178. /package/build/{dateLookup → calendar}/yearCalendar/table/YearCalendarTable.js +0 -0
  179. /package/build/{dateLookup → calendar}/yearCalendar/table/YearCalendarTable.mjs +0 -0
  180. /package/build/types/{dateLookup → calendar}/dateHeader/DateHeader.d.ts +0 -0
  181. /package/build/types/{dateLookup → calendar}/dateHeader/index.d.ts +0 -0
  182. /package/build/types/{dateLookup → calendar}/dayCalendar/DayCalendar.d.ts +0 -0
  183. /package/build/types/{dateLookup → calendar}/dayCalendar/index.d.ts +0 -0
  184. /package/build/types/{dateLookup → calendar}/dayCalendar/table/DayCalendarTable.d.ts +0 -0
  185. /package/build/types/{dateLookup → calendar}/dayCalendar/table/index.d.ts +0 -0
  186. /package/build/types/{dateLookup → calendar}/getFocusableTime/getFocusableTime.d.ts +0 -0
  187. /package/build/types/{dateLookup → calendar}/getStartOfDay/getStartOfDay.d.ts +0 -0
  188. /package/build/types/{dateLookup → calendar}/getStartOfDay/index.d.ts +0 -0
  189. /package/build/types/{dateLookup → calendar}/monthCalendar/index.d.ts +0 -0
  190. /package/build/types/{dateLookup → calendar}/monthCalendar/table/index.d.ts +0 -0
  191. /package/build/types/{dateLookup → calendar}/tableLink/TableLink.d.ts +0 -0
  192. /package/build/types/{dateLookup → calendar}/tableLink/index.d.ts +0 -0
  193. /package/build/types/{dateLookup → calendar}/yearCalendar/index.d.ts +0 -0
  194. /package/build/types/{dateLookup → calendar}/yearCalendar/table/index.d.ts +0 -0
  195. /package/src/{dateLookup/DateLookup.messages.ts → calendar/Calendar.messages.ts} +0 -0
  196. /package/src/{dateLookup → calendar}/dateHeader/index.ts +0 -0
  197. /package/src/{dateLookup → calendar}/dayCalendar/index.ts +0 -0
  198. /package/src/{dateLookup → calendar}/dayCalendar/table/DayCalendarTable.tsx +0 -0
  199. /package/src/{dateLookup → calendar}/dayCalendar/table/index.ts +0 -0
  200. /package/src/{dateLookup → calendar}/getFocusableTime/getFocusable.test.ts +0 -0
  201. /package/src/{dateLookup → calendar}/getFocusableTime/getFocusableTime.tsx +0 -0
  202. /package/src/{dateLookup → calendar}/getStartOfDay/getStartOfDay.test.js +0 -0
  203. /package/src/{dateLookup → calendar}/getStartOfDay/getStartOfDay.tsx +0 -0
  204. /package/src/{dateLookup → calendar}/getStartOfDay/index.ts +0 -0
  205. /package/src/{dateLookup → calendar}/monthCalendar/index.ts +0 -0
  206. /package/src/{dateLookup → calendar}/monthCalendar/table/index.ts +0 -0
  207. /package/src/{dateLookup → calendar}/tableLink/index.ts +0 -0
  208. /package/src/{dateLookup → calendar}/yearCalendar/index.ts +0 -0
  209. /package/src/{dateLookup → calendar}/yearCalendar/table/index.ts +0 -0
@@ -0,0 +1,138 @@
1
+ import { mockMatchMedia, render, screen, userEvent } from '../test-utils';
2
+ import Calendar from './Calendar';
3
+
4
+ mockMatchMedia();
5
+
6
+ const user = userEvent.setup();
7
+
8
+ const initialValue = new Date(2000, 0, 1);
9
+
10
+ describe('Calendar', () => {
11
+ describe('in day view', () => {
12
+ it.each([
13
+ ['{ArrowLeft}', -1],
14
+ ['{ArrowRight}', +1],
15
+ ['{ArrowUp}', -7],
16
+ ['{ArrowDown}', +7],
17
+ ])("handles '%s' to step %d day(s)", async (text: string, step: number) => {
18
+ const handleChange = jest.fn();
19
+ render(<Calendar value={initialValue} onChange={handleChange} />);
20
+
21
+ await user.click(screen.getByRole('button', { name: /selected day/iu }));
22
+ await user.keyboard(text);
23
+
24
+ const expected = new Date(initialValue);
25
+ expected.setDate(initialValue.getDate() + step);
26
+ expect(handleChange).toHaveBeenCalledWith(expected);
27
+ });
28
+
29
+ it('selects a day on click', async () => {
30
+ const handleChange = jest.fn();
31
+ render(<Calendar value={initialValue} onChange={handleChange} />);
32
+
33
+ await user.click(screen.getByText('15'));
34
+
35
+ expect(handleChange).toHaveBeenCalledWith(new Date(2000, 0, 15));
36
+ });
37
+
38
+ it('calls onSelect instead of onChange when clicking a day', async () => {
39
+ const handleChange = jest.fn();
40
+ const handleSelect = jest.fn();
41
+ render(<Calendar value={initialValue} onChange={handleChange} onSelect={handleSelect} />);
42
+
43
+ await user.click(screen.getByText('15'));
44
+
45
+ expect(handleSelect).toHaveBeenCalledWith(new Date(2000, 0, 15));
46
+ expect(handleChange).not.toHaveBeenCalled();
47
+ });
48
+ });
49
+
50
+ describe('in year view', () => {
51
+ it.each([
52
+ ['{ArrowLeft}', -1],
53
+ ['{ArrowRight}', +1],
54
+ ['{ArrowUp}', -4],
55
+ ['{ArrowDown}', +4],
56
+ ])("handles '%s' to step %d year(s)", async (text: string, step: number) => {
57
+ const handleChange = jest.fn();
58
+ render(<Calendar value={initialValue} onChange={handleChange} />);
59
+
60
+ await user.click(screen.getByRole('button', { name: /year view/iu }));
61
+ await user.keyboard(text);
62
+
63
+ const expected = new Date(initialValue);
64
+ expected.setFullYear(initialValue.getFullYear() + step);
65
+ expect(handleChange).toHaveBeenCalledWith(expected);
66
+ });
67
+ });
68
+
69
+ describe('in month view', () => {
70
+ it.each([
71
+ ['{ArrowLeft}', -1],
72
+ ['{ArrowRight}', +1],
73
+ ['{ArrowUp}', -4],
74
+ ['{ArrowDown}', +4],
75
+ ])("handles '%s' to step %d month(s)", async (text: string, step: number) => {
76
+ const handleChange = jest.fn();
77
+ render(<Calendar value={initialValue} onChange={handleChange} />);
78
+
79
+ await user.click(screen.getByRole('button', { name: /year view/iu }));
80
+ await user.keyboard(' ');
81
+ await user.keyboard(text);
82
+
83
+ const expected = new Date(initialValue);
84
+ expected.setMonth(initialValue.getMonth() + step);
85
+ expect(handleChange).toHaveBeenCalledWith(expected);
86
+ });
87
+ });
88
+
89
+ describe('min/max clamping', () => {
90
+ it('limits navigation to min value', async () => {
91
+ const min = new Date(initialValue);
92
+ min.setDate(min.getDate() - 1);
93
+ const handleChange = jest.fn();
94
+ render(<Calendar value={initialValue} min={min} onChange={handleChange} />);
95
+
96
+ await user.click(screen.getByRole('button', { name: /selected day/iu }));
97
+ await user.keyboard('{ArrowLeft}{ArrowLeft}');
98
+
99
+ expect(handleChange).toHaveBeenLastCalledWith(min);
100
+ });
101
+
102
+ it('limits navigation to max value', async () => {
103
+ const max = new Date(initialValue);
104
+ max.setDate(max.getDate() + 1);
105
+ const handleChange = jest.fn();
106
+ render(<Calendar value={initialValue} max={max} onChange={handleChange} />);
107
+
108
+ await user.click(screen.getByRole('button', { name: /selected day/iu }));
109
+ await user.keyboard('{ArrowRight}{ArrowRight}');
110
+
111
+ expect(handleChange).toHaveBeenLastCalledWith(max);
112
+ });
113
+
114
+ it('clamps value to range when value is outside min/max', () => {
115
+ const min = new Date(2000, 0, 5);
116
+ const max = new Date(2000, 0, 20);
117
+ const handleChange = jest.fn();
118
+ render(<Calendar value={initialValue} min={min} max={max} onChange={handleChange} />);
119
+
120
+ expect(handleChange).toHaveBeenCalledWith(min);
121
+ });
122
+ });
123
+
124
+ describe('view switching', () => {
125
+ it('switches to year view and back to day view', async () => {
126
+ render(<Calendar value={initialValue} onChange={jest.fn()} />);
127
+
128
+ await user.click(screen.getByRole('button', { name: /year view/iu }));
129
+ expect(screen.getByRole('button', { name: /selected year/iu })).toBeInTheDocument();
130
+
131
+ await user.click(screen.getByRole('button', { name: /selected year/iu }));
132
+ expect(screen.getByRole('button', { name: /selected month/iu })).toBeInTheDocument();
133
+
134
+ await user.click(screen.getByRole('button', { name: /selected month/iu }));
135
+ expect(screen.getByRole('button', { name: /next month/iu })).toBeInTheDocument();
136
+ });
137
+ });
138
+ });
@@ -0,0 +1,165 @@
1
+ import { useState, useCallback, useEffect, KeyboardEvent } from 'react';
2
+
3
+ import { MonthFormat } from '../common';
4
+ import { isWithinRange, moveToWithinRange, returnDateView } from '../common/dateUtils';
5
+ import DayCalendar from './dayCalendar';
6
+ import { getStartOfDay } from './getStartOfDay';
7
+ import MonthCalendar from './monthCalendar';
8
+ import YearCalendar from './yearCalendar';
9
+
10
+ export interface CalendarProps {
11
+ value: Date | null;
12
+ min?: Date | null;
13
+ max?: Date | null;
14
+ monthFormat?: `${MonthFormat}`;
15
+ placeholder?: string;
16
+ onChange: (date: Date | null) => void;
17
+ onSelect?: (date: Date) => void;
18
+ }
19
+
20
+ const Calendar = ({
21
+ value,
22
+ min: minProp = null,
23
+ max: maxProp = null,
24
+ monthFormat = MonthFormat.LONG,
25
+ placeholder,
26
+ onChange,
27
+ onSelect,
28
+ }: CalendarProps) => {
29
+ const selectedDate = getStartOfDay(value);
30
+ const min = getStartOfDay(minProp);
31
+ const max = getStartOfDay(maxProp);
32
+
33
+ useEffect(() => {
34
+ if (selectedDate && !isWithinRange(selectedDate, min, max)) {
35
+ onChange(moveToWithinRange(selectedDate, min, max));
36
+ }
37
+ }, [selectedDate?.getTime(), min?.getTime(), max?.getTime(), onChange]); // eslint-disable-line react-hooks/exhaustive-deps
38
+
39
+ const dateView = returnDateView(selectedDate, min, max);
40
+ const [viewMonth, setViewMonth] = useState(dateView.getMonth());
41
+ const [viewYear, setViewYear] = useState(dateView.getFullYear());
42
+ const [mode, setMode] = useState<'day' | 'month' | 'year'>('day');
43
+
44
+ useEffect(() => {
45
+ const view = returnDateView(selectedDate, min, max);
46
+ // eslint-disable-next-line react-hooks/set-state-in-effect
47
+ setViewMonth(view.getMonth());
48
+
49
+ setViewYear(view.getFullYear());
50
+ }, [selectedDate?.getTime(), min?.getTime(), max?.getTime()]); // eslint-disable-line react-hooks/exhaustive-deps
51
+
52
+ const handleViewDateUpdate = useCallback(
53
+ // eslint-disable-next-line react-hooks/preserve-manual-memoization
54
+ ({ month, year }: { month?: number; year?: number }) => {
55
+ if (month !== undefined) setViewMonth(month);
56
+ if (year !== undefined) setViewYear(year);
57
+ },
58
+ [],
59
+ );
60
+
61
+ const switchToDays = useCallback(() => setMode('day'), []);
62
+ const switchToMonths = useCallback(() => setMode('month'), []);
63
+ const switchToYears = useCallback(() => setMode('year'), []);
64
+
65
+ const handleSelectedDateUpdate = useCallback(
66
+ (date: Date) => {
67
+ if (onSelect) {
68
+ onSelect(date);
69
+ } else {
70
+ onChange(date);
71
+ }
72
+ },
73
+ [onChange, onSelect],
74
+ );
75
+
76
+ const adjustDate = useCallback(
77
+ (daysToAdd: number, monthsToAdd: number, yearsToAdd: number) => {
78
+ let date: Date | null;
79
+ if (selectedDate) {
80
+ date = new Date(
81
+ mode === 'year' ? selectedDate.getFullYear() + yearsToAdd : selectedDate.getFullYear(),
82
+ mode === 'month' ? selectedDate.getMonth() + monthsToAdd : selectedDate.getMonth(),
83
+ mode === 'day' ? selectedDate.getDate() + daysToAdd : selectedDate.getDate(),
84
+ );
85
+ } else {
86
+ date = getStartOfDay(new Date());
87
+ }
88
+ date &&= moveToWithinRange(date, min, max);
89
+ if (date?.getTime() !== selectedDate?.getTime()) {
90
+ onChange(date);
91
+ }
92
+ },
93
+ [selectedDate, min, max, mode, onChange],
94
+ );
95
+
96
+ const handleKeyDown = useCallback(
97
+ (event: KeyboardEvent<HTMLDivElement>) => {
98
+ switch (event.key) {
99
+ case 'ArrowLeft':
100
+ adjustDate(-1, -1, -1);
101
+ event.preventDefault();
102
+ break;
103
+ case 'ArrowUp':
104
+ adjustDate(-7, -4, -4);
105
+ event.preventDefault();
106
+ break;
107
+ case 'ArrowRight':
108
+ adjustDate(1, 1, 1);
109
+ event.preventDefault();
110
+ break;
111
+ case 'ArrowDown':
112
+ adjustDate(7, 4, 4);
113
+ event.preventDefault();
114
+ break;
115
+ default:
116
+ break;
117
+ }
118
+ },
119
+ [adjustDate],
120
+ );
121
+
122
+ return (
123
+ // eslint-disable-next-line jsx-a11y/no-static-element-interactions
124
+ <div onKeyDown={handleKeyDown}>
125
+ {mode === 'day' && (
126
+ <DayCalendar
127
+ selectedDate={selectedDate}
128
+ min={min}
129
+ max={max}
130
+ viewMonth={viewMonth}
131
+ viewYear={viewYear}
132
+ monthFormat={monthFormat}
133
+ onSelect={handleSelectedDateUpdate}
134
+ onLabelClick={switchToYears}
135
+ onViewDateUpdate={handleViewDateUpdate}
136
+ />
137
+ )}
138
+ {mode === 'month' && (
139
+ <MonthCalendar
140
+ selectedDate={selectedDate}
141
+ min={min}
142
+ max={max}
143
+ viewYear={viewYear}
144
+ {...(placeholder != null && { placeholder })}
145
+ onSelect={switchToDays}
146
+ onLabelClick={switchToYears}
147
+ onViewDateUpdate={handleViewDateUpdate}
148
+ />
149
+ )}
150
+ {mode === 'year' && (
151
+ <YearCalendar
152
+ selectedDate={selectedDate}
153
+ min={min}
154
+ max={max}
155
+ viewYear={viewYear}
156
+ {...(placeholder != null && { placeholder })}
157
+ onSelect={switchToMonths}
158
+ onViewDateUpdate={handleViewDateUpdate}
159
+ />
160
+ )}
161
+ </div>
162
+ );
163
+ };
164
+
165
+ export default Calendar;
@@ -4,7 +4,7 @@ import { useIntl } from 'react-intl';
4
4
  import { Typography } from '../../common';
5
5
  import { useLayout } from '../../common/hooks';
6
6
  import Title from '../../title';
7
- import messages from '../DateLookup.messages';
7
+ import messages from '../Calendar.messages';
8
8
  import Button from '../../button/Button';
9
9
  import { ChevronDown, ChevronLeft, ChevronRight } from '@transferwise/icons';
10
10
  import IconButton from '../../iconButton';
@@ -3,7 +3,7 @@ import { PureComponent } from 'react';
3
3
  import { injectIntl, WrappedComponentProps } from 'react-intl';
4
4
 
5
5
  import { MonthFormat } from '../../common';
6
- import messages from '../DateLookup.messages';
6
+ import messages from '../Calendar.messages';
7
7
  import DateHeader from '../dateHeader';
8
8
 
9
9
  import DayCalendarTable from './table';
@@ -0,0 +1,2 @@
1
+ export { default } from './Calendar';
2
+ export type { CalendarProps } from './Calendar';
@@ -2,7 +2,7 @@ import { formatDate } from '@transferwise/formatting';
2
2
  import { PureComponent } from 'react';
3
3
  import { injectIntl, WrappedComponentProps } from 'react-intl';
4
4
 
5
- import messages from '../DateLookup.messages';
5
+ import messages from '../Calendar.messages';
6
6
  import DateHeader from '../dateHeader';
7
7
 
8
8
  import MonthCalendarTable from './table';
@@ -12,7 +12,7 @@ interface MonthCalendarProps extends WrappedComponentProps {
12
12
  min: Date | null;
13
13
  max: Date | null;
14
14
  viewYear: number;
15
- placeholder: string;
15
+ placeholder?: string;
16
16
  onSelect: () => void;
17
17
  onLabelClick: () => void;
18
18
  onViewDateUpdate: (date: { year?: number; month?: number }) => void;
@@ -9,7 +9,7 @@ interface MonthCalendarTableProps {
9
9
  min: Date | null;
10
10
  max: Date | null;
11
11
  viewYear: number;
12
- placeholder: string;
12
+ placeholder?: string;
13
13
  onSelect: (date: number) => void;
14
14
  }
15
15
 
@@ -2,7 +2,7 @@ import { clsx } from 'clsx';
2
2
  import { useEffect, useRef } from 'react';
3
3
  import { useIntl } from 'react-intl';
4
4
 
5
- import messages from '../DateLookup.messages';
5
+ import messages from '../Calendar.messages';
6
6
 
7
7
  interface TableLinkProps {
8
8
  item: number;
@@ -1,7 +1,7 @@
1
1
  import { PureComponent } from 'react';
2
2
  import { injectIntl, WrappedComponentProps } from 'react-intl';
3
3
 
4
- import messages from '../DateLookup.messages';
4
+ import messages from '../Calendar.messages';
5
5
  import DateHeader from '../dateHeader';
6
6
 
7
7
  import YearCalendarTable from './table';
@@ -11,7 +11,7 @@ interface YearCalendarProps extends WrappedComponentProps {
11
11
  min: Date | null;
12
12
  max: Date | null;
13
13
  viewYear: number;
14
- placeholder: string;
14
+ placeholder?: string;
15
15
  onSelect: () => void;
16
16
  onViewDateUpdate: (date: { year: number }) => void;
17
17
  }
@@ -9,7 +9,7 @@ interface YearCalendarTableProps {
9
9
  min: Date | null;
10
10
  max: Date | null;
11
11
  viewYear: number;
12
- placeholder: string;
12
+ placeholder?: string;
13
13
  onSelect: (year: number) => void;
14
14
  }
15
15
 
@@ -80,7 +80,7 @@ describe('CriticalCommsBanner', () => {
80
80
 
81
81
  const surface = screen.getByTestId('alert').closest('.critical-comms');
82
82
  expect(surface).toHaveClass('wds-sentiment-surface');
83
- expect(surface).toHaveClass('wds-sentiment-surface-warning-elevated');
83
+ expect(surface).toHaveClass('wds-sentiment-warning-light-elevated');
84
84
  });
85
85
 
86
86
  it('applies className to the wrapper', () => {
@@ -1,93 +1,3 @@
1
1
  .tw-date-lookup-menu {
2
2
  width: 400px;
3
3
  }
4
- .tw-date-lookup-calendar {
5
- min-width: 300px;
6
- text-align: center;
7
- table-layout: fixed;
8
- background-color: inherit;
9
- }
10
- .tw-date-lookup-calendar > tbody > tr > td.weekend button {
11
- color: #5d7079;
12
- color: var(--color-content-secondary);
13
- }
14
- .tw-date-lookup-calendar > tbody > tr > td {
15
- padding: 4px;
16
- padding: var(--size-4);
17
- }
18
- @media (max-width: 320px) {
19
- .tw-date-lookup-calendar > tbody > tr > td {
20
- padding: 0;
21
- }
22
- }
23
- .tw-date-lookup-calendar > tbody > tr > td:has(.tw-date-lookup-day-option) {
24
- padding: 1px;
25
- }
26
- .tw-date-lookup-calendar > tbody > tr > td button {
27
- width: 100%;
28
- padding: 4px 0;
29
- padding: var(--size-4) 0;
30
- color: #0097c7;
31
- color: var(--color-content-accent);
32
- border: transparent;
33
- border-radius: 10px;
34
- border-radius: var(--radius-small);
35
- background-color: transparent;
36
- font-weight: 600;
37
- font-weight: var(--font-weight-semi-bold);
38
- color: #37517e;
39
- color: var(--color-content-primary);
40
- }
41
- @media (max-width: 320px) {
42
- .tw-date-lookup-calendar > tbody > tr > td button {
43
- padding: 0;
44
- }
45
- }
46
- .tw-date-lookup-calendar > tbody > tr > td button.tw-date-lookup-day-option {
47
- height: 40px;
48
- height: var(--size-40);
49
- border-radius: 9999px;
50
- border-radius: var(--radius-full);
51
- line-height: 40px;
52
- line-height: var(--size-40);
53
- width: 40px;
54
- width: var(--size-40);
55
- padding: 0;
56
- display: inline-flex;
57
- align-items: center;
58
- justify-content: center;
59
- }
60
- .tw-date-lookup-calendar > tbody > tr > td button.tw-date-lookup-day-option.today {
61
- -webkit-text-decoration: underline;
62
- text-decoration: underline;
63
- text-decoration-thickness: 2px;
64
- text-underline-offset: 4px;
65
- }
66
- .tw-date-lookup-calendar > tbody > tr > td:not(.disabled):not(:disabled) button.show-focus,
67
- .tw-date-lookup-calendar > tbody > tr > td:hover button:not(.disabled):not(:disabled) {
68
- background-color: var(--color-background-screen-hover);
69
- }
70
- .tw-date-lookup-calendar > tbody > tr > td:not(.disabled):not(:disabled) button.active {
71
- background-color: var(--color-interactive-primary);
72
- color: var(--color-interactive-contrast);
73
- }
74
- .tw-date-lookup-calendar abbr {
75
- -webkit-text-decoration: none;
76
- text-decoration: none;
77
- }
78
- .tw-date-lookup-header-current-container {
79
- display: inline;
80
- }
81
- .np-theme-personal.tw-date-lookup-menu .table-bordered,
82
- .np-theme-personal .tw-date-lookup-menu .table-bordered {
83
- border: none;
84
- }
85
- .np-theme-personal.tw-date-lookup-menu thead,
86
- .np-theme-personal .tw-date-lookup-menu thead {
87
- background-color: transparent;
88
- background-color: initial;
89
- }
90
- .np-theme-personal.tw-date-lookup-menu td,
91
- .np-theme-personal .tw-date-lookup-menu td {
92
- border: none;
93
- }
@@ -1,94 +1,3 @@
1
- @import (reference) "./../styles/variables/neptune-tokens.less";
2
-
3
1
  .tw-date-lookup-menu {
4
2
  width: 400px;
5
3
  }
6
-
7
- .tw-date-lookup-calendar {
8
- min-width: 300px;
9
- text-align: center;
10
- table-layout: fixed;
11
-
12
- > tbody > tr > td.weekend button {
13
- color: var(--color-content-secondary);
14
- }
15
-
16
- > tbody > tr > td {
17
- padding: var(--size-4);
18
- @media (--screen-400-zoom) {
19
- padding: 0;
20
- }
21
-
22
- &:has(.tw-date-lookup-day-option) {
23
- padding: 1px;
24
- }
25
-
26
- button {
27
- width: 100%;
28
- padding: var(--size-4) 0;
29
- @media (--screen-400-zoom) {
30
- padding: 0;
31
- }
32
- color: var(--color-content-accent);
33
- border: transparent;
34
- border-radius: var(--radius-small);
35
- background-color: transparent;
36
- font-weight: var(--font-weight-semi-bold);
37
- color: var(--color-content-primary);
38
-
39
- &.tw-date-lookup-day-option {
40
- height: var(--size-40);
41
- border-radius: var(--radius-full);
42
- line-height: var(--size-40);
43
- width: var(--size-40);
44
- padding: 0;
45
- display: inline-flex;
46
- align-items: center;
47
- justify-content: center;
48
-
49
- &.today {
50
- text-decoration: underline;
51
- text-decoration-thickness: 2px;
52
- text-underline-offset: 4px;
53
- }
54
- }
55
- }
56
-
57
- &:not(.disabled, :disabled) button.show-focus,
58
- &:hover button:not(.disabled, :disabled) {
59
- background-color: var(--color-background-screen-hover);
60
- }
61
-
62
- &:not(.disabled, :disabled) button.active {
63
- background-color: var(--color-interactive-primary);
64
- color: var(--color-interactive-contrast);
65
- }
66
- }
67
-
68
- abbr {
69
- text-decoration: none;
70
- }
71
-
72
- background-color: inherit;
73
- }
74
-
75
- .tw-date-lookup-header-current-container {
76
- display: inline;
77
- }
78
-
79
- .np-theme-personal {
80
- &.tw-date-lookup-menu,
81
- .tw-date-lookup-menu {
82
- .table-bordered {
83
- border: none;
84
- }
85
-
86
- thead {
87
- background-color: unset;
88
- }
89
-
90
- td {
91
- border: none;
92
- }
93
- }
94
- }