@monolith-forensics/monolith-ui 1.1.0 → 1.1.1
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/package.json +4 -1
- package/Button/Button.tsx +0 -382
- package/Button/index.ts +0 -2
- package/Calendar/Calendar.tsx +0 -376
- package/Calendar/CalendarStyles.tsx +0 -180
- package/Calendar/calendarHelpers.ts +0 -196
- package/Calendar/index.ts +0 -1
- package/CheckBox/CheckBox.tsx +0 -61
- package/CheckBox/index.ts +0 -1
- package/DateInput/DateInput.tsx +0 -717
- package/DateInput/index.ts +0 -1
- package/DropDownMenu/DropDownMenu.tsx +0 -402
- package/DropDownMenu/index.ts +0 -1
- package/Error/Error.tsx +0 -51
- package/Error/index.ts +0 -1
- package/FieldLabel/FieldLabel.tsx +0 -155
- package/FieldLabel/index.ts +0 -1
- package/FileInputField/FileInputField.tsx +0 -179
- package/FileInputField/index.ts +0 -1
- package/Flyout/Flyout.tsx +0 -172
- package/Flyout/FlyoutHeader.tsx +0 -14
- package/Flyout/FlyoutTitle.tsx +0 -10
- package/Flyout/index.ts +0 -3
- package/FormSection/FormSection.tsx +0 -71
- package/FormSection/index.ts +0 -1
- package/Grid/Grid.tsx +0 -18
- package/Grid/index.ts +0 -1
- package/IconButton/IconButton.tsx +0 -27
- package/IconButton/index.ts +0 -1
- package/Input/Input.tsx +0 -164
- package/Input/index.ts +0 -1
- package/Modal/Modal.tsx +0 -172
- package/Modal/index.ts +0 -1
- package/Pill/Pill.tsx +0 -174
- package/Pill/index.ts +0 -1
- package/SelectBox/SelectBox.tsx +0 -745
- package/SelectBox/index.ts +0 -1
- package/Switch/Switch.tsx +0 -204
- package/Switch/index.ts +0 -1
- package/TagBox/TagBox.tsx +0 -694
- package/TagBox/TagBoxStyles.tsx +0 -116
- package/TagBox/index.ts +0 -1
- package/TextArea/TextArea.tsx +0 -92
- package/TextArea/index.ts +0 -1
- package/TextAreaInput/TextAreaInput.tsx +0 -46
- package/TextAreaInput/index.ts +0 -1
- package/TextInput/TextInput.tsx +0 -48
- package/TextInput/index.ts +0 -1
- package/Tooltip/Tooltip.tsx +0 -68
- package/Tooltip/index.ts +0 -1
- package/core/ArrowButton.tsx +0 -51
- package/core/ClearButton.tsx +0 -51
- package/core/MonolithThemeProvider.js +0 -16
- package/core/StyledContent.tsx +0 -50
- package/core/StyledFloatContainer.tsx +0 -7
- package/core/Types/Size.ts +0 -3
- package/core/Types/Variant.ts +0 -10
- package/core/index.ts +0 -6
- package/index.ts +0 -22
- package/theme/breakpoints.js +0 -11
- package/theme/components.js +0 -138
- package/theme/index.js +0 -76
- package/theme/shadows.js +0 -33
- package/theme/typography.js +0 -58
- package/theme/variants.js +0 -234
- package/tsconfig.json +0 -109
package/DateInput/DateInput.tsx
DELETED
|
@@ -1,717 +0,0 @@
|
|
|
1
|
-
import moment from "moment";
|
|
2
|
-
import { useFloating, flip, offset, FloatingPortal } from "@floating-ui/react";
|
|
3
|
-
import React, {
|
|
4
|
-
MutableRefObject,
|
|
5
|
-
useEffect,
|
|
6
|
-
useMemo,
|
|
7
|
-
useRef,
|
|
8
|
-
useState,
|
|
9
|
-
} from "react";
|
|
10
|
-
import styled from "styled-components";
|
|
11
|
-
import { FieldLabel, Calendar } from "..";
|
|
12
|
-
import {
|
|
13
|
-
StyledContent,
|
|
14
|
-
StyledFloatContainer,
|
|
15
|
-
ArrowButton,
|
|
16
|
-
ClearButton,
|
|
17
|
-
Size,
|
|
18
|
-
Variant,
|
|
19
|
-
} from "../core";
|
|
20
|
-
|
|
21
|
-
const StyledInputContainer = styled.div<{
|
|
22
|
-
size: Size;
|
|
23
|
-
variant: Variant;
|
|
24
|
-
}>`
|
|
25
|
-
position: relative;
|
|
26
|
-
|
|
27
|
-
caret-color: transparent;
|
|
28
|
-
user-select: none;
|
|
29
|
-
|
|
30
|
-
display: flex;
|
|
31
|
-
flex-direction: row;
|
|
32
|
-
align-items: center;
|
|
33
|
-
user-select: none;
|
|
34
|
-
|
|
35
|
-
pointer-events: all;
|
|
36
|
-
outline: none;
|
|
37
|
-
|
|
38
|
-
border-radius: 5px;
|
|
39
|
-
transition: border 0.1s ease-in-out;
|
|
40
|
-
border: 1px solid
|
|
41
|
-
${({ theme, variant }) => {
|
|
42
|
-
switch (variant) {
|
|
43
|
-
case "filled":
|
|
44
|
-
return "transparent";
|
|
45
|
-
case "outlined":
|
|
46
|
-
return theme.palette.input.border;
|
|
47
|
-
case "text":
|
|
48
|
-
return "transparent";
|
|
49
|
-
default:
|
|
50
|
-
return theme.palette.input.border;
|
|
51
|
-
}
|
|
52
|
-
}};
|
|
53
|
-
|
|
54
|
-
font-family: ${({ theme }) => theme.typography.fontFamily};
|
|
55
|
-
|
|
56
|
-
color: ${(props) => props.theme.palette.text.primary};
|
|
57
|
-
font-size: ${({ size }) =>
|
|
58
|
-
size === "xs"
|
|
59
|
-
? "11px"
|
|
60
|
-
: size === "sm"
|
|
61
|
-
? "13px"
|
|
62
|
-
: size === "md"
|
|
63
|
-
? "15px"
|
|
64
|
-
: size === "lg"
|
|
65
|
-
? "17px"
|
|
66
|
-
: size === "xl"
|
|
67
|
-
? "19px"
|
|
68
|
-
: "11px"};
|
|
69
|
-
|
|
70
|
-
width: 100%;
|
|
71
|
-
height: ${({ size }) =>
|
|
72
|
-
size === "xs"
|
|
73
|
-
? "26px"
|
|
74
|
-
: size === "sm"
|
|
75
|
-
? "30px"
|
|
76
|
-
: size === "md"
|
|
77
|
-
? "36px"
|
|
78
|
-
: size === "lg"
|
|
79
|
-
? "42px"
|
|
80
|
-
: size === "xl"
|
|
81
|
-
? "50px"
|
|
82
|
-
: "26px"};
|
|
83
|
-
|
|
84
|
-
padding: ${({ size }) =>
|
|
85
|
-
size === "xs"
|
|
86
|
-
? "0px 8px"
|
|
87
|
-
: size === "sm"
|
|
88
|
-
? "0px 10px"
|
|
89
|
-
: size === "md"
|
|
90
|
-
? "0px 12px"
|
|
91
|
-
: size === "lg"
|
|
92
|
-
? "0px 14px"
|
|
93
|
-
: size === "xl"
|
|
94
|
-
? "0px 16px"
|
|
95
|
-
: "0px 8px"};
|
|
96
|
-
|
|
97
|
-
&[data-button-right="true"] {
|
|
98
|
-
padding-right: 36px;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
background-color: ${({ theme, variant }) => {
|
|
102
|
-
switch (variant) {
|
|
103
|
-
case "filled":
|
|
104
|
-
return theme.palette.input.background;
|
|
105
|
-
case "outlined":
|
|
106
|
-
return theme.palette.input.background;
|
|
107
|
-
case "text":
|
|
108
|
-
return "transparent";
|
|
109
|
-
default:
|
|
110
|
-
return theme.palette.input.background;
|
|
111
|
-
}
|
|
112
|
-
}};
|
|
113
|
-
|
|
114
|
-
&[readOnly] {
|
|
115
|
-
cursor: pointer;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
& [data-has-space="true"] {
|
|
119
|
-
padding-left: 4px;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
& [data-selected="true"] {
|
|
123
|
-
background-color: ${(props) => props.theme.palette.primary.main}50;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
&[data-empty="true"] {
|
|
127
|
-
color: ${(props) => props.theme.palette.input.placeholder};
|
|
128
|
-
div {
|
|
129
|
-
color: ${(props) => props.theme.palette.input.placeholder};
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
& [data-default-btn="true"] {
|
|
134
|
-
color: ${(props) => props.theme.palette.text.secondary};
|
|
135
|
-
div {
|
|
136
|
-
color: ${(props) => props.theme.palette.text.secondary};
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
&:focus {
|
|
141
|
-
border: 1px solid ${(props) => props.theme.palette.primary.main};
|
|
142
|
-
}
|
|
143
|
-
`;
|
|
144
|
-
|
|
145
|
-
const InputSegment = styled.div<{
|
|
146
|
-
size: Size;
|
|
147
|
-
}>`
|
|
148
|
-
user-select: none;
|
|
149
|
-
display: flex;
|
|
150
|
-
flex-direction: row;
|
|
151
|
-
align-items: center;
|
|
152
|
-
pointer-events: all;
|
|
153
|
-
outline: none;
|
|
154
|
-
border: none;
|
|
155
|
-
padding: 0;
|
|
156
|
-
|
|
157
|
-
height: ${({ size }) =>
|
|
158
|
-
size === "xs"
|
|
159
|
-
? "22px"
|
|
160
|
-
: size === "sm"
|
|
161
|
-
? "26px"
|
|
162
|
-
: size === "md"
|
|
163
|
-
? "32px"
|
|
164
|
-
: size === "lg"
|
|
165
|
-
? "38px"
|
|
166
|
-
: size === "xl"
|
|
167
|
-
? "46px"
|
|
168
|
-
: "22px"};
|
|
169
|
-
|
|
170
|
-
height: 100%;
|
|
171
|
-
|
|
172
|
-
background-color: transparent;
|
|
173
|
-
color: ${(props) => props.theme.palette.text.primary};
|
|
174
|
-
|
|
175
|
-
::placeholder {
|
|
176
|
-
font-size: ${({ size }) =>
|
|
177
|
-
size === "xs"
|
|
178
|
-
? "10px"
|
|
179
|
-
: size === "sm"
|
|
180
|
-
? "12px"
|
|
181
|
-
: size === "md"
|
|
182
|
-
? "14px"
|
|
183
|
-
: size === "lg"
|
|
184
|
-
? "16px"
|
|
185
|
-
: size === "xl"
|
|
186
|
-
? "18px"
|
|
187
|
-
: "10px"};
|
|
188
|
-
}
|
|
189
|
-
`;
|
|
190
|
-
|
|
191
|
-
type Segment = {
|
|
192
|
-
value: string;
|
|
193
|
-
text: string;
|
|
194
|
-
placeholder: string;
|
|
195
|
-
type: moment.unitOfTime.DurationConstructor | "separator";
|
|
196
|
-
index: number;
|
|
197
|
-
momentType?: moment.unitOfTime.All | moment.unitOfTime.DurationConstructor;
|
|
198
|
-
pattern?: string;
|
|
199
|
-
};
|
|
200
|
-
|
|
201
|
-
function parseTimestamp(
|
|
202
|
-
timestamp: string,
|
|
203
|
-
format: string,
|
|
204
|
-
utc = false
|
|
205
|
-
): Segment[] {
|
|
206
|
-
// Define patterns to identify datetime components and their placeholders
|
|
207
|
-
const patterns = [
|
|
208
|
-
{ pattern: "YYYY", placeholder: "YYYY", type: "year", momentType: "year" },
|
|
209
|
-
{ pattern: "MM", placeholder: "MM", type: "month", momentType: "month" },
|
|
210
|
-
{ pattern: "DD", placeholder: "DD", type: "day", momentType: "date" },
|
|
211
|
-
{ pattern: "HH", placeholder: "HH", type: "hour", momentType: "hour" },
|
|
212
|
-
{ pattern: "h", placeholder: "h", type: "hour", momentType: "hour" },
|
|
213
|
-
{ pattern: "mm", placeholder: "mm", type: "minute", momentType: "minute" },
|
|
214
|
-
{ pattern: "ss", placeholder: "ss", type: "second", momentType: "second" },
|
|
215
|
-
{
|
|
216
|
-
pattern: "SSS",
|
|
217
|
-
placeholder: "SSS",
|
|
218
|
-
type: "millisecond",
|
|
219
|
-
momentType: "millisecond",
|
|
220
|
-
},
|
|
221
|
-
{
|
|
222
|
-
pattern: "A",
|
|
223
|
-
placeholder: "AM/PM",
|
|
224
|
-
type: "meridiem",
|
|
225
|
-
momentType: "meridiem",
|
|
226
|
-
},
|
|
227
|
-
{
|
|
228
|
-
pattern: "Z",
|
|
229
|
-
placeholder: "Z",
|
|
230
|
-
type: "timezone",
|
|
231
|
-
momentType: "timezone",
|
|
232
|
-
},
|
|
233
|
-
] as Segment[];
|
|
234
|
-
|
|
235
|
-
// Helper function to split format into datetime components and separators
|
|
236
|
-
function splitFormat(format: string) {
|
|
237
|
-
return format.split(/(YYYY|MM|DD|HH|h|mm|ss|SSS|Z)/).filter((s) => s);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// Helper function to match segments to their placeholders and types
|
|
241
|
-
function matchSegment(segment: string): Segment {
|
|
242
|
-
const pattern = patterns.find((p) => p.pattern === segment);
|
|
243
|
-
return pattern
|
|
244
|
-
? pattern
|
|
245
|
-
: {
|
|
246
|
-
pattern: segment,
|
|
247
|
-
placeholder: segment,
|
|
248
|
-
type: "separator",
|
|
249
|
-
value: "",
|
|
250
|
-
text: "",
|
|
251
|
-
index: -1,
|
|
252
|
-
};
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
const segments = splitFormat(format).map((segment, i) => {
|
|
256
|
-
const { pattern, placeholder, type, momentType } = matchSegment(segment);
|
|
257
|
-
const value = timestamp
|
|
258
|
-
? utc === true
|
|
259
|
-
? moment.utc(timestamp).format(pattern)
|
|
260
|
-
: moment(timestamp).format(pattern)
|
|
261
|
-
: placeholder;
|
|
262
|
-
|
|
263
|
-
return {
|
|
264
|
-
value,
|
|
265
|
-
text: value,
|
|
266
|
-
placeholder,
|
|
267
|
-
type,
|
|
268
|
-
momentType,
|
|
269
|
-
index: i,
|
|
270
|
-
};
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
return segments;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
interface DateInputProps {
|
|
277
|
-
className?: string;
|
|
278
|
-
defaultValue?: string | null;
|
|
279
|
-
format?: string;
|
|
280
|
-
label?: string;
|
|
281
|
-
description?: string;
|
|
282
|
-
arrow?: boolean;
|
|
283
|
-
size?: Size;
|
|
284
|
-
variant?: Variant;
|
|
285
|
-
clearable?: boolean;
|
|
286
|
-
required?: boolean;
|
|
287
|
-
onChange?: (value: string | null) => void;
|
|
288
|
-
min?: Date;
|
|
289
|
-
max?: Date;
|
|
290
|
-
error?: string;
|
|
291
|
-
width?: string;
|
|
292
|
-
enableCalendar?: boolean;
|
|
293
|
-
utc?: boolean;
|
|
294
|
-
closeOnSelect?: boolean;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
const DateInput = styled(
|
|
298
|
-
({
|
|
299
|
-
className,
|
|
300
|
-
defaultValue = null,
|
|
301
|
-
format = "YYYY-MM-DD HH:mm:ss",
|
|
302
|
-
label,
|
|
303
|
-
description,
|
|
304
|
-
arrow = true,
|
|
305
|
-
size = "sm",
|
|
306
|
-
variant = "outlined",
|
|
307
|
-
clearable = false,
|
|
308
|
-
required = false,
|
|
309
|
-
onChange = () => {},
|
|
310
|
-
min,
|
|
311
|
-
max,
|
|
312
|
-
error,
|
|
313
|
-
enableCalendar = false,
|
|
314
|
-
utc = false,
|
|
315
|
-
closeOnSelect = true,
|
|
316
|
-
}: DateInputProps) => {
|
|
317
|
-
const [value, setValue] = useState<string | null>(defaultValue);
|
|
318
|
-
const [selectedSegment, setSelectedSegment] = useState<
|
|
319
|
-
Segment | null | undefined
|
|
320
|
-
>();
|
|
321
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
322
|
-
|
|
323
|
-
// Check if format is date only and does not include time
|
|
324
|
-
const isDateOnly = format.match(/(HH|h|mm|ss|SSS|A|Z)/) === null;
|
|
325
|
-
|
|
326
|
-
const mainRef: MutableRefObject<HTMLElement | null> =
|
|
327
|
-
useRef<HTMLElement>(null);
|
|
328
|
-
|
|
329
|
-
const typedKeys = useRef("");
|
|
330
|
-
|
|
331
|
-
const { refs, floatingStyles } = useFloating({
|
|
332
|
-
open: isOpen,
|
|
333
|
-
onOpenChange: setIsOpen,
|
|
334
|
-
placement: "bottom-start",
|
|
335
|
-
strategy: "absolute",
|
|
336
|
-
// Handle collisions with the viewport
|
|
337
|
-
middleware: [flip(), offset(5)],
|
|
338
|
-
});
|
|
339
|
-
|
|
340
|
-
const segments: Segment[] = useMemo(
|
|
341
|
-
() => parseTimestamp(moment(value).toISOString(), format, utc),
|
|
342
|
-
[value, format, utc]
|
|
343
|
-
);
|
|
344
|
-
|
|
345
|
-
const checkValidRange = (value: string) => {
|
|
346
|
-
if (min && moment(value).isBefore(min)) return false;
|
|
347
|
-
if (max && moment(value).isAfter(max)) return false;
|
|
348
|
-
return true;
|
|
349
|
-
};
|
|
350
|
-
|
|
351
|
-
const toggleOpen = () => {
|
|
352
|
-
setIsOpen((prev) => {
|
|
353
|
-
return !prev;
|
|
354
|
-
});
|
|
355
|
-
};
|
|
356
|
-
|
|
357
|
-
const handleClear = (e: React.MouseEvent) => {
|
|
358
|
-
e.preventDefault();
|
|
359
|
-
e.stopPropagation();
|
|
360
|
-
|
|
361
|
-
setValue(null);
|
|
362
|
-
onChange?.(null);
|
|
363
|
-
setIsOpen(false);
|
|
364
|
-
};
|
|
365
|
-
|
|
366
|
-
const handleSegmentClick = (e: React.MouseEvent, segment: Segment) => {
|
|
367
|
-
e.stopPropagation();
|
|
368
|
-
e.preventDefault();
|
|
369
|
-
if (segment.type === "separator") return;
|
|
370
|
-
if (mainRef?.current) {
|
|
371
|
-
const input: HTMLInputElement | null = mainRef.current.querySelector(
|
|
372
|
-
"div[data-type='input']"
|
|
373
|
-
);
|
|
374
|
-
if (input) {
|
|
375
|
-
input.focus();
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
setSelectedSegment(segment);
|
|
379
|
-
};
|
|
380
|
-
|
|
381
|
-
const handleContainerClick = (e: React.MouseEvent) => {
|
|
382
|
-
e.stopPropagation();
|
|
383
|
-
e.preventDefault();
|
|
384
|
-
if (mainRef?.current) {
|
|
385
|
-
const input: HTMLInputElement | null = mainRef.current.querySelector(
|
|
386
|
-
"div[data-type='input']"
|
|
387
|
-
);
|
|
388
|
-
if (input) {
|
|
389
|
-
input.focus();
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
toggleOpen();
|
|
393
|
-
setIsOpen(true);
|
|
394
|
-
setSelectedSegment(segments[0]);
|
|
395
|
-
};
|
|
396
|
-
|
|
397
|
-
const nextSegment = () => {
|
|
398
|
-
setSelectedSegment((prev) => {
|
|
399
|
-
if (!prev) return segments[0];
|
|
400
|
-
const next = segments[prev.index + 2];
|
|
401
|
-
return next || prev;
|
|
402
|
-
});
|
|
403
|
-
};
|
|
404
|
-
|
|
405
|
-
// prevent click and drag selection
|
|
406
|
-
const handleMouseDown = (
|
|
407
|
-
e: React.MouseEvent<HTMLDivElement, MouseEvent>
|
|
408
|
-
) => {
|
|
409
|
-
e.preventDefault();
|
|
410
|
-
};
|
|
411
|
-
|
|
412
|
-
const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {
|
|
413
|
-
if (!selectedSegment) return;
|
|
414
|
-
// tab
|
|
415
|
-
if (e.key === "Tab") {
|
|
416
|
-
setSelectedSegment(null);
|
|
417
|
-
setIsOpen(false);
|
|
418
|
-
return;
|
|
419
|
-
}
|
|
420
|
-
// Right Arrow
|
|
421
|
-
if (e.key === "ArrowRight") {
|
|
422
|
-
e.preventDefault();
|
|
423
|
-
|
|
424
|
-
setSelectedSegment((prev) => {
|
|
425
|
-
if (!prev) return segments[0];
|
|
426
|
-
const next = segments[prev.index + 2];
|
|
427
|
-
return next || prev;
|
|
428
|
-
});
|
|
429
|
-
}
|
|
430
|
-
// Left Arrow
|
|
431
|
-
if (e.key === "ArrowLeft") {
|
|
432
|
-
e.preventDefault();
|
|
433
|
-
setSelectedSegment((prev) => {
|
|
434
|
-
if (!prev) return segments[0];
|
|
435
|
-
const next = segments[prev.index - 2];
|
|
436
|
-
return next || prev;
|
|
437
|
-
});
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
// Up Arrow
|
|
441
|
-
if (e.key === "ArrowUp") {
|
|
442
|
-
e.preventDefault();
|
|
443
|
-
|
|
444
|
-
setValue((prev) => {
|
|
445
|
-
if (selectedSegment.type === "separator") return prev;
|
|
446
|
-
let newValue = prev
|
|
447
|
-
? moment(prev).add(1, selectedSegment.type).toISOString()
|
|
448
|
-
: moment().toISOString();
|
|
449
|
-
if (!checkValidRange(newValue)) return prev;
|
|
450
|
-
if (isDateOnly) {
|
|
451
|
-
newValue = moment(newValue).format("YYYY-MM-DD");
|
|
452
|
-
}
|
|
453
|
-
onChange?.(newValue);
|
|
454
|
-
return newValue;
|
|
455
|
-
});
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
// Down Arrow
|
|
459
|
-
if (e.key === "ArrowDown") {
|
|
460
|
-
e.preventDefault();
|
|
461
|
-
|
|
462
|
-
setValue((prev) => {
|
|
463
|
-
if (selectedSegment.type === "separator") return prev;
|
|
464
|
-
let newValue = prev
|
|
465
|
-
? moment(prev).subtract(1, selectedSegment.type).toISOString()
|
|
466
|
-
: moment().toISOString();
|
|
467
|
-
if (!checkValidRange(newValue)) return prev;
|
|
468
|
-
|
|
469
|
-
if (isDateOnly) {
|
|
470
|
-
newValue = moment(newValue).format("YYYY-MM-DD");
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
onChange?.(newValue);
|
|
474
|
-
return newValue;
|
|
475
|
-
});
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
// handle paste
|
|
479
|
-
if (e.key === "v" && (e.metaKey || e.ctrlKey)) {
|
|
480
|
-
return;
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
// only allow numbers
|
|
484
|
-
if (e.key.match(/[0-9]/)) {
|
|
485
|
-
e.preventDefault();
|
|
486
|
-
const segmentLength = selectedSegment.text.length;
|
|
487
|
-
|
|
488
|
-
typedKeys.current += e.key;
|
|
489
|
-
let tempValue = typedKeys.current;
|
|
490
|
-
|
|
491
|
-
if (
|
|
492
|
-
["month", "day"].includes(selectedSegment.type) &&
|
|
493
|
-
Array.from(tempValue).every((c) => c === "0")
|
|
494
|
-
) {
|
|
495
|
-
tempValue = "01";
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
setValue((prev) => {
|
|
499
|
-
if (!selectedSegment?.momentType) return prev;
|
|
500
|
-
const newValue = moment(prev)
|
|
501
|
-
.set(
|
|
502
|
-
selectedSegment.momentType,
|
|
503
|
-
parseInt(tempValue, 10) -
|
|
504
|
-
(selectedSegment.type === "month" ? 1 : 0)
|
|
505
|
-
)
|
|
506
|
-
.toISOString();
|
|
507
|
-
if (!checkValidRange(newValue)) return prev;
|
|
508
|
-
onChange?.(newValue);
|
|
509
|
-
return newValue;
|
|
510
|
-
});
|
|
511
|
-
|
|
512
|
-
if (typedKeys.current.length === segmentLength) {
|
|
513
|
-
nextSegment();
|
|
514
|
-
typedKeys.current = "";
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
e.preventDefault();
|
|
519
|
-
};
|
|
520
|
-
|
|
521
|
-
const handleWheelEvent = (e: WheelEvent) => {
|
|
522
|
-
if (!selectedSegment) return;
|
|
523
|
-
|
|
524
|
-
if (e.deltaY > 0) {
|
|
525
|
-
setValue((prev) => {
|
|
526
|
-
if (selectedSegment.type === "separator") return prev;
|
|
527
|
-
const newValue = prev
|
|
528
|
-
? moment(prev).subtract(1, selectedSegment.type).toISOString()
|
|
529
|
-
: moment().toISOString();
|
|
530
|
-
if (!checkValidRange(newValue)) return prev;
|
|
531
|
-
onChange?.(newValue);
|
|
532
|
-
return newValue;
|
|
533
|
-
});
|
|
534
|
-
} else {
|
|
535
|
-
setValue((prev) => {
|
|
536
|
-
if (selectedSegment.type === "separator") return prev;
|
|
537
|
-
const newValue = prev
|
|
538
|
-
? moment(prev).add(1, selectedSegment.type).toISOString()
|
|
539
|
-
: moment().toISOString();
|
|
540
|
-
if (!checkValidRange(newValue)) return prev;
|
|
541
|
-
onChange?.(newValue);
|
|
542
|
-
return newValue;
|
|
543
|
-
});
|
|
544
|
-
}
|
|
545
|
-
};
|
|
546
|
-
|
|
547
|
-
const handlePaste = (e: React.ClipboardEvent<HTMLDivElement>) => {
|
|
548
|
-
e.preventDefault();
|
|
549
|
-
const pastedText = e?.clipboardData?.getData?.("text");
|
|
550
|
-
if (!pastedText) return;
|
|
551
|
-
|
|
552
|
-
// check if pasted text is a valid timestamp
|
|
553
|
-
if (!moment(pastedText).isValid()) return;
|
|
554
|
-
|
|
555
|
-
const parsedTimestamp = moment.utc(pastedText).toISOString();
|
|
556
|
-
|
|
557
|
-
setValue(parsedTimestamp);
|
|
558
|
-
};
|
|
559
|
-
|
|
560
|
-
// Close on outside click
|
|
561
|
-
useEffect(() => {
|
|
562
|
-
const close = (e: MouseEvent) => {
|
|
563
|
-
const target = e.target as Node;
|
|
564
|
-
const referenceElement = refs?.reference?.current as Node;
|
|
565
|
-
const floatingElement = refs?.floating?.current as Node;
|
|
566
|
-
|
|
567
|
-
if (
|
|
568
|
-
floatingElement && // Check if the floating element exists
|
|
569
|
-
e.target !== referenceElement && // Check if the target is not the reference (input)
|
|
570
|
-
!referenceElement.contains(target) && // Check if the target is not inside the reference (input)
|
|
571
|
-
!floatingElement.contains(target) // Check if the target is not inside the floating element (content)
|
|
572
|
-
) {
|
|
573
|
-
setIsOpen(false);
|
|
574
|
-
}
|
|
575
|
-
setSelectedSegment(null); // clear selected segment when clicked outside component
|
|
576
|
-
};
|
|
577
|
-
document.addEventListener("click", close);
|
|
578
|
-
return () => document.removeEventListener("click", close);
|
|
579
|
-
}, [refs.floating]);
|
|
580
|
-
|
|
581
|
-
// Global Wheel Event when segement selected
|
|
582
|
-
useEffect(() => {
|
|
583
|
-
if (selectedSegment) {
|
|
584
|
-
document.addEventListener("wheel", handleWheelEvent);
|
|
585
|
-
}
|
|
586
|
-
return () => {
|
|
587
|
-
document.removeEventListener("wheel", handleWheelEvent);
|
|
588
|
-
};
|
|
589
|
-
}, [selectedSegment]);
|
|
590
|
-
|
|
591
|
-
return (
|
|
592
|
-
<div className={className}>
|
|
593
|
-
{label && (
|
|
594
|
-
<FieldLabel
|
|
595
|
-
error={error}
|
|
596
|
-
asterisk={required}
|
|
597
|
-
size={size}
|
|
598
|
-
description={description}
|
|
599
|
-
>
|
|
600
|
-
{label}
|
|
601
|
-
</FieldLabel>
|
|
602
|
-
)}
|
|
603
|
-
<StyledInputContainer
|
|
604
|
-
ref={(ref) => {
|
|
605
|
-
mainRef.current = ref;
|
|
606
|
-
refs.setReference(ref);
|
|
607
|
-
}}
|
|
608
|
-
onClick={handleContainerClick}
|
|
609
|
-
onMouseDown={handleMouseDown}
|
|
610
|
-
onKeyDown={handleKeyDown}
|
|
611
|
-
onPaste={handlePaste}
|
|
612
|
-
onFocus={(e) => {
|
|
613
|
-
e.preventDefault();
|
|
614
|
-
setSelectedSegment(segments[0]);
|
|
615
|
-
}}
|
|
616
|
-
data-empty={!value}
|
|
617
|
-
role="textbox"
|
|
618
|
-
size={size}
|
|
619
|
-
variant={variant}
|
|
620
|
-
data-button-right={arrow || clearable}
|
|
621
|
-
>
|
|
622
|
-
{segments.map((segment, i) => {
|
|
623
|
-
if (segment.type === "separator") {
|
|
624
|
-
return (
|
|
625
|
-
<div
|
|
626
|
-
className="separator"
|
|
627
|
-
key={i}
|
|
628
|
-
tabIndex={-1}
|
|
629
|
-
onClick={(e) => {
|
|
630
|
-
e.preventDefault();
|
|
631
|
-
e.stopPropagation();
|
|
632
|
-
}}
|
|
633
|
-
onFocus={(e) => e.preventDefault()}
|
|
634
|
-
onPointerDown={(e) => e.preventDefault()}
|
|
635
|
-
data-type="separator"
|
|
636
|
-
data-identifier={segment.type}
|
|
637
|
-
data-has-space={segment.text.includes(" ")}
|
|
638
|
-
data-placeholder={segment.placeholder}
|
|
639
|
-
data-value={segment.value}
|
|
640
|
-
>
|
|
641
|
-
{segment.text}
|
|
642
|
-
</div>
|
|
643
|
-
);
|
|
644
|
-
}
|
|
645
|
-
return (
|
|
646
|
-
<InputSegment
|
|
647
|
-
className={"input"}
|
|
648
|
-
contentEditable
|
|
649
|
-
suppressContentEditableWarning
|
|
650
|
-
key={i}
|
|
651
|
-
tabIndex={i === 0 ? 0 : -1}
|
|
652
|
-
onClick={(e) => handleSegmentClick(e, segment)}
|
|
653
|
-
data-type="input"
|
|
654
|
-
size={size}
|
|
655
|
-
data-identifier={segment.type}
|
|
656
|
-
data-has-space={segment.text.includes(" ")}
|
|
657
|
-
data-placeholder={segment.placeholder}
|
|
658
|
-
data-value={segment.value}
|
|
659
|
-
data-selected={selectedSegment?.index === segment.index}
|
|
660
|
-
>
|
|
661
|
-
{value ? segment.text : segment.placeholder}
|
|
662
|
-
</InputSegment>
|
|
663
|
-
);
|
|
664
|
-
})}
|
|
665
|
-
{utc && <div style={{ marginLeft: 5 }}>UTC</div>}
|
|
666
|
-
{clearable && value ? (
|
|
667
|
-
<ClearButton onClick={handleClear} />
|
|
668
|
-
) : arrow ? (
|
|
669
|
-
<ArrowButton />
|
|
670
|
-
) : null}
|
|
671
|
-
</StyledInputContainer>
|
|
672
|
-
{enableCalendar && isOpen && (
|
|
673
|
-
<FloatingPortal preserveTabOrder>
|
|
674
|
-
<StyledFloatContainer ref={refs.setFloating} style={floatingStyles}>
|
|
675
|
-
<StyledContent maxDropdownHeight="fit-content">
|
|
676
|
-
<div>
|
|
677
|
-
<Calendar
|
|
678
|
-
key={1}
|
|
679
|
-
value={moment(value).toDate()}
|
|
680
|
-
clearable={false}
|
|
681
|
-
min={min}
|
|
682
|
-
max={max}
|
|
683
|
-
// hourFormat={hourFormat}
|
|
684
|
-
onChange={(date) => {
|
|
685
|
-
setValue((prev) => {
|
|
686
|
-
// make copy of prev variable
|
|
687
|
-
const oldValue = moment(prev).toISOString();
|
|
688
|
-
|
|
689
|
-
const result = `${moment(date).format(
|
|
690
|
-
"YYYY-MM-DD"
|
|
691
|
-
)}T${moment(prev || undefined).format("HH:mm:ss")}`;
|
|
692
|
-
|
|
693
|
-
let isoResult = moment(result).toISOString();
|
|
694
|
-
|
|
695
|
-
if (!checkValidRange(result)) return oldValue;
|
|
696
|
-
|
|
697
|
-
if (isDateOnly) {
|
|
698
|
-
isoResult = moment(result).format("YYYY-MM-DD");
|
|
699
|
-
}
|
|
700
|
-
onChange?.(isoResult);
|
|
701
|
-
setIsOpen(closeOnSelect ? false : true);
|
|
702
|
-
return isoResult;
|
|
703
|
-
});
|
|
704
|
-
}}
|
|
705
|
-
includeTime={false}
|
|
706
|
-
/>
|
|
707
|
-
</div>
|
|
708
|
-
</StyledContent>
|
|
709
|
-
</StyledFloatContainer>
|
|
710
|
-
</FloatingPortal>
|
|
711
|
-
)}
|
|
712
|
-
</div>
|
|
713
|
-
);
|
|
714
|
-
}
|
|
715
|
-
)``;
|
|
716
|
-
|
|
717
|
-
export default DateInput;
|
package/DateInput/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default } from "./DateInput";
|