@planningcenter/tapestry-react 2.6.0 → 2.6.2
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.
- package/dist/cjs/Collapse/Collapse.js +3 -1
- package/dist/cjs/Dropdown/Dropdown.js +19 -2
- package/dist/cjs/Input/Input.js +4 -2
- package/dist/cjs/Modal/Modal.js +4 -2
- package/dist/cjs/TimeField/TimeField.js +37 -2
- package/dist/cjs/TimeField/TimeField.test.js +179 -10
- package/dist/cjs/Tooltip/Tooltip.test.js +178 -0
- package/dist/esm/Collapse/Collapse.js +3 -1
- package/dist/esm/Dropdown/Dropdown.js +19 -2
- package/dist/esm/Input/Input.js +4 -2
- package/dist/esm/Modal/Modal.js +4 -2
- package/dist/esm/TimeField/TimeField.js +36 -2
- package/dist/esm/TimeField/TimeField.test.js +153 -10
- package/dist/esm/Tooltip/Tooltip.test.js +160 -0
- package/dist/types/Tooltip/Tooltip.test.d.ts +1 -0
- package/package.json +1 -1
- package/src/Collapse/Collapse.js +1 -1
- package/src/Dropdown/Dropdown.js +12 -1
- package/src/Input/Input.js +7 -0
- package/src/Modal/Modal.js +4 -2
- package/src/TimeField/TimeField.js +35 -2
- package/src/TimeField/TimeField.test.tsx +105 -1
- package/src/Tooltip/Tooltip.test.tsx +136 -0
|
@@ -11,6 +11,8 @@ import InputField from '../Input/InputField';
|
|
|
11
11
|
import NumberField from '../NumberField';
|
|
12
12
|
import { isIOS, noop, padNumber } from '../utils';
|
|
13
13
|
import { HOURS_TO_NOON, HOURS_IN_DAY, addHoursToTime, addMinutesToTime, addTimeToDate, getMeridiem, getTimeFromDate } from './utils';
|
|
14
|
+
var MIN_MINUTE = 0;
|
|
15
|
+
var MAX_MINUTE = 59;
|
|
14
16
|
|
|
15
17
|
var _ref = /*#__PURE__*/React.createElement(Box, {
|
|
16
18
|
as: "span",
|
|
@@ -82,9 +84,31 @@ var TimeField = /*#__PURE__*/function (_Component) {
|
|
|
82
84
|
});
|
|
83
85
|
|
|
84
86
|
_defineProperty(_assertThisInitialized(_this), "handleHoursKeyDown", function (event) {
|
|
87
|
+
var hour = Number(event.target.value);
|
|
88
|
+
var isTwelveHourClock = _this.props.twelveHourClock;
|
|
89
|
+
var isHourEleven = HOURS_TO_NOON - 1;
|
|
90
|
+
var maxHour = isTwelveHourClock ? HOURS_TO_NOON : HOURS_IN_DAY - 1;
|
|
91
|
+
var minHour = isTwelveHourClock ? 1 : 0;
|
|
92
|
+
|
|
85
93
|
if (event.key === 'ArrowRight') {
|
|
86
94
|
_this.inputBox.focus(1);
|
|
87
95
|
}
|
|
96
|
+
|
|
97
|
+
if (event.key === 'ArrowUp' && isTwelveHourClock && hour === isHourEleven) {
|
|
98
|
+
_this.toggleMeridiem();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (event.key === 'ArrowUp' && hour === maxHour) {
|
|
102
|
+
_this.updateHours(1);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (event.key === 'ArrowDown' && isTwelveHourClock && hour === minHour) {
|
|
106
|
+
_this.toggleMeridiem();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (event.key === 'ArrowDown' && hour === minHour) {
|
|
110
|
+
_this.updateHours(-1);
|
|
111
|
+
}
|
|
88
112
|
});
|
|
89
113
|
|
|
90
114
|
_defineProperty(_assertThisInitialized(_this), "handleMinutesChange", function (minutes) {
|
|
@@ -94,6 +118,8 @@ var TimeField = /*#__PURE__*/function (_Component) {
|
|
|
94
118
|
});
|
|
95
119
|
|
|
96
120
|
_defineProperty(_assertThisInitialized(_this), "handleMinutesKeyDown", function (event) {
|
|
121
|
+
var minute = Number(event.target.value);
|
|
122
|
+
|
|
97
123
|
if (_this.props.ignoredKeys.includes(event.key)) {
|
|
98
124
|
return;
|
|
99
125
|
}
|
|
@@ -105,6 +131,14 @@ var TimeField = /*#__PURE__*/function (_Component) {
|
|
|
105
131
|
if (event.key === 'ArrowRight') {
|
|
106
132
|
_this.inputBox.focus(2);
|
|
107
133
|
}
|
|
134
|
+
|
|
135
|
+
if (event.key === 'ArrowUp' && minute >= MAX_MINUTE) {
|
|
136
|
+
_this.updateMinutes(1);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (event.key === 'ArrowDown' && minute <= MIN_MINUTE) {
|
|
140
|
+
_this.updateMinutes(-1);
|
|
141
|
+
}
|
|
108
142
|
});
|
|
109
143
|
|
|
110
144
|
_defineProperty(_assertThisInitialized(_this), "handleAMPMKeyDown", function (event) {
|
|
@@ -194,8 +228,8 @@ var TimeField = /*#__PURE__*/function (_Component) {
|
|
|
194
228
|
fontVariantNumeric: "tabular-nums",
|
|
195
229
|
moveFocusOnMax: true,
|
|
196
230
|
value: minutes,
|
|
197
|
-
min:
|
|
198
|
-
max:
|
|
231
|
+
min: MIN_MINUTE,
|
|
232
|
+
max: MAX_MINUTE,
|
|
199
233
|
pad: 2,
|
|
200
234
|
grow: 0,
|
|
201
235
|
width: "2ch",
|
|
@@ -182,7 +182,7 @@ it('does not change the meridiem on arrow key if arrow keys are ignored', functi
|
|
|
182
182
|
userEvent.type(meridiemInput, '{arrowup}');
|
|
183
183
|
expect(meridiemInput).toHaveValue('PM');
|
|
184
184
|
});
|
|
185
|
-
it('
|
|
185
|
+
it('increment hour on arrow up', function () {
|
|
186
186
|
var _setup15 = setup({
|
|
187
187
|
hours: 1,
|
|
188
188
|
minutes: 42
|
|
@@ -193,13 +193,156 @@ it('changes the value of hours on arrow up or arrow down', function () {
|
|
|
193
193
|
userEvent.type(hourInput, '{arrowup}');
|
|
194
194
|
expect(hourInput).toHaveValue("02");
|
|
195
195
|
});
|
|
196
|
-
it('
|
|
196
|
+
it('increment hour if arrow up on minutes exceeds max value', function () {
|
|
197
197
|
var _setup16 = setup({
|
|
198
|
+
hours: 1,
|
|
199
|
+
minutes: 59
|
|
200
|
+
}),
|
|
201
|
+
hourInput = _setup16.hourInput,
|
|
202
|
+
minuteInput = _setup16.minuteInput;
|
|
203
|
+
|
|
204
|
+
expect(hourInput).toHaveValue("01");
|
|
205
|
+
userEvent.type(minuteInput, '{arrowup}');
|
|
206
|
+
expect(hourInput).toHaveValue("02");
|
|
207
|
+
});
|
|
208
|
+
it('decrement hour on arrow down', function () {
|
|
209
|
+
var _setup17 = setup({
|
|
210
|
+
hours: 2,
|
|
211
|
+
minutes: 42
|
|
212
|
+
}),
|
|
213
|
+
hourInput = _setup17.hourInput;
|
|
214
|
+
|
|
215
|
+
expect(hourInput).toHaveValue("02");
|
|
216
|
+
userEvent.type(hourInput, '{arrowdown}');
|
|
217
|
+
expect(hourInput).toHaveValue("01");
|
|
218
|
+
});
|
|
219
|
+
it('decrement hour if arrow down on minutes exceeds min value', function () {
|
|
220
|
+
var _setup18 = setup({
|
|
221
|
+
hours: 2,
|
|
222
|
+
minutes: 0
|
|
223
|
+
}),
|
|
224
|
+
hourInput = _setup18.hourInput,
|
|
225
|
+
minuteInput = _setup18.minuteInput;
|
|
226
|
+
|
|
227
|
+
expect(hourInput).toHaveValue("02");
|
|
228
|
+
userEvent.type(minuteInput, '{arrowdown}');
|
|
229
|
+
expect(hourInput).toHaveValue("01");
|
|
230
|
+
});
|
|
231
|
+
it('increment minute on arrow up', function () {
|
|
232
|
+
var _setup19 = setup({
|
|
233
|
+
hours: 1,
|
|
234
|
+
minutes: 42
|
|
235
|
+
}),
|
|
236
|
+
minuteInput = _setup19.minuteInput;
|
|
237
|
+
|
|
238
|
+
expect(minuteInput).toHaveValue("42");
|
|
239
|
+
userEvent.type(minuteInput, '{arrowup}');
|
|
240
|
+
expect(minuteInput).toHaveValue("43");
|
|
241
|
+
});
|
|
242
|
+
it('decrement minute on arrow down', function () {
|
|
243
|
+
var _setup20 = setup({
|
|
244
|
+
hours: 2,
|
|
245
|
+
minutes: 43
|
|
246
|
+
}),
|
|
247
|
+
minuteInput = _setup20.minuteInput;
|
|
248
|
+
|
|
249
|
+
expect(minuteInput).toHaveValue("43");
|
|
250
|
+
userEvent.type(minuteInput, '{arrowdown}');
|
|
251
|
+
expect(minuteInput).toHaveValue("42");
|
|
252
|
+
});
|
|
253
|
+
it('set minute to min value if arrow up on minutes exceeds max value', function () {
|
|
254
|
+
var _setup21 = setup({
|
|
255
|
+
hours: 1,
|
|
256
|
+
minutes: 59
|
|
257
|
+
}),
|
|
258
|
+
minuteInput = _setup21.minuteInput;
|
|
259
|
+
|
|
260
|
+
expect(minuteInput).toHaveValue("59");
|
|
261
|
+
userEvent.type(minuteInput, '{arrowup}');
|
|
262
|
+
expect(minuteInput).toHaveValue("00");
|
|
263
|
+
});
|
|
264
|
+
it('set minute to max value if arrow down on minutes exceeds min value', function () {
|
|
265
|
+
var _setup22 = setup({
|
|
266
|
+
hours: 1,
|
|
267
|
+
minutes: 0
|
|
268
|
+
}),
|
|
269
|
+
minuteInput = _setup22.minuteInput;
|
|
270
|
+
|
|
271
|
+
expect(minuteInput).toHaveValue("00");
|
|
272
|
+
userEvent.type(minuteInput, '{arrowdown}');
|
|
273
|
+
expect(minuteInput).toHaveValue("59");
|
|
274
|
+
});
|
|
275
|
+
it('toggle meridiem if arrow up on hour exceeds eleven', function () {
|
|
276
|
+
var _setup23 = setup({
|
|
277
|
+
hours: 11
|
|
278
|
+
}),
|
|
279
|
+
hourInput = _setup23.hourInput,
|
|
280
|
+
meridiemInput = _setup23.meridiemInput;
|
|
281
|
+
|
|
282
|
+
expect(meridiemInput).toHaveValue('AM');
|
|
283
|
+
userEvent.type(hourInput, '{arrowup}');
|
|
284
|
+
expect(meridiemInput).toHaveValue('PM');
|
|
285
|
+
});
|
|
286
|
+
it('toggle meridiem if arrow down on hour exceeds min value', function () {
|
|
287
|
+
var _setup24 = setup({
|
|
288
|
+
hours: 1
|
|
289
|
+
}),
|
|
290
|
+
hourInput = _setup24.hourInput,
|
|
291
|
+
meridiemInput = _setup24.meridiemInput;
|
|
292
|
+
|
|
293
|
+
expect(meridiemInput).toHaveValue('AM');
|
|
294
|
+
userEvent.type(hourInput, '{arrowdown}');
|
|
295
|
+
expect(meridiemInput).toHaveValue('PM');
|
|
296
|
+
});
|
|
297
|
+
it('set 12 hour clock to min value if arrow up on hour exceeds max value', function () {
|
|
298
|
+
var _setup25 = setup({
|
|
299
|
+
hours: 12
|
|
300
|
+
}),
|
|
301
|
+
hourInput = _setup25.hourInput;
|
|
302
|
+
|
|
303
|
+
expect(hourInput).toHaveValue("12");
|
|
304
|
+
userEvent.type(hourInput, '{arrowup}');
|
|
305
|
+
expect(hourInput).toHaveValue("01");
|
|
306
|
+
});
|
|
307
|
+
it('set 24 hour clock to min value if arrow up on hour exceeds max value', function () {
|
|
308
|
+
var _setup26 = setup({
|
|
309
|
+
hours: 23,
|
|
310
|
+
twelveHourClock: false
|
|
311
|
+
}),
|
|
312
|
+
hourInput = _setup26.hourInput;
|
|
313
|
+
|
|
314
|
+
expect(hourInput).toHaveValue("23");
|
|
315
|
+
userEvent.type(hourInput, '{arrowup}');
|
|
316
|
+
expect(hourInput).toHaveValue("00");
|
|
317
|
+
});
|
|
318
|
+
it('set 12 hour clock to max value if arrow down on hour exceeds min value', function () {
|
|
319
|
+
var _setup27 = setup({
|
|
320
|
+
hours: 1
|
|
321
|
+
}),
|
|
322
|
+
hourInput = _setup27.hourInput;
|
|
323
|
+
|
|
324
|
+
expect(hourInput).toHaveValue("01");
|
|
325
|
+
userEvent.type(hourInput, '{arrowdown}');
|
|
326
|
+
expect(hourInput).toHaveValue("12");
|
|
327
|
+
});
|
|
328
|
+
it('set 24 hour clock to max value if arrow down on hour exceeds min value', function () {
|
|
329
|
+
var _setup28 = setup({
|
|
330
|
+
hours: 0,
|
|
331
|
+
twelveHourClock: false
|
|
332
|
+
}),
|
|
333
|
+
hourInput = _setup28.hourInput;
|
|
334
|
+
|
|
335
|
+
expect(hourInput).toHaveValue("00");
|
|
336
|
+
userEvent.type(hourInput, '{arrowdown}');
|
|
337
|
+
expect(hourInput).toHaveValue("23");
|
|
338
|
+
});
|
|
339
|
+
it('does not change the value of hours on arrow up or arrow down if ignored', function () {
|
|
340
|
+
var _setup29 = setup({
|
|
198
341
|
hours: 1,
|
|
199
342
|
minutes: 42,
|
|
200
343
|
ignoredKeys: ['ArrowUp', 'ArrowDown']
|
|
201
344
|
}),
|
|
202
|
-
hourInput =
|
|
345
|
+
hourInput = _setup29.hourInput;
|
|
203
346
|
|
|
204
347
|
expect(hourInput).toHaveValue("01");
|
|
205
348
|
userEvent.type(hourInput, '{arrowup}');
|
|
@@ -208,12 +351,12 @@ it('does not change the value of hours on arrow up or arrow down if ignored', fu
|
|
|
208
351
|
expect(hourInput).toHaveValue("01");
|
|
209
352
|
});
|
|
210
353
|
it('does not change the value of minutes on arrow up or arrow down if ignored', function () {
|
|
211
|
-
var
|
|
354
|
+
var _setup30 = setup({
|
|
212
355
|
hours: 1,
|
|
213
356
|
minutes: 42,
|
|
214
357
|
ignoredKeys: ['ArrowUp', 'ArrowDown']
|
|
215
358
|
}),
|
|
216
|
-
minuteInput =
|
|
359
|
+
minuteInput = _setup30.minuteInput;
|
|
217
360
|
|
|
218
361
|
expect(minuteInput).toHaveValue("42");
|
|
219
362
|
userEvent.type(minuteInput, '{arrowup}');
|
|
@@ -223,15 +366,15 @@ it('does not change the value of minutes on arrow up or arrow down if ignored',
|
|
|
223
366
|
}); // ios
|
|
224
367
|
|
|
225
368
|
it('renders iOS as a single input', function () {
|
|
226
|
-
var
|
|
369
|
+
var _setup31 = setup({
|
|
227
370
|
isIOS: true,
|
|
228
371
|
hours: 13,
|
|
229
372
|
minutes: 42
|
|
230
373
|
}),
|
|
231
|
-
container =
|
|
232
|
-
hourInput =
|
|
233
|
-
minuteInput =
|
|
234
|
-
meridiemInput =
|
|
374
|
+
container = _setup31.container,
|
|
375
|
+
hourInput = _setup31.hourInput,
|
|
376
|
+
minuteInput = _setup31.minuteInput,
|
|
377
|
+
meridiemInput = _setup31.meridiemInput;
|
|
235
378
|
|
|
236
379
|
var singleTimeInput = container.querySelector('[type=time]');
|
|
237
380
|
expect(singleTimeInput).toHaveValue('13:42');
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
2
|
+
import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { act, render, screen, waitFor } from '@testing-library/react';
|
|
5
|
+
import userEvent from '@testing-library/user-event';
|
|
6
|
+
import '@testing-library/jest-dom/extend-expect';
|
|
7
|
+
import { Button, Link, StackView, Text, Tooltip, hooks } from '..';
|
|
8
|
+
|
|
9
|
+
var _ref = /*#__PURE__*/React.createElement(Text, null, "Tooltip anchor");
|
|
10
|
+
|
|
11
|
+
var _ref3 = /*#__PURE__*/React.createElement(Text, null, "Tooltip anchor");
|
|
12
|
+
|
|
13
|
+
var _ref5 = /*#__PURE__*/React.createElement(Button, null, "Tooltip anchor");
|
|
14
|
+
|
|
15
|
+
var _ref7 = /*#__PURE__*/React.createElement(Text, null, "Tooltip anchor");
|
|
16
|
+
|
|
17
|
+
var _ref8 = /*#__PURE__*/React.createElement(Tooltip, {
|
|
18
|
+
title: "Test Text"
|
|
19
|
+
}, /*#__PURE__*/React.createElement(Text, null, "Tooltip anchor"));
|
|
20
|
+
|
|
21
|
+
describe('Tooltip', function () {
|
|
22
|
+
test('does not render string when closed', function () {
|
|
23
|
+
var string = 'Test Text';
|
|
24
|
+
render( /*#__PURE__*/React.createElement(Tooltip, {
|
|
25
|
+
title: string
|
|
26
|
+
}, _ref));
|
|
27
|
+
expect(screen.queryByText(string)).toBeNull();
|
|
28
|
+
});
|
|
29
|
+
test('renders string on hover', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
30
|
+
var string, tooltip;
|
|
31
|
+
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
32
|
+
while (1) {
|
|
33
|
+
switch (_context.prev = _context.next) {
|
|
34
|
+
case 0:
|
|
35
|
+
string = 'Test Text';
|
|
36
|
+
render( /*#__PURE__*/React.createElement(Tooltip, {
|
|
37
|
+
title: string
|
|
38
|
+
}, _ref3));
|
|
39
|
+
userEvent.hover(screen.getByText('Tooltip anchor'));
|
|
40
|
+
_context.next = 5;
|
|
41
|
+
return screen.findByText(string);
|
|
42
|
+
|
|
43
|
+
case 5:
|
|
44
|
+
tooltip = _context.sent;
|
|
45
|
+
expect(tooltip).toBeInTheDocument();
|
|
46
|
+
|
|
47
|
+
case 7:
|
|
48
|
+
case "end":
|
|
49
|
+
return _context.stop();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}, _callee);
|
|
53
|
+
})));
|
|
54
|
+
test('renders string on focus', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
|
|
55
|
+
var string, tooltip;
|
|
56
|
+
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
|
|
57
|
+
while (1) {
|
|
58
|
+
switch (_context2.prev = _context2.next) {
|
|
59
|
+
case 0:
|
|
60
|
+
string = 'Test Text';
|
|
61
|
+
render( /*#__PURE__*/React.createElement(Tooltip, {
|
|
62
|
+
title: string,
|
|
63
|
+
triggerOnFocus: true
|
|
64
|
+
}, _ref5));
|
|
65
|
+
userEvent.tab();
|
|
66
|
+
_context2.next = 5;
|
|
67
|
+
return screen.findByText(string);
|
|
68
|
+
|
|
69
|
+
case 5:
|
|
70
|
+
tooltip = _context2.sent;
|
|
71
|
+
expect(tooltip).toBeInTheDocument();
|
|
72
|
+
|
|
73
|
+
case 7:
|
|
74
|
+
case "end":
|
|
75
|
+
return _context2.stop();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}, _callee2);
|
|
79
|
+
})));
|
|
80
|
+
test('removes string after timeout', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
|
|
81
|
+
var string, anchor, tooltip;
|
|
82
|
+
return _regeneratorRuntime.wrap(function _callee3$(_context3) {
|
|
83
|
+
while (1) {
|
|
84
|
+
switch (_context3.prev = _context3.next) {
|
|
85
|
+
case 0:
|
|
86
|
+
string = 'Test Text';
|
|
87
|
+
render( /*#__PURE__*/React.createElement(Tooltip, {
|
|
88
|
+
title: string
|
|
89
|
+
}, _ref7));
|
|
90
|
+
anchor = screen.getByText('Tooltip anchor');
|
|
91
|
+
expect(screen.queryByText(string)).toBeNull();
|
|
92
|
+
userEvent.hover(anchor);
|
|
93
|
+
_context3.next = 7;
|
|
94
|
+
return screen.findByText(string);
|
|
95
|
+
|
|
96
|
+
case 7:
|
|
97
|
+
tooltip = _context3.sent;
|
|
98
|
+
expect(tooltip).toBeInTheDocument();
|
|
99
|
+
userEvent.unhover(anchor);
|
|
100
|
+
_context3.next = 12;
|
|
101
|
+
return waitFor(function () {
|
|
102
|
+
expect(screen.queryByText(string)).not.toBeInTheDocument();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
case 12:
|
|
106
|
+
case "end":
|
|
107
|
+
return _context3.stop();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}, _callee3);
|
|
111
|
+
})));
|
|
112
|
+
test('stays open when hovering a custom tooltip', function () {
|
|
113
|
+
var CustomTooltip = function CustomTooltip() {
|
|
114
|
+
var _hooks$useHover = hooks.useHover(),
|
|
115
|
+
hover = _hooks$useHover.hover,
|
|
116
|
+
hoverProps = _hooks$useHover.hoverProps;
|
|
117
|
+
|
|
118
|
+
return /*#__PURE__*/React.createElement(Tooltip, {
|
|
119
|
+
title: /*#__PURE__*/React.createElement(Link, {
|
|
120
|
+
to: "#"
|
|
121
|
+
}, /*#__PURE__*/React.createElement(StackView, null, /*#__PURE__*/React.createElement(Text, {
|
|
122
|
+
"data-hover": hover
|
|
123
|
+
}, string)))
|
|
124
|
+
}, /*#__PURE__*/React.createElement(Button, hoverProps, "Tooltip anchor"));
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
var string = 'Test Text';
|
|
128
|
+
render( /*#__PURE__*/React.createElement(CustomTooltip, null));
|
|
129
|
+
var anchor = screen.getByText('Tooltip anchor');
|
|
130
|
+
userEvent.hover(anchor);
|
|
131
|
+
act(function () {
|
|
132
|
+
jest.runAllTimers();
|
|
133
|
+
});
|
|
134
|
+
var tooltip = screen.getByText(string);
|
|
135
|
+
expect(tooltip).toBeInTheDocument();
|
|
136
|
+
userEvent.unhover(anchor);
|
|
137
|
+
userEvent.hover(tooltip);
|
|
138
|
+
act(function () {
|
|
139
|
+
jest.runAllTimers();
|
|
140
|
+
});
|
|
141
|
+
expect(tooltip).toBeInTheDocument();
|
|
142
|
+
userEvent.unhover(tooltip);
|
|
143
|
+
act(function () {
|
|
144
|
+
jest.runAllTimers();
|
|
145
|
+
});
|
|
146
|
+
expect(tooltip).not.toBeInTheDocument();
|
|
147
|
+
});
|
|
148
|
+
test('cleans up pageViewChange listeners', function () {
|
|
149
|
+
window.removeEventListener = jest.fn().mockImplementation(function (event, callback) {});
|
|
150
|
+
document.removeEventListener = jest.fn().mockImplementation(function (event, callback) {});
|
|
151
|
+
|
|
152
|
+
var _render = render(_ref8),
|
|
153
|
+
unmount = _render.unmount;
|
|
154
|
+
|
|
155
|
+
unmount();
|
|
156
|
+
expect(window.removeEventListener).toBeCalledWith('focus', expect.any(Function));
|
|
157
|
+
expect(window.removeEventListener).toBeCalledWith('blur', expect.any(Function));
|
|
158
|
+
expect(document.removeEventListener).toBeCalledWith('visibilitychange', expect.any(Function));
|
|
159
|
+
});
|
|
160
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import '@testing-library/jest-dom/extend-expect';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planningcenter/tapestry-react",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.2",
|
|
4
4
|
"description": "A collection of flexible React components to help you build resilient, accessible user interfaces quickly and effectively.",
|
|
5
5
|
"author": "Front End Systems Engineering <frontend@pco.bz>",
|
|
6
6
|
"main": "dist/cjs/index.js",
|
package/src/Collapse/Collapse.js
CHANGED
package/src/Dropdown/Dropdown.js
CHANGED
|
@@ -91,6 +91,7 @@ class Dropdown extends Component<Props> {
|
|
|
91
91
|
super(props)
|
|
92
92
|
this.state = {
|
|
93
93
|
isPopoverOpen: props.defaultOpen || props.forceOpen,
|
|
94
|
+
preventBlur: false,
|
|
94
95
|
}
|
|
95
96
|
this.id = generateId('dropdown')
|
|
96
97
|
}
|
|
@@ -112,6 +113,7 @@ class Dropdown extends Component<Props> {
|
|
|
112
113
|
}
|
|
113
114
|
|
|
114
115
|
togglePopover = (event) => {
|
|
116
|
+
this.setState({ preventBlur: false })
|
|
115
117
|
if (this.state.isPopoverOpen) {
|
|
116
118
|
this.closePopover(event)
|
|
117
119
|
} else {
|
|
@@ -223,7 +225,13 @@ class Dropdown extends Component<Props> {
|
|
|
223
225
|
title: arrowIconOnly ? 'arrow down' : restProps.title,
|
|
224
226
|
tabIndex: 0,
|
|
225
227
|
cursor: 'pointer',
|
|
226
|
-
onBlur:
|
|
228
|
+
onBlur: (event) => {
|
|
229
|
+
if (this.state.preventBlur) {
|
|
230
|
+
this.setState({ preventBlur: false })
|
|
231
|
+
} else {
|
|
232
|
+
requestBlur(event)
|
|
233
|
+
}
|
|
234
|
+
},
|
|
227
235
|
onClick: (event) => {
|
|
228
236
|
this.togglePopover()
|
|
229
237
|
if (!isPopoverOpen) {
|
|
@@ -277,6 +285,9 @@ class Dropdown extends Component<Props> {
|
|
|
277
285
|
})
|
|
278
286
|
}
|
|
279
287
|
},
|
|
288
|
+
onMouseDown: () => {
|
|
289
|
+
this.setState({ preventBlur: true })
|
|
290
|
+
},
|
|
280
291
|
...restProps,
|
|
281
292
|
}
|
|
282
293
|
if (React.isValidElement(triggerElement)) {
|
package/src/Input/Input.js
CHANGED
|
@@ -119,6 +119,11 @@ type InputProps = {
|
|
|
119
119
|
* Changes color of the input's placeholder text. Both [theme colors](/colors) and html values are supported.
|
|
120
120
|
*/
|
|
121
121
|
placeholderColor?: string,
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Sets the input's required attribute.
|
|
125
|
+
*/
|
|
126
|
+
required?: boolean,
|
|
122
127
|
}
|
|
123
128
|
|
|
124
129
|
class Input extends Component<InputProps> {
|
|
@@ -162,6 +167,7 @@ class Input extends Component<InputProps> {
|
|
|
162
167
|
highlightOnInteraction,
|
|
163
168
|
type,
|
|
164
169
|
value,
|
|
170
|
+
required,
|
|
165
171
|
...restProps
|
|
166
172
|
} = this.props
|
|
167
173
|
const ariaLabel = restProps['aria-label']
|
|
@@ -206,6 +212,7 @@ class Input extends Component<InputProps> {
|
|
|
206
212
|
onBlur={onBlur}
|
|
207
213
|
onKeyDown={onKeyDown}
|
|
208
214
|
onKeyUp={onKeyUp}
|
|
215
|
+
required={required}
|
|
209
216
|
/>
|
|
210
217
|
</InputBox>
|
|
211
218
|
)
|
package/src/Modal/Modal.js
CHANGED
|
@@ -69,11 +69,13 @@ function Modal({
|
|
|
69
69
|
>
|
|
70
70
|
<Box
|
|
71
71
|
backgroundColor="surface"
|
|
72
|
+
boxShadow="0 0 20px rgba(0, 0, 0, 0.15)"
|
|
72
73
|
innerRef={modalRef}
|
|
73
74
|
margin={4}
|
|
74
75
|
maxWidth={60}
|
|
75
|
-
padding={
|
|
76
|
-
|
|
76
|
+
padding={4}
|
|
77
|
+
paddingBottom={3}
|
|
78
|
+
radius={8}
|
|
77
79
|
width="100%"
|
|
78
80
|
{...themeProps}
|
|
79
81
|
>
|
|
@@ -18,6 +18,9 @@ import {
|
|
|
18
18
|
getTimeFromDate,
|
|
19
19
|
} from './utils'
|
|
20
20
|
|
|
21
|
+
const MIN_MINUTE = 0
|
|
22
|
+
const MAX_MINUTE = 59
|
|
23
|
+
|
|
21
24
|
type Props = {
|
|
22
25
|
/**
|
|
23
26
|
* An array of keys to ignore when pushed.
|
|
@@ -119,9 +122,31 @@ class TimeField extends Component<Props> {
|
|
|
119
122
|
}
|
|
120
123
|
|
|
121
124
|
handleHoursKeyDown = (event) => {
|
|
125
|
+
const hour = Number(event.target.value)
|
|
126
|
+
const isTwelveHourClock = this.props.twelveHourClock
|
|
127
|
+
const isHourEleven = HOURS_TO_NOON - 1
|
|
128
|
+
const maxHour = isTwelveHourClock ? HOURS_TO_NOON : HOURS_IN_DAY - 1
|
|
129
|
+
const minHour = isTwelveHourClock ? 1 : 0
|
|
130
|
+
|
|
122
131
|
if (event.key === 'ArrowRight') {
|
|
123
132
|
this.inputBox.focus(1)
|
|
124
133
|
}
|
|
134
|
+
|
|
135
|
+
if (event.key === 'ArrowUp' && isTwelveHourClock && hour === isHourEleven) {
|
|
136
|
+
this.toggleMeridiem()
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (event.key === 'ArrowUp' && hour === maxHour) {
|
|
140
|
+
this.updateHours(1)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (event.key === 'ArrowDown' && isTwelveHourClock && hour === minHour) {
|
|
144
|
+
this.toggleMeridiem()
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (event.key === 'ArrowDown' && hour === minHour) {
|
|
148
|
+
this.updateHours(-1)
|
|
149
|
+
}
|
|
125
150
|
}
|
|
126
151
|
|
|
127
152
|
handleMinutesChange = (minutes) => {
|
|
@@ -129,6 +154,8 @@ class TimeField extends Component<Props> {
|
|
|
129
154
|
}
|
|
130
155
|
|
|
131
156
|
handleMinutesKeyDown = (event) => {
|
|
157
|
+
const minute = Number(event.target.value)
|
|
158
|
+
|
|
132
159
|
if (this.props.ignoredKeys.includes(event.key)) {
|
|
133
160
|
return
|
|
134
161
|
}
|
|
@@ -138,6 +165,12 @@ class TimeField extends Component<Props> {
|
|
|
138
165
|
if (event.key === 'ArrowRight') {
|
|
139
166
|
this.inputBox.focus(2)
|
|
140
167
|
}
|
|
168
|
+
if (event.key === 'ArrowUp' && minute >= MAX_MINUTE) {
|
|
169
|
+
this.updateMinutes(1)
|
|
170
|
+
}
|
|
171
|
+
if (event.key === 'ArrowDown' && minute <= MIN_MINUTE) {
|
|
172
|
+
this.updateMinutes(-1)
|
|
173
|
+
}
|
|
141
174
|
}
|
|
142
175
|
|
|
143
176
|
handleAMPMKeyDown = (event) => {
|
|
@@ -214,8 +247,8 @@ class TimeField extends Component<Props> {
|
|
|
214
247
|
fontVariantNumeric="tabular-nums"
|
|
215
248
|
moveFocusOnMax
|
|
216
249
|
value={minutes}
|
|
217
|
-
min={
|
|
218
|
-
max={
|
|
250
|
+
min={MIN_MINUTE}
|
|
251
|
+
max={MAX_MINUTE}
|
|
219
252
|
pad={2}
|
|
220
253
|
grow={0}
|
|
221
254
|
width="2ch"
|