@transferwise/components 46.27.0 → 46.28.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.
- package/build/i18n/th.json +2 -2
- package/build/index.js +327 -630
- package/build/index.js.map +1 -1
- package/build/index.mjs +328 -631
- package/build/index.mjs.map +1 -1
- package/build/types/alert/Alert.d.ts +47 -58
- package/build/types/alert/Alert.d.ts.map +1 -1
- package/build/types/alert/index.d.ts +2 -1
- package/build/types/alert/index.d.ts.map +1 -1
- package/build/types/button/Button.d.ts +7 -9
- package/build/types/button/Button.d.ts.map +1 -1
- package/build/types/common/dateUtils/isWithinRange/isWithinRange.d.ts +1 -1
- package/build/types/common/dateUtils/isWithinRange/isWithinRange.d.ts.map +1 -1
- package/build/types/common/dateUtils/moveToWithinRange/moveToWithinRange.d.ts +1 -1
- package/build/types/common/dateUtils/moveToWithinRange/moveToWithinRange.d.ts.map +1 -1
- package/build/types/common/propsValues/sentiment.d.ts +0 -1
- package/build/types/common/propsValues/sentiment.d.ts.map +1 -1
- package/build/types/dateLookup/DateLookup.d.ts +75 -28
- package/build/types/dateLookup/DateLookup.d.ts.map +1 -1
- package/build/types/dateLookup/DateLookup.messages.d.ts +42 -63
- package/build/types/dateLookup/DateLookup.messages.d.ts.map +1 -1
- package/build/types/dateLookup/dateHeader/DateHeader.d.ts +9 -22
- package/build/types/dateLookup/dateHeader/DateHeader.d.ts.map +1 -1
- package/build/types/dateLookup/dateHeader/index.d.ts +1 -1
- package/build/types/dateLookup/dateHeader/index.d.ts.map +1 -1
- package/build/types/dateLookup/dateTrigger/DateTrigger.d.ts +13 -31
- package/build/types/dateLookup/dateTrigger/DateTrigger.d.ts.map +1 -1
- package/build/types/dateLookup/dateTrigger/index.d.ts +1 -1
- package/build/types/dateLookup/dateTrigger/index.d.ts.map +1 -1
- package/build/types/dateLookup/dayCalendar/DayCalendar.d.ts +19 -2
- package/build/types/dateLookup/dayCalendar/DayCalendar.d.ts.map +1 -1
- package/build/types/dateLookup/dayCalendar/index.d.ts +1 -1
- package/build/types/dateLookup/dayCalendar/index.d.ts.map +1 -1
- package/build/types/dateLookup/dayCalendar/table/DayCalendarTable.d.ts +12 -2
- package/build/types/dateLookup/dayCalendar/table/DayCalendarTable.d.ts.map +1 -1
- package/build/types/dateLookup/dayCalendar/table/index.d.ts +1 -1
- package/build/types/dateLookup/dayCalendar/table/index.d.ts.map +1 -1
- package/build/types/dateLookup/getStartOfDay/getStartOfDay.d.ts +1 -1
- package/build/types/dateLookup/getStartOfDay/getStartOfDay.d.ts.map +1 -1
- package/build/types/dateLookup/getStartOfDay/index.d.ts +1 -1
- package/build/types/dateLookup/getStartOfDay/index.d.ts.map +1 -1
- package/build/types/dateLookup/index.d.ts +2 -1
- package/build/types/dateLookup/index.d.ts.map +1 -1
- package/build/types/dateLookup/monthCalendar/MonthCalendar.d.ts +17 -2
- package/build/types/dateLookup/monthCalendar/MonthCalendar.d.ts.map +1 -1
- package/build/types/dateLookup/monthCalendar/index.d.ts +1 -1
- package/build/types/dateLookup/monthCalendar/index.d.ts.map +1 -1
- package/build/types/dateLookup/monthCalendar/table/MonthCalendarTable.d.ts +10 -26
- package/build/types/dateLookup/monthCalendar/table/MonthCalendarTable.d.ts.map +1 -1
- package/build/types/dateLookup/monthCalendar/table/index.d.ts +1 -1
- package/build/types/dateLookup/monthCalendar/table/index.d.ts.map +1 -1
- package/build/types/dateLookup/yearCalendar/YearCalendar.d.ts +15 -2
- package/build/types/dateLookup/yearCalendar/YearCalendar.d.ts.map +1 -1
- package/build/types/dateLookup/yearCalendar/index.d.ts +1 -1
- package/build/types/dateLookup/yearCalendar/index.d.ts.map +1 -1
- package/build/types/dateLookup/yearCalendar/table/YearCalendarTable.d.ts +10 -26
- package/build/types/dateLookup/yearCalendar/table/YearCalendarTable.d.ts.map +1 -1
- package/build/types/dateLookup/yearCalendar/table/index.d.ts +1 -1
- package/build/types/dateLookup/yearCalendar/table/index.d.ts.map +1 -1
- package/build/types/index.d.ts +2 -1
- package/build/types/index.d.ts.map +1 -1
- package/build/types/inlineAlert/InlineAlert.d.ts +2 -4
- package/build/types/inlineAlert/InlineAlert.d.ts.map +1 -1
- package/build/types/inputs/SelectInput.d.ts.map +1 -1
- package/build/types/inputs/_BottomSheet.d.ts.map +1 -1
- package/build/types/inputs/_Popover.d.ts.map +1 -1
- package/build/types/statusIcon/StatusIcon.d.ts +1 -1
- package/build/types/statusIcon/StatusIcon.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/alert/{Alert.spec.js → Alert.spec.tsx} +43 -40
- package/src/alert/Alert.story.tsx +1 -2
- package/src/alert/Alert.tsx +218 -0
- package/src/alert/index.ts +2 -0
- package/src/button/Button.tsx +6 -10
- package/src/common/dateUtils/isWithinRange/isWithinRange.spec.ts +21 -0
- package/src/common/dateUtils/isWithinRange/isWithinRange.ts +2 -2
- package/src/common/dateUtils/moveToWithinRange/moveToWithinRange.ts +8 -4
- package/src/common/propsValues/sentiment.ts +0 -10
- package/src/dateLookup/DateLookup.state.spec.js +7 -0
- package/src/dateLookup/{DateLookup.story.js → DateLookup.story.tsx} +13 -14
- package/src/dateLookup/DateLookup.tests.story.tsx +70 -0
- package/src/dateLookup/{DateLookup.js → DateLookup.tsx} +115 -81
- package/src/dateLookup/dateHeader/{DateHeader.js → DateHeader.tsx} +15 -15
- package/src/dateLookup/dateTrigger/DateTrigger.spec.js +0 -22
- package/src/dateLookup/dateTrigger/{DateTrigger.js → DateTrigger.tsx} +15 -32
- package/src/dateLookup/dayCalendar/{DayCalendar.js → DayCalendar.tsx} +14 -21
- package/src/dateLookup/dayCalendar/table/{DayCalendarTable.js → DayCalendarTable.tsx} +26 -37
- package/src/dateLookup/getStartOfDay/{getStartOfDay.js → getStartOfDay.tsx} +1 -1
- package/src/dateLookup/index.ts +2 -0
- package/src/dateLookup/monthCalendar/{MonthCalendar.js → MonthCalendar.tsx} +19 -22
- package/src/dateLookup/monthCalendar/table/{MonthCalendarTable.js → MonthCalendarTable.tsx} +31 -30
- package/src/dateLookup/yearCalendar/{YearCalendar.js → YearCalendar.tsx} +18 -21
- package/src/dateLookup/yearCalendar/table/{YearCalendarTable.js → YearCalendarTable.tsx} +26 -28
- package/src/i18n/th.json +2 -2
- package/src/index.ts +2 -1
- package/src/inlineAlert/InlineAlert.spec.tsx +0 -7
- package/src/inlineAlert/InlineAlert.tsx +19 -47
- package/src/inputs/InputGroup.tsx +3 -3
- package/src/inputs/SelectInput.tsx +1 -0
- package/src/inputs/_BottomSheet.tsx +44 -54
- package/src/inputs/_Popover.tsx +20 -23
- package/src/statusIcon/StatusIcon.tsx +14 -14
- package/build/types/alert/withArrow/alertArrowPositions.d.ts +0 -9
- package/build/types/alert/withArrow/alertArrowPositions.d.ts.map +0 -1
- package/build/types/alert/withArrow/index.d.ts +0 -3
- package/build/types/alert/withArrow/index.d.ts.map +0 -1
- package/build/types/alert/withArrow/withArrow.d.ts +0 -11
- package/build/types/alert/withArrow/withArrow.d.ts.map +0 -1
- package/src/alert/Alert.js +0 -196
- package/src/alert/index.js +0 -1
- package/src/alert/withArrow/alertArrowPositions.ts +0 -9
- package/src/alert/withArrow/index.js +0 -2
- package/src/alert/withArrow/withArrow.js +0 -50
- package/src/alert/withArrow/withArrow.spec.js +0 -51
- package/src/dateLookup/index.js +0 -1
- /package/src/dateLookup/{DateLookup.messages.js → DateLookup.messages.ts} +0 -0
- /package/src/dateLookup/dateHeader/{index.js → index.ts} +0 -0
- /package/src/dateLookup/dateTrigger/{index.js → index.ts} +0 -0
- /package/src/dateLookup/dayCalendar/{index.js → index.ts} +0 -0
- /package/src/dateLookup/dayCalendar/table/{index.js → index.ts} +0 -0
- /package/src/dateLookup/getStartOfDay/{index.js → index.ts} +0 -0
- /package/src/dateLookup/monthCalendar/{index.js → index.ts} +0 -0
- /package/src/dateLookup/monthCalendar/table/{index.js → index.ts} +0 -0
- /package/src/dateLookup/yearCalendar/{index.js → index.ts} +0 -0
- /package/src/dateLookup/yearCalendar/table/{index.js → index.ts} +0 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import classNames from 'classnames';
|
|
2
|
+
import { useState, useRef, useEffect } from 'react';
|
|
3
|
+
|
|
4
|
+
import Body from '../body/Body';
|
|
5
|
+
import { Sentiment, Size, Typography, Variant } from '../common';
|
|
6
|
+
import { CloseButton } from '../common/closeButton';
|
|
7
|
+
import Link from '../link';
|
|
8
|
+
import StatusIcon from '../statusIcon';
|
|
9
|
+
import Title from '../title/Title';
|
|
10
|
+
import { logActionRequired } from '../utilities';
|
|
11
|
+
|
|
12
|
+
import InlineMarkdown from './inlineMarkdown';
|
|
13
|
+
|
|
14
|
+
export type AlertAction = {
|
|
15
|
+
'aria-label'?: string;
|
|
16
|
+
href: string;
|
|
17
|
+
target?: string;
|
|
18
|
+
text: React.ReactNode;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/** @deprecated Use `"top" | "bottom"` instead. */
|
|
22
|
+
type AlertTypeDeprecated = `${Sentiment.SUCCESS | Sentiment.INFO | Sentiment.ERROR}`;
|
|
23
|
+
type AlertTypeResolved = `${
|
|
24
|
+
| Sentiment.POSITIVE
|
|
25
|
+
| Sentiment.NEUTRAL
|
|
26
|
+
| Sentiment.WARNING
|
|
27
|
+
| Sentiment.NEGATIVE}`;
|
|
28
|
+
export type AlertType = AlertTypeResolved | AlertTypeDeprecated;
|
|
29
|
+
|
|
30
|
+
export enum AlertArrowPosition {
|
|
31
|
+
TOP_LEFT = 'up-left',
|
|
32
|
+
TOP = 'up-center',
|
|
33
|
+
TOP_RIGHT = 'up-right',
|
|
34
|
+
BOTTOM_LEFT = 'down-left',
|
|
35
|
+
BOTTOM = 'down-center',
|
|
36
|
+
BOTTOM_RIGHT = 'down-right',
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface AlertProps {
|
|
40
|
+
/** An optional call to action to sit under the main body of the alert. If your label is short, use aria-label to provide more context */
|
|
41
|
+
action?: AlertAction;
|
|
42
|
+
className?: string;
|
|
43
|
+
/** An optional icon. If not provided, we will default the icon to something appropriate for the type */
|
|
44
|
+
icon?: React.ReactElement;
|
|
45
|
+
/** Title for the alert component */
|
|
46
|
+
title?: string;
|
|
47
|
+
/** The main body of the alert. Accepts plain text and bold words specified with **double stars*/
|
|
48
|
+
message?: string;
|
|
49
|
+
/** The presence of the onDismiss handler will trigger the visibility of the close button */
|
|
50
|
+
onDismiss?: React.MouseEventHandler<HTMLButtonElement>;
|
|
51
|
+
/** The type dictates which icon and colour will be used */
|
|
52
|
+
type?: AlertType;
|
|
53
|
+
variant?: `${Variant}`;
|
|
54
|
+
/** @deprecated Use `InlineAlert` instead. */
|
|
55
|
+
arrow?: `${AlertArrowPosition}`;
|
|
56
|
+
/** @deprecated Use `message` instead. Be aware `message` only accepts plain text or text with **bold** markdown. */
|
|
57
|
+
children?: React.ReactNode;
|
|
58
|
+
/** @deprecated Use `onDismiss` instead. */
|
|
59
|
+
dismissible?: boolean;
|
|
60
|
+
/** @deprecated Alert component doesn't support `size` anymore, please remove this prop. */
|
|
61
|
+
size?: `${Size}`;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function resolveType(type: AlertType): AlertTypeResolved {
|
|
65
|
+
switch (type) {
|
|
66
|
+
case 'success':
|
|
67
|
+
return 'positive';
|
|
68
|
+
case 'info':
|
|
69
|
+
return 'neutral';
|
|
70
|
+
case 'error':
|
|
71
|
+
return 'negative';
|
|
72
|
+
}
|
|
73
|
+
return type;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export default function Alert({
|
|
77
|
+
arrow,
|
|
78
|
+
action,
|
|
79
|
+
children,
|
|
80
|
+
className,
|
|
81
|
+
dismissible,
|
|
82
|
+
icon,
|
|
83
|
+
onDismiss,
|
|
84
|
+
message,
|
|
85
|
+
size,
|
|
86
|
+
title,
|
|
87
|
+
type = 'neutral',
|
|
88
|
+
variant = 'desktop',
|
|
89
|
+
}: AlertProps) {
|
|
90
|
+
useEffect(() => {
|
|
91
|
+
if (arrow !== undefined) {
|
|
92
|
+
logActionRequired(
|
|
93
|
+
"Alert component doesn't support 'arrow' anymore, use 'InlineAlert' instead.",
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
}, [arrow]);
|
|
97
|
+
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
if (children !== undefined) {
|
|
100
|
+
logActionRequired(
|
|
101
|
+
"Alert component doesn't support 'children' anymore, use 'message' instead.",
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
}, [children]);
|
|
105
|
+
|
|
106
|
+
useEffect(() => {
|
|
107
|
+
if (dismissible !== undefined) {
|
|
108
|
+
logActionRequired(
|
|
109
|
+
"Alert component doesn't support 'dismissible' anymore, use 'onDismiss' instead.",
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
}, [dismissible]);
|
|
113
|
+
|
|
114
|
+
useEffect(() => {
|
|
115
|
+
if (size !== undefined) {
|
|
116
|
+
logActionRequired("Alert component doesn't support 'size' anymore, please remove that prop.");
|
|
117
|
+
}
|
|
118
|
+
}, [size]);
|
|
119
|
+
|
|
120
|
+
const resolvedType = resolveType(type);
|
|
121
|
+
useEffect(() => {
|
|
122
|
+
if (resolvedType !== type) {
|
|
123
|
+
logActionRequired(
|
|
124
|
+
`Alert component has deprecated '${type}' value for the 'type' prop. Please use '${resolvedType}' instead.`,
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
}, [resolvedType, type]);
|
|
128
|
+
|
|
129
|
+
const [shouldFire, setShouldFire] = useState(false);
|
|
130
|
+
|
|
131
|
+
const closeButtonReference = useRef<HTMLButtonElement>(null);
|
|
132
|
+
|
|
133
|
+
return (
|
|
134
|
+
<div
|
|
135
|
+
className={classNames(
|
|
136
|
+
'alert d-flex',
|
|
137
|
+
`alert-${resolvedType}`,
|
|
138
|
+
arrow != null && alertArrowClassNames(arrow),
|
|
139
|
+
className,
|
|
140
|
+
)}
|
|
141
|
+
data-testid="alert"
|
|
142
|
+
onTouchStart={() => setShouldFire(true)}
|
|
143
|
+
onTouchEnd={(event) => {
|
|
144
|
+
if (
|
|
145
|
+
shouldFire &&
|
|
146
|
+
action &&
|
|
147
|
+
// Check if current event is triggered from closeButton
|
|
148
|
+
event.target instanceof Node &&
|
|
149
|
+
closeButtonReference.current &&
|
|
150
|
+
!closeButtonReference.current.contains(event.target)
|
|
151
|
+
) {
|
|
152
|
+
if (action.target === '_blank') {
|
|
153
|
+
window.top?.open(action.href);
|
|
154
|
+
} else {
|
|
155
|
+
window.top?.location.assign(action.href);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
setShouldFire(false);
|
|
159
|
+
}}
|
|
160
|
+
onTouchMove={() => setShouldFire(false)}
|
|
161
|
+
>
|
|
162
|
+
<div
|
|
163
|
+
className={classNames('alert__content', 'd-flex', 'flex-grow-1', variant)}
|
|
164
|
+
data-testid={variant}
|
|
165
|
+
>
|
|
166
|
+
{icon ? (
|
|
167
|
+
<div className="alert__icon">{icon}</div>
|
|
168
|
+
) : (
|
|
169
|
+
<StatusIcon size={Size.LARGE} sentiment={resolvedType} />
|
|
170
|
+
)}
|
|
171
|
+
<div className="alert__message">
|
|
172
|
+
<div role={Sentiment.NEGATIVE === resolvedType ? 'alert' : 'status'}>
|
|
173
|
+
{title && (
|
|
174
|
+
<Title className="m-b-1" type={Typography.TITLE_BODY}>
|
|
175
|
+
{title}
|
|
176
|
+
</Title>
|
|
177
|
+
)}
|
|
178
|
+
<Body as="span" className="d-block" type={Typography.BODY_LARGE}>
|
|
179
|
+
{children || <InlineMarkdown>{message}</InlineMarkdown>}
|
|
180
|
+
</Body>
|
|
181
|
+
</div>
|
|
182
|
+
{action && (
|
|
183
|
+
<Link
|
|
184
|
+
href={action.href}
|
|
185
|
+
className="m-t-1"
|
|
186
|
+
aria-label={action['aria-label']}
|
|
187
|
+
target={action.target}
|
|
188
|
+
type={Typography.LINK_LARGE}
|
|
189
|
+
>
|
|
190
|
+
{action.text}
|
|
191
|
+
</Link>
|
|
192
|
+
)}
|
|
193
|
+
</div>
|
|
194
|
+
</div>
|
|
195
|
+
{onDismiss && (
|
|
196
|
+
<CloseButton ref={closeButtonReference} className="m-l-2" onClick={onDismiss} />
|
|
197
|
+
)}
|
|
198
|
+
</div>
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function alertArrowClassNames(arrow: `${AlertArrowPosition}`) {
|
|
203
|
+
switch (arrow) {
|
|
204
|
+
case 'down-center':
|
|
205
|
+
return 'arrow arrow-bottom arrow-center';
|
|
206
|
+
case 'down-left':
|
|
207
|
+
return 'arrow arrow-bottom arrow-left';
|
|
208
|
+
case 'down-right':
|
|
209
|
+
return 'arrow arrow-bottom arrow-right';
|
|
210
|
+
case 'up-center':
|
|
211
|
+
return 'arrow arrow-center';
|
|
212
|
+
case 'up-right':
|
|
213
|
+
return 'arrow arrow-right';
|
|
214
|
+
case 'up-left':
|
|
215
|
+
default:
|
|
216
|
+
return 'arrow';
|
|
217
|
+
}
|
|
218
|
+
}
|
package/src/button/Button.tsx
CHANGED
|
@@ -16,7 +16,6 @@ import {
|
|
|
16
16
|
SizeSmall,
|
|
17
17
|
SizeMedium,
|
|
18
18
|
SizeLarge,
|
|
19
|
-
LinkProps,
|
|
20
19
|
} from '../common';
|
|
21
20
|
import ProcessIndicator from '../processIndicator';
|
|
22
21
|
|
|
@@ -30,8 +29,7 @@ type DeprecatedTypes = 'primary' | 'pay' | 'secondary' | 'danger' | 'link';
|
|
|
30
29
|
/** @deprecated */
|
|
31
30
|
type DeprecatedSizes = SizeExtraSmall;
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
as?: ElementType;
|
|
32
|
+
type CommonProps = {
|
|
35
33
|
block?: boolean;
|
|
36
34
|
disabled?: boolean;
|
|
37
35
|
loading?: boolean;
|
|
@@ -40,22 +38,20 @@ export type CommonProps = {
|
|
|
40
38
|
size?: SizeSmall | SizeMedium | SizeLarge | DeprecatedSizes;
|
|
41
39
|
};
|
|
42
40
|
|
|
43
|
-
|
|
44
|
-
Omit<
|
|
41
|
+
type ButtonProps = CommonProps &
|
|
42
|
+
Omit<React.ComponentPropsWithRef<'button'>, 'type'> & {
|
|
45
43
|
as?: 'button';
|
|
46
44
|
htmlType?: 'submit' | 'reset' | 'button';
|
|
47
45
|
};
|
|
48
46
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
Omit<LinkProps, 'href'> & {
|
|
47
|
+
type AnchorProps = CommonProps &
|
|
48
|
+
React.ComponentPropsWithRef<'a'> & {
|
|
52
49
|
as?: 'a';
|
|
53
|
-
href?: string; // Optional due to usage of component with next/link's passHref behavior
|
|
54
50
|
};
|
|
55
51
|
|
|
56
52
|
export type Props = ButtonProps | AnchorProps;
|
|
57
53
|
|
|
58
|
-
|
|
54
|
+
type ButtonReferenceType = HTMLButtonElement | HTMLAnchorElement;
|
|
59
55
|
|
|
60
56
|
const Button = forwardRef<ButtonReferenceType, Props>(
|
|
61
57
|
(
|
|
@@ -22,10 +22,31 @@ describe('isWithinRange', () => {
|
|
|
22
22
|
expect(isWithinRange(date, min, max)).toBe(false);
|
|
23
23
|
});
|
|
24
24
|
|
|
25
|
+
it('returns false when min > date and max is undefined', () => {
|
|
26
|
+
const date = new Date('1995-12-20');
|
|
27
|
+
const min = new Date('1995-12-21');
|
|
28
|
+
const max = null;
|
|
29
|
+
expect(isWithinRange(date, min, max)).toBe(false);
|
|
30
|
+
});
|
|
31
|
+
|
|
25
32
|
it('returns false when date > max', () => {
|
|
26
33
|
const date = new Date('1995-12-23');
|
|
27
34
|
const min = new Date('1995-12-20');
|
|
28
35
|
const max = new Date('1995-12-22');
|
|
29
36
|
expect(isWithinRange(date, min, max)).toBe(false);
|
|
30
37
|
});
|
|
38
|
+
|
|
39
|
+
it('returns false when date > max and min is undefined', () => {
|
|
40
|
+
const date = new Date('1995-12-23');
|
|
41
|
+
const min = null;
|
|
42
|
+
const max = new Date('1995-12-22');
|
|
43
|
+
expect(isWithinRange(date, min, max)).toBe(false);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('returns true when min and max are undefined', () => {
|
|
47
|
+
const date = new Date('1995-12-23');
|
|
48
|
+
const min = null;
|
|
49
|
+
const max = null;
|
|
50
|
+
expect(isWithinRange(date, min, max)).toBe(true);
|
|
51
|
+
});
|
|
31
52
|
});
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export function isWithinRange(date: Date, min: Date, max: Date) {
|
|
2
|
-
return
|
|
1
|
+
export function isWithinRange(date: Date, min: Date | null, max: Date | null) {
|
|
2
|
+
return (!min || date >= min) && (!max || date <= max);
|
|
3
3
|
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import { isWithinRange } from '..';
|
|
2
|
-
|
|
3
1
|
// Makes sure that date is between min and max dates, returns a cloned min or max
|
|
4
|
-
export function moveToWithinRange(date: Date, min: Date, max: Date) {
|
|
5
|
-
|
|
2
|
+
export function moveToWithinRange(date: Date, min: Date | null, max: Date | null) {
|
|
3
|
+
if (min && date < min) {
|
|
4
|
+
return new Date(min);
|
|
5
|
+
}
|
|
6
|
+
if (max && date > max) {
|
|
7
|
+
return new Date(max);
|
|
8
|
+
}
|
|
9
|
+
return date;
|
|
6
10
|
}
|
|
@@ -66,4 +66,11 @@ describe('DateLookup state', () => {
|
|
|
66
66
|
DateLookup.getDerivedStateFromProps(props, defaultState);
|
|
67
67
|
expect(onChange).toHaveBeenCalledWith(new Date(2018, 10, 1));
|
|
68
68
|
});
|
|
69
|
+
|
|
70
|
+
it('updates viewMonth and viewYear to date within min/max on Clear', () => {
|
|
71
|
+
const props = { value: null, min: new Date(2018, 11, 26), max: new Date(2018, 11, 26) };
|
|
72
|
+
const newState = DateLookup.getDerivedStateFromProps(props, defaultState);
|
|
73
|
+
expect(newState.viewMonth).toBe(11);
|
|
74
|
+
expect(newState.viewYear).toBe(2018);
|
|
75
|
+
});
|
|
69
76
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { boolean, select,
|
|
2
|
-
import { userEvent
|
|
1
|
+
import { boolean, select, text, date } from '@storybook/addon-knobs';
|
|
2
|
+
import { userEvent } from '@storybook/test';
|
|
3
3
|
import { useState } from 'react';
|
|
4
4
|
|
|
5
5
|
import { Size } from '../common';
|
|
@@ -13,21 +13,21 @@ export default {
|
|
|
13
13
|
};
|
|
14
14
|
|
|
15
15
|
const epoch = new Date('2011-01-01');
|
|
16
|
-
|
|
16
|
+
const theFuture = new Date(epoch);
|
|
17
17
|
theFuture.setUTCDate(epoch.getUTCDate() + 10);
|
|
18
|
-
|
|
18
|
+
const thePast = new Date(epoch);
|
|
19
19
|
thePast.setUTCDate(epoch.getUTCDate() - 10);
|
|
20
|
+
const size = select('size', Object.values([Size.SMALL, Size.MEDIUM, Size.LARGE]), Size.MEDIUM);
|
|
20
21
|
|
|
21
22
|
export const Basic = () => {
|
|
22
|
-
const [value, setValue] = useState(epoch);
|
|
23
|
+
const [value, setValue] = useState<Date | null>(epoch);
|
|
23
24
|
const disabled = boolean('disabled', false);
|
|
24
25
|
const label = text('label', 'label');
|
|
25
|
-
const monthFormat = select('monthFormat', ['long', 'short']);
|
|
26
|
+
const monthFormat = select('monthFormat', ['long', 'short'], 'long');
|
|
26
27
|
const placeholder = text('placeholder', 'placeholder');
|
|
27
|
-
const size = select('size', Object.values(Size), Size.MEDIUM);
|
|
28
28
|
const id = text('id', 'date-lookup');
|
|
29
29
|
|
|
30
|
-
const clearable = boolean('clearable',
|
|
30
|
+
const clearable = boolean('clearable', true);
|
|
31
31
|
|
|
32
32
|
return (
|
|
33
33
|
<DateLookup
|
|
@@ -35,6 +35,7 @@ export const Basic = () => {
|
|
|
35
35
|
id={id}
|
|
36
36
|
label={label}
|
|
37
37
|
min={thePast}
|
|
38
|
+
max={theFuture}
|
|
38
39
|
monthFormat={monthFormat}
|
|
39
40
|
placeholder={placeholder}
|
|
40
41
|
size={size}
|
|
@@ -48,10 +49,9 @@ export const Basic = () => {
|
|
|
48
49
|
);
|
|
49
50
|
};
|
|
50
51
|
|
|
51
|
-
Basic.play = async ({ canvasElement }) => {
|
|
52
|
+
Basic.play = async ({ canvasElement }: { canvasElement: HTMLElement }) => {
|
|
52
53
|
// testing focus state on keyboard nav
|
|
53
|
-
|
|
54
|
-
await userEvent.tab(canvas.getByRole('button'));
|
|
54
|
+
await userEvent.tab();
|
|
55
55
|
await userEvent.keyboard(' ');
|
|
56
56
|
};
|
|
57
57
|
|
|
@@ -61,12 +61,11 @@ export const Basic400Zoom = storyConfig(
|
|
|
61
61
|
);
|
|
62
62
|
|
|
63
63
|
export const RightAligned = () => {
|
|
64
|
-
const [value, setValue] = useState(epoch);
|
|
64
|
+
const [value, setValue] = useState<Date | null>(epoch);
|
|
65
65
|
const disabled = boolean('disabled', false);
|
|
66
66
|
const label = text('label', 'label');
|
|
67
|
-
const monthFormat = select('monthFormat', ['long', 'short']);
|
|
67
|
+
const monthFormat = select('monthFormat', ['long', 'short'], 'long');
|
|
68
68
|
const placeholder = text('placeholder', 'placeholder');
|
|
69
|
-
const size = select('size', Object.values(Size), Size.MEDIUM);
|
|
70
69
|
|
|
71
70
|
const minvalue = date('minvalue', thePast);
|
|
72
71
|
const maxvalue = date('maxvalue', theFuture);
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { ReactRenderer, Story } from '@storybook/react';
|
|
2
|
+
import { expect, userEvent, within } from '@storybook/test';
|
|
3
|
+
import { PlayFunctionContext } from '@storybook/types';
|
|
4
|
+
import { useState } from 'react';
|
|
5
|
+
|
|
6
|
+
import DateLookup from './DateLookup';
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
component: DateLookup,
|
|
10
|
+
title: 'Forms/DateLookup/Tests',
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const Template: Story<DateLookup> = () => {
|
|
14
|
+
const [value, setValue] = useState<Date | null>(new Date(1987, 0, 10, 12, 0, 0));
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<DateLookup
|
|
18
|
+
value={value}
|
|
19
|
+
clearable
|
|
20
|
+
placeholder="placeholder"
|
|
21
|
+
onChange={(v) => {
|
|
22
|
+
setValue(v);
|
|
23
|
+
}}
|
|
24
|
+
/>
|
|
25
|
+
);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const ClearSpace = Template.bind({});
|
|
29
|
+
|
|
30
|
+
ClearSpace.play = async ({
|
|
31
|
+
canvasElement,
|
|
32
|
+
step,
|
|
33
|
+
}: PlayFunctionContext<ReactRenderer, DateLookup>) => {
|
|
34
|
+
const canvas = within(canvasElement);
|
|
35
|
+
|
|
36
|
+
await step('space can activate clear button', async () => {
|
|
37
|
+
// focus on clear button
|
|
38
|
+
const date = await canvas.findByText('January 10, 1987');
|
|
39
|
+
await expect(date).toBeInTheDocument();
|
|
40
|
+
await userEvent.tab();
|
|
41
|
+
await userEvent.tab();
|
|
42
|
+
|
|
43
|
+
// clear with space
|
|
44
|
+
await userEvent.keyboard(' ');
|
|
45
|
+
const placeholder = canvas.getByText('placeholder');
|
|
46
|
+
await expect(placeholder).toBeInTheDocument();
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export const ClearEnter = Template.bind({});
|
|
51
|
+
|
|
52
|
+
ClearEnter.play = async ({
|
|
53
|
+
canvasElement,
|
|
54
|
+
step,
|
|
55
|
+
}: PlayFunctionContext<ReactRenderer, DateLookup>) => {
|
|
56
|
+
const canvas = within(canvasElement);
|
|
57
|
+
|
|
58
|
+
await step('enter can activate clear button', async () => {
|
|
59
|
+
// focus on clear button
|
|
60
|
+
const date = await canvas.findByText('January 10, 1987');
|
|
61
|
+
await expect(date).toBeInTheDocument();
|
|
62
|
+
await userEvent.tab();
|
|
63
|
+
await userEvent.tab();
|
|
64
|
+
|
|
65
|
+
// clear with space
|
|
66
|
+
await userEvent.keyboard('{enter}');
|
|
67
|
+
const placeholder = canvas.getByText('placeholder');
|
|
68
|
+
await expect(placeholder).toBeInTheDocument();
|
|
69
|
+
});
|
|
70
|
+
};
|