@jobber/components 6.38.4 → 6.39.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/dist/Chip/Chip.d.ts +5 -5
- package/dist/Chip/Chip.types.d.ts +64 -0
- package/dist/Chip/index.d.ts +1 -0
- package/dist/Chip-cjs.js +2 -2
- package/dist/Chip-es.js +2 -2
- package/dist/Chips/ChipsTypes.d.ts +12 -0
- package/dist/Chips/InternalChipDismissible/InternalChipDismissibleTypes.d.ts +12 -0
- package/dist/Chips/InternalChipDismissible/hooks/useInternalChipDismissibleInput.d.ts +4 -1
- package/dist/FormField/FormFieldWrapper.d.ts +2 -1
- package/dist/FormField-cjs.js +5 -4
- package/dist/FormField-es.js +5 -4
- package/dist/InputTime/InputTime.d.ts +1 -2
- package/dist/InputTime/InputTime.rebuilt.d.ts +2 -0
- package/dist/InputTime/{InputTimeProps.d.ts → InputTime.types.d.ts} +9 -0
- package/dist/InputTime/hooks/useTimePredict.d.ts +1 -1
- package/dist/InputTime/index.cjs +275 -13
- package/dist/InputTime/index.d.ts +3 -1
- package/dist/InputTime/index.mjs +278 -12
- package/dist/InputTime/utils/input-time-utils.d.ts +2 -0
- package/dist/InternalChipDismissible-cjs.js +7 -7
- package/dist/InternalChipDismissible-es.js +7 -7
- package/dist/index.cjs +2 -2
- package/dist/index.mjs +1 -1
- package/dist/useScrollToActive-cjs.js +50 -13
- package/dist/useScrollToActive-es.js +50 -13
- package/package.json +2 -2
- package/dist/InputTime-cjs.js +0 -209
- package/dist/InputTime-es.js +0 -207
package/dist/Chip/Chip.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ChipPrefix } from "./components/ChipPrefix/Chip.Prefix";
|
|
2
2
|
import { ChipSuffix } from "./components/ChipSuffix/Chip.Suffix";
|
|
3
3
|
import { ChipProps } from "./Chip.types";
|
|
4
|
-
export declare
|
|
5
|
-
|
|
6
|
-
Prefix: typeof ChipPrefix;
|
|
7
|
-
Suffix: typeof ChipSuffix;
|
|
8
|
-
}
|
|
4
|
+
export declare function Chip({ ariaLabel, disabled, heading, invalid, label, value, testID, onClick, onKeyDown, children, role, tabIndex, variation, }: ChipProps): JSX.Element;
|
|
5
|
+
export declare namespace Chip {
|
|
6
|
+
var Prefix: typeof ChipPrefix;
|
|
7
|
+
var Suffix: typeof ChipSuffix;
|
|
8
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import React, { PropsWithChildren } from "react";
|
|
2
|
+
export interface ChipProps extends PropsWithChildren {
|
|
3
|
+
/**
|
|
4
|
+
* Accessible label, which can be different from the primary label.
|
|
5
|
+
*/
|
|
6
|
+
readonly ariaLabel?: string;
|
|
7
|
+
/**
|
|
8
|
+
* The testing id for the chip if necessary.
|
|
9
|
+
*/
|
|
10
|
+
testID?: string;
|
|
11
|
+
/**
|
|
12
|
+
* Disables both mouse and keyboard functionality, and updates the visual style of the Chip to appear disabled.
|
|
13
|
+
*/
|
|
14
|
+
readonly disabled?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Adds more prominent text to act as a heading. Will be displayed on the left with a | separator.
|
|
17
|
+
*/
|
|
18
|
+
readonly heading?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Changes Chip styling to inform the user of an issue.
|
|
21
|
+
*/
|
|
22
|
+
readonly invalid?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* The content of the chip. Will be displayed on the right if you include a heading.
|
|
25
|
+
*/
|
|
26
|
+
readonly label: string;
|
|
27
|
+
/**
|
|
28
|
+
* The accessible role the Chip is fulfilling. Defaults to 'button'
|
|
29
|
+
*/
|
|
30
|
+
readonly role?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Used for accessibility purpopses, specifically using the tab key as navigation.
|
|
33
|
+
* @default 0
|
|
34
|
+
*/
|
|
35
|
+
readonly tabIndex?: number;
|
|
36
|
+
/**
|
|
37
|
+
* Will be passed to onClick, when the user clicks on this Chip.
|
|
38
|
+
*/
|
|
39
|
+
readonly value?: string | number;
|
|
40
|
+
/**
|
|
41
|
+
* Button style variation. Does not affect functionality.
|
|
42
|
+
* @default "base"
|
|
43
|
+
*/
|
|
44
|
+
readonly variation?: ChipVariations;
|
|
45
|
+
/**
|
|
46
|
+
* Chip Click Callback. Sends an event and sometimes a value (SelectableChip).
|
|
47
|
+
*/
|
|
48
|
+
readonly onClick?: (value: string | number | undefined, ev: React.MouseEvent<HTMLButtonElement | HTMLDivElement>) => void;
|
|
49
|
+
/**
|
|
50
|
+
* Callback. Called when you keydown on Chip. Ships the event, so you can get the key pushed.
|
|
51
|
+
*/
|
|
52
|
+
readonly onKeyDown?: (ev: React.KeyboardEvent<HTMLButtonElement | HTMLDivElement>) => void;
|
|
53
|
+
}
|
|
54
|
+
export type ChipVariations = "subtle" | "base";
|
|
55
|
+
export interface ChipSelectableProps extends ChipProps {
|
|
56
|
+
/**
|
|
57
|
+
* Is Chip selected?
|
|
58
|
+
*/
|
|
59
|
+
readonly selected?: boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Send this back onClick. Good for determining which Chip was clicked.
|
|
62
|
+
*/
|
|
63
|
+
readonly value?: string | number;
|
|
64
|
+
}
|
package/dist/Chip/index.d.ts
CHANGED
package/dist/Chip-cjs.js
CHANGED
|
@@ -75,7 +75,7 @@ const allowedSuffixIcons = [
|
|
|
75
75
|
"arrowDown",
|
|
76
76
|
];
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
function Chip({ ariaLabel, disabled, heading, invalid, label, value, testID, onClick, onKeyDown, children, role = "button", tabIndex = 0, variation = "base", }) {
|
|
79
79
|
const classes = classnames(styles$1.chip, {
|
|
80
80
|
[styles$1.invalid]: invalid,
|
|
81
81
|
[styles$1.base]: variation === "base",
|
|
@@ -103,7 +103,7 @@ const Chip = ({ ariaLabel, disabled, heading, invalid, label, value, testID, onC
|
|
|
103
103
|
!labelFullyVisible && (React.createElement("div", { className: styles$1.truncateGradient, "data-testid": "ATL-Chip-Truncation-Gradient" },
|
|
104
104
|
React.createElement("span", null)))),
|
|
105
105
|
suffix)));
|
|
106
|
-
}
|
|
106
|
+
}
|
|
107
107
|
function getTooltipMessage(labelFullyVisible, headingFullyVisible, label, heading) {
|
|
108
108
|
let message = "";
|
|
109
109
|
if (heading && !headingFullyVisible) {
|
package/dist/Chip-es.js
CHANGED
|
@@ -73,7 +73,7 @@ const allowedSuffixIcons = [
|
|
|
73
73
|
"arrowDown",
|
|
74
74
|
];
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
function Chip({ ariaLabel, disabled, heading, invalid, label, value, testID, onClick, onKeyDown, children, role = "button", tabIndex = 0, variation = "base", }) {
|
|
77
77
|
const classes = classnames(styles$1.chip, {
|
|
78
78
|
[styles$1.invalid]: invalid,
|
|
79
79
|
[styles$1.base]: variation === "base",
|
|
@@ -101,7 +101,7 @@ const Chip = ({ ariaLabel, disabled, heading, invalid, label, value, testID, onC
|
|
|
101
101
|
!labelFullyVisible && (React__default.createElement("div", { className: styles$1.truncateGradient, "data-testid": "ATL-Chip-Truncation-Gradient" },
|
|
102
102
|
React__default.createElement("span", null)))),
|
|
103
103
|
suffix)));
|
|
104
|
-
}
|
|
104
|
+
}
|
|
105
105
|
function getTooltipMessage(labelFullyVisible, headingFullyVisible, label, heading) {
|
|
106
106
|
let message = "";
|
|
107
107
|
if (heading && !headingFullyVisible) {
|
|
@@ -86,6 +86,18 @@ export interface ChipDismissibleProps extends ChipFoundationProps {
|
|
|
86
86
|
* @param searchValue - The input value
|
|
87
87
|
*/
|
|
88
88
|
onLoadMore?(searchValue: string): void;
|
|
89
|
+
/**
|
|
90
|
+
* Control whether the menu only appears once the user types.
|
|
91
|
+
* @default false
|
|
92
|
+
*/
|
|
93
|
+
readonly onlyShowMenuOnSearch?: boolean;
|
|
94
|
+
/**
|
|
95
|
+
* If true, automatically selects an option based on the current search value when the input loses focus.
|
|
96
|
+
* The automatic selection order is: an exact match of the search value if available, a custom option if
|
|
97
|
+
* onCustomOptionSelect is provided, or the closest match.
|
|
98
|
+
* @default false
|
|
99
|
+
*/
|
|
100
|
+
readonly autoSelectOnClickOutside?: boolean;
|
|
89
101
|
}
|
|
90
102
|
export type ChipsProps = ChipSingleSelectProps | (ChipMultiSelectProps | ChipDismissibleProps);
|
|
91
103
|
export {};
|
|
@@ -6,6 +6,18 @@ export interface ChipDismissibleInputProps extends Pick<InternalChipDismissibleP
|
|
|
6
6
|
readonly options: ChipProps[];
|
|
7
7
|
onCustomOptionSelect?(value: string): void;
|
|
8
8
|
onOptionSelect(value: string): void;
|
|
9
|
+
/**
|
|
10
|
+
* Control whether the menu only appears once the user types.
|
|
11
|
+
* @default false
|
|
12
|
+
*/
|
|
13
|
+
readonly onlyShowMenuOnSearch?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* If true, automatically selects an option based on the current search value when the input loses focus.
|
|
16
|
+
* The automatic selection order is: an exact match of the search value if available, a custom option if
|
|
17
|
+
* onCustomOptionSelect is provided, or the closest match.
|
|
18
|
+
* @default false
|
|
19
|
+
*/
|
|
20
|
+
readonly autoSelectOnClickOutside?: boolean;
|
|
9
21
|
}
|
|
10
22
|
export interface ChipDismissibleInputOptionProps extends ChipProps {
|
|
11
23
|
readonly custom: boolean;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import React, { ChangeEvent, KeyboardEvent } from "react";
|
|
2
2
|
import { ChipDismissibleInputOptionProps, ChipDismissibleInputProps } from "../InternalChipDismissibleTypes";
|
|
3
3
|
import { ChipProps } from "../../Chip";
|
|
4
|
-
export declare function useInternalChipDismissibleInput({ options, isLoadingMore, onCustomOptionSelect, onOptionSelect, onSearch, }: ChipDismissibleInputProps): {
|
|
4
|
+
export declare function useInternalChipDismissibleInput({ options, isLoadingMore, onCustomOptionSelect, onOptionSelect, onSearch, onlyShowMenuOnSearch, autoSelectOnClickOutside, }: ChipDismissibleInputProps): {
|
|
5
5
|
menuOpen: boolean;
|
|
6
|
+
showInput: boolean;
|
|
6
7
|
searchValue: string;
|
|
7
8
|
shouldCancelBlur: boolean;
|
|
8
9
|
menuId: string;
|
|
@@ -20,9 +21,11 @@ export declare function useInternalChipDismissibleInput({ options, isLoadingMore
|
|
|
20
21
|
handleCancelBlur: () => void;
|
|
21
22
|
handleEnableBlur: () => void;
|
|
22
23
|
handleBlur: () => void;
|
|
24
|
+
handleFocus: () => void;
|
|
23
25
|
handleSearchChange: (event: ChangeEvent<HTMLInputElement>) => void;
|
|
24
26
|
handleSetActiveOnMouseOver: (index: number) => () => void;
|
|
25
27
|
handleSelectOption: (selected: ChipDismissibleInputOptionProps) => void;
|
|
28
|
+
handleShowInput: () => void;
|
|
26
29
|
handleKeyDown: (event: KeyboardEvent<HTMLInputElement>) => void;
|
|
27
30
|
handleDebouncedSearch: import("lodash").DebouncedFunc<(newSearchValue: string, newOptions?: ChipProps[]) => void>;
|
|
28
31
|
};
|
|
@@ -8,8 +8,9 @@ export interface FormFieldWrapperProps extends FormFieldProps {
|
|
|
8
8
|
readonly clearable: Clearable;
|
|
9
9
|
readonly onClear: () => void;
|
|
10
10
|
readonly showMiniLabel?: boolean;
|
|
11
|
+
readonly readonly?: boolean;
|
|
11
12
|
}
|
|
12
|
-
export declare function FormFieldWrapper({ align, description, descriptionIdentifier, placeholder, value, children, invalid, error, size, prefix, suffix, max, maxLength, type, disabled, inline, identifier, clearable, onClear, toolbar, toolbarVisibility, showMiniLabel, wrapperRef, }: PropsWithChildren<FormFieldWrapperProps>): JSX.Element;
|
|
13
|
+
export declare function FormFieldWrapper({ align, description, descriptionIdentifier, placeholder, value, children, invalid, error, size, prefix, suffix, max, maxLength, type, disabled, inline, identifier, clearable, onClear, readonly, toolbar, toolbarVisibility, showMiniLabel, wrapperRef, }: PropsWithChildren<FormFieldWrapperProps>): JSX.Element;
|
|
13
14
|
/**
|
|
14
15
|
* @internal Reach out to UX Foundations if using this component since it is possible it might change
|
|
15
16
|
*/
|
package/dist/FormField-cjs.js
CHANGED
|
@@ -17,12 +17,12 @@ var useShowClear$1 = {};
|
|
|
17
17
|
|
|
18
18
|
Object.defineProperty(useShowClear$1, "__esModule", { value: true });
|
|
19
19
|
var useShowClear_2 = useShowClear$1.useShowClear = useShowClear;
|
|
20
|
-
function useShowClear({ clearable, multiline, focused, hasValue, disabled = false, }) {
|
|
20
|
+
function useShowClear({ clearable, multiline, focused, hasValue, readonly, disabled = false, }) {
|
|
21
21
|
if (multiline && clearable !== "never") {
|
|
22
22
|
throw new Error("Multiline inputs can not be clearable");
|
|
23
23
|
}
|
|
24
24
|
// Do not show if there is no value
|
|
25
|
-
if (!hasValue || clearable === "never" || disabled) {
|
|
25
|
+
if (!hasValue || clearable === "never" || disabled || readonly) {
|
|
26
26
|
return false;
|
|
27
27
|
}
|
|
28
28
|
switch (clearable) {
|
|
@@ -79,7 +79,7 @@ var styles = {"clearInput":"YmRTd-KeXv4-","spinning":"B25z9B8I3gs-"};
|
|
|
79
79
|
function ClearAction({ onClick, visible, }) {
|
|
80
80
|
if (!visible)
|
|
81
81
|
return null;
|
|
82
|
-
return (React.createElement("button", { className: styles.clearInput, onClick: onClick, type: "button", "aria-label": "Clear input" },
|
|
82
|
+
return (React.createElement("button", { className: styles.clearInput, onClick: onClick, type: "button", "aria-label": "Clear input", "data-testid": "ATL-FormField-clearButton" },
|
|
83
83
|
React.createElement(Icon.Icon, { name: "remove", size: "small" })));
|
|
84
84
|
}
|
|
85
85
|
|
|
@@ -169,7 +169,7 @@ function getAffixPaddding({ value, type, prefixWidth, suffixWidth, }) {
|
|
|
169
169
|
return newPadding;
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
-
function FormFieldWrapper({ align, description, descriptionIdentifier, placeholder, value, children, invalid, error, size, prefix, suffix, max, maxLength, type, disabled, inline, identifier, clearable, onClear, toolbar, toolbarVisibility = "while-editing", showMiniLabel = true, wrapperRef, }) {
|
|
172
|
+
function FormFieldWrapper({ align, description, descriptionIdentifier, placeholder, value, children, invalid, error, size, prefix, suffix, max, maxLength, type, disabled, inline, identifier, clearable, onClear, readonly, toolbar, toolbarVisibility = "while-editing", showMiniLabel = true, wrapperRef, }) {
|
|
173
173
|
const prefixRef = React.useRef();
|
|
174
174
|
const suffixRef = React.useRef();
|
|
175
175
|
const { wrapperClasses, containerClasses, wrapperInlineStyle, labelStyle } = useFormFieldWrapperStyles({
|
|
@@ -195,6 +195,7 @@ function FormFieldWrapper({ align, description, descriptionIdentifier, placehold
|
|
|
195
195
|
focused,
|
|
196
196
|
hasValue: Boolean(value),
|
|
197
197
|
disabled,
|
|
198
|
+
readonly,
|
|
198
199
|
});
|
|
199
200
|
const { isToolbarVisible, toolbarAnimationEnd, toolbarAnimationStart } = useToolbar({
|
|
200
201
|
focused,
|
package/dist/FormField-es.js
CHANGED
|
@@ -15,12 +15,12 @@ var useShowClear$1 = {};
|
|
|
15
15
|
|
|
16
16
|
Object.defineProperty(useShowClear$1, "__esModule", { value: true });
|
|
17
17
|
var useShowClear_2 = useShowClear$1.useShowClear = useShowClear;
|
|
18
|
-
function useShowClear({ clearable, multiline, focused, hasValue, disabled = false, }) {
|
|
18
|
+
function useShowClear({ clearable, multiline, focused, hasValue, readonly, disabled = false, }) {
|
|
19
19
|
if (multiline && clearable !== "never") {
|
|
20
20
|
throw new Error("Multiline inputs can not be clearable");
|
|
21
21
|
}
|
|
22
22
|
// Do not show if there is no value
|
|
23
|
-
if (!hasValue || clearable === "never" || disabled) {
|
|
23
|
+
if (!hasValue || clearable === "never" || disabled || readonly) {
|
|
24
24
|
return false;
|
|
25
25
|
}
|
|
26
26
|
switch (clearable) {
|
|
@@ -77,7 +77,7 @@ var styles = {"clearInput":"YmRTd-KeXv4-","spinning":"B25z9B8I3gs-"};
|
|
|
77
77
|
function ClearAction({ onClick, visible, }) {
|
|
78
78
|
if (!visible)
|
|
79
79
|
return null;
|
|
80
|
-
return (React__default.createElement("button", { className: styles.clearInput, onClick: onClick, type: "button", "aria-label": "Clear input" },
|
|
80
|
+
return (React__default.createElement("button", { className: styles.clearInput, onClick: onClick, type: "button", "aria-label": "Clear input", "data-testid": "ATL-FormField-clearButton" },
|
|
81
81
|
React__default.createElement(Icon, { name: "remove", size: "small" })));
|
|
82
82
|
}
|
|
83
83
|
|
|
@@ -167,7 +167,7 @@ function getAffixPaddding({ value, type, prefixWidth, suffixWidth, }) {
|
|
|
167
167
|
return newPadding;
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
-
function FormFieldWrapper({ align, description, descriptionIdentifier, placeholder, value, children, invalid, error, size, prefix, suffix, max, maxLength, type, disabled, inline, identifier, clearable, onClear, toolbar, toolbarVisibility = "while-editing", showMiniLabel = true, wrapperRef, }) {
|
|
170
|
+
function FormFieldWrapper({ align, description, descriptionIdentifier, placeholder, value, children, invalid, error, size, prefix, suffix, max, maxLength, type, disabled, inline, identifier, clearable, onClear, readonly, toolbar, toolbarVisibility = "while-editing", showMiniLabel = true, wrapperRef, }) {
|
|
171
171
|
const prefixRef = useRef();
|
|
172
172
|
const suffixRef = useRef();
|
|
173
173
|
const { wrapperClasses, containerClasses, wrapperInlineStyle, labelStyle } = useFormFieldWrapperStyles({
|
|
@@ -193,6 +193,7 @@ function FormFieldWrapper({ align, description, descriptionIdentifier, placehold
|
|
|
193
193
|
focused,
|
|
194
194
|
hasValue: Boolean(value),
|
|
195
195
|
disabled,
|
|
196
|
+
readonly,
|
|
196
197
|
});
|
|
197
198
|
const { isToolbarVisible, toolbarAnimationEnd, toolbarAnimationStart } = useToolbar({
|
|
198
199
|
focused,
|
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
import { InputTimeProps } from "./
|
|
1
|
+
import { InputTimeProps } from "./InputTime.types";
|
|
2
2
|
export declare function InputTime({ defaultValue, value, onChange, ...params }: InputTimeProps): JSX.Element;
|
|
3
|
-
export declare function timeStringToDate(timeString: string): Date | undefined;
|
|
@@ -14,4 +14,13 @@ export interface InputTimeProps extends Pick<CommonFormFieldProps, "id" | "align
|
|
|
14
14
|
* Function called when user changes input value.
|
|
15
15
|
*/
|
|
16
16
|
onChange?(newValue?: Date): void;
|
|
17
|
+
/**
|
|
18
|
+
* The version of the component.
|
|
19
|
+
*/
|
|
20
|
+
version?: 1 | 2;
|
|
21
|
+
}
|
|
22
|
+
export interface InputTimeRebuiltProps extends Omit<InputTimeProps, "defaultValue" | "version"> {
|
|
23
|
+
defaultValue?: never;
|
|
24
|
+
version: 2;
|
|
25
|
+
error?: string;
|
|
17
26
|
}
|
package/dist/InputTime/index.cjs
CHANGED
|
@@ -1,26 +1,288 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
require('../tslib.es6-cjs.js');
|
|
5
|
-
require('
|
|
6
|
-
require('../
|
|
7
|
-
require('../_commonjsHelpers-cjs.js');
|
|
8
|
-
require('../isObjectLike-cjs.js');
|
|
9
|
-
require('../isSymbol-cjs.js');
|
|
10
|
-
require('../FormField-cjs.js');
|
|
11
|
-
require('framer-motion');
|
|
3
|
+
var React = require('react');
|
|
4
|
+
var tslib_es6 = require('../tslib.es6-cjs.js');
|
|
5
|
+
var debounce = require('../debounce-cjs.js');
|
|
6
|
+
var FormField = require('../FormField-cjs.js');
|
|
12
7
|
require('@jobber/design');
|
|
13
8
|
require('classnames');
|
|
9
|
+
require('react-hook-form');
|
|
14
10
|
require('../Button-cjs.js');
|
|
15
|
-
require('
|
|
11
|
+
var omit = require('../omit-cjs.js');
|
|
12
|
+
require('framer-motion');
|
|
13
|
+
require('../_commonjsHelpers-cjs.js');
|
|
14
|
+
require('../isObjectLike-cjs.js');
|
|
15
|
+
require('../isSymbol-cjs.js');
|
|
16
16
|
require('../Icon-cjs.js');
|
|
17
|
-
require('../Typography-cjs.js');
|
|
18
17
|
require('../Text-cjs.js');
|
|
18
|
+
require('../Typography-cjs.js');
|
|
19
19
|
require('../useFormFieldFocus-cjs.js');
|
|
20
20
|
require('../InputValidation-cjs.js');
|
|
21
21
|
require('../Spinner-cjs.js');
|
|
22
|
-
require('react-
|
|
22
|
+
require('react-router-dom');
|
|
23
|
+
require('../_baseGet-cjs.js');
|
|
24
|
+
require('../isTypedArray-cjs.js');
|
|
25
|
+
require('../identity-cjs.js');
|
|
26
|
+
require('../_getTag-cjs.js');
|
|
27
|
+
require('../keysIn-cjs.js');
|
|
28
|
+
require('../_baseAssignValue-cjs.js');
|
|
29
|
+
require('../_baseFlatten-cjs.js');
|
|
30
|
+
require('../_setToString-cjs.js');
|
|
31
|
+
|
|
32
|
+
const DEBOUNCE_TIME = 300;
|
|
33
|
+
function useTimePredict({ value, handleChange }) {
|
|
34
|
+
const [IS_12_HOUR_FORMAT, set12HourFormat] = React.useState(false);
|
|
35
|
+
const [typedTime, setTypedTime] = React.useState("");
|
|
36
|
+
const predictTime = React.useCallback(debounce.debounce(() => {
|
|
37
|
+
if (value)
|
|
38
|
+
return;
|
|
39
|
+
handleChange(predictHours(typedTime, IS_12_HOUR_FORMAT));
|
|
40
|
+
}, DEBOUNCE_TIME), [typedTime, value, handleChange, IS_12_HOUR_FORMAT]);
|
|
41
|
+
React.useEffect(() => {
|
|
42
|
+
set12HourFormat(Boolean(Intl.DateTimeFormat(navigator.language, {
|
|
43
|
+
hour: "numeric",
|
|
44
|
+
}).resolvedOptions().hour12));
|
|
45
|
+
}, []);
|
|
46
|
+
/**
|
|
47
|
+
* Predict the hour when user types a number
|
|
48
|
+
*/
|
|
49
|
+
React.useEffect(() => {
|
|
50
|
+
/**
|
|
51
|
+
* Don't try to predict if the user types 0 as the user would almost always
|
|
52
|
+
* type another number after 0.
|
|
53
|
+
*/
|
|
54
|
+
if (typedTime && typedTime !== "0") {
|
|
55
|
+
predictTime();
|
|
56
|
+
if ((IS_12_HOUR_FORMAT && typedTime !== "1") || typedTime.length === 2) {
|
|
57
|
+
// Immediately predict the hour
|
|
58
|
+
predictTime.flush();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return predictTime.cancel;
|
|
62
|
+
}, [typedTime]);
|
|
63
|
+
/**
|
|
64
|
+
* Reset typed time when the value changed
|
|
65
|
+
*/
|
|
66
|
+
React.useEffect(() => {
|
|
67
|
+
setTypedTime("");
|
|
68
|
+
}, [value]);
|
|
69
|
+
return {
|
|
70
|
+
setTypedTime,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function predictHours(time, is12HourFormat = false) {
|
|
74
|
+
const today = new Date();
|
|
75
|
+
const currentHour = today.getHours();
|
|
76
|
+
const parsedTime = parseInt(time, 10);
|
|
77
|
+
let predictedTime;
|
|
78
|
+
if (is12HourFormat) {
|
|
79
|
+
predictedTime = predict12Hours(parsedTime, currentHour);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
predictedTime = predict24Hours(time, parsedTime, currentHour);
|
|
83
|
+
}
|
|
84
|
+
return formatHour(predictedTime);
|
|
85
|
+
}
|
|
86
|
+
function predict12Hours(parsedTime, currentHour) {
|
|
87
|
+
/**
|
|
88
|
+
* We need to predict what the user wants when they type 1 since it could be
|
|
89
|
+
* 10, 11, 12, or 1.
|
|
90
|
+
*
|
|
91
|
+
* If the current hour is over 12PM, we can skip this and go to the next logic.
|
|
92
|
+
*/
|
|
93
|
+
if (parsedTime === 1 && currentHour < 12) {
|
|
94
|
+
if (currentHour < 10) {
|
|
95
|
+
return 10;
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
return currentHour + 1;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Typing 1-5 predicts that the user want that exact hour on the afternoon.
|
|
103
|
+
*/
|
|
104
|
+
if (parsedTime <= 5) {
|
|
105
|
+
return parsedTime + 12;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Typing 13-15 predicts that the user want the 2nd number as the minute interval.
|
|
109
|
+
*/
|
|
110
|
+
if (parsedTime > 12 && parsedTime <= 15) {
|
|
111
|
+
const timeArray = parsedTime.toString().split("").map(Number); // 13 -> [1, 3]
|
|
112
|
+
const convertToHoursAndMinutes = timeArray.map((time, i) => {
|
|
113
|
+
if (i === 0)
|
|
114
|
+
return time + 12; // 1 -> 13 as 1PM
|
|
115
|
+
if (i === 1)
|
|
116
|
+
return time * 10; // 3 -> 30 as 30 minutes
|
|
117
|
+
});
|
|
118
|
+
return Number(convertToHoursAndMinutes.join("")); // [13, 30] -> 1330
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Anything after 5 will be predicted to be set as AM.
|
|
122
|
+
*/
|
|
123
|
+
return parsedTime;
|
|
124
|
+
}
|
|
125
|
+
function predict24Hours(time, parsedTime, currentHour) {
|
|
126
|
+
/**
|
|
127
|
+
* Typing 1 could be predicted from 10 to 19.
|
|
128
|
+
* Typing 01 skips this logic and sets the time to 01:00.
|
|
129
|
+
*/
|
|
130
|
+
if (parsedTime === 1 && time !== "01") {
|
|
131
|
+
if (currentHour < 10 || currentHour > 19) {
|
|
132
|
+
return 10;
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
return currentHour + 1;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Typing 2 could be predicted from 20 to 24.
|
|
140
|
+
* Typing 02 skips this logic and sets the time to 02:00.
|
|
141
|
+
*/
|
|
142
|
+
if (parsedTime === 2 && time !== "02") {
|
|
143
|
+
if (currentHour < 20) {
|
|
144
|
+
return 20;
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
return currentHour + 1;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Typing 24 or 00 is set to midnight. This ensures the time doesn't get set
|
|
152
|
+
* to 24 as that would be invalid.
|
|
153
|
+
*/
|
|
154
|
+
if (parsedTime === 24 || time === "00") {
|
|
155
|
+
return 0;
|
|
156
|
+
}
|
|
157
|
+
return parsedTime;
|
|
158
|
+
}
|
|
159
|
+
function formatHour(time) {
|
|
160
|
+
if (time > 99) {
|
|
161
|
+
const splitTime = time.toString().split("");
|
|
162
|
+
if (splitTime.length === 3)
|
|
163
|
+
splitTime.unshift("0"); // 130 -> 0130
|
|
164
|
+
splitTime.splice(2, 0, ":"); // 0130 -> 01:30
|
|
165
|
+
return splitTime.join("");
|
|
166
|
+
}
|
|
167
|
+
if (time < 10) {
|
|
168
|
+
return `0${time}:00`;
|
|
169
|
+
}
|
|
170
|
+
return `${time}:00`;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function dateToTimeString(date) {
|
|
174
|
+
if (!(date instanceof Date)) {
|
|
175
|
+
return "";
|
|
176
|
+
}
|
|
177
|
+
// Extract hours and minutes from the Date object
|
|
178
|
+
const hours = date.getHours().toString().padStart(2, "0");
|
|
179
|
+
const minutes = date.getMinutes().toString().padStart(2, "0");
|
|
180
|
+
// Return the time string in HH:MM format
|
|
181
|
+
return `${hours}:${minutes}`;
|
|
182
|
+
}
|
|
183
|
+
function timeStringToDate(timeString) {
|
|
184
|
+
try {
|
|
185
|
+
const [hours, minutes] = timeString.split(":").map(Number);
|
|
186
|
+
if (isNaN(hours) ||
|
|
187
|
+
isNaN(minutes) ||
|
|
188
|
+
hours < 0 ||
|
|
189
|
+
hours > 24 ||
|
|
190
|
+
minutes < 0 ||
|
|
191
|
+
minutes > 60) {
|
|
192
|
+
return undefined;
|
|
193
|
+
}
|
|
194
|
+
const date = new Date();
|
|
195
|
+
date.setHours(hours, minutes, 0, 0);
|
|
196
|
+
return date;
|
|
197
|
+
}
|
|
198
|
+
catch (_a) {
|
|
199
|
+
return undefined;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function InputTimeRebuilt(_a) {
|
|
204
|
+
var _b, _c;
|
|
205
|
+
var { value, onChange } = _a, params = tslib_es6.__rest(_a, ["value", "onChange"]);
|
|
206
|
+
const ref = (_b = params.inputRef) !== null && _b !== void 0 ? _b : React.useRef(null);
|
|
207
|
+
const { setTypedTime } = useTimePredict({
|
|
208
|
+
value,
|
|
209
|
+
handleChange,
|
|
210
|
+
});
|
|
211
|
+
const { inputStyle } = FormField.useFormFieldWrapperStyles(params);
|
|
212
|
+
const id = getId(params);
|
|
213
|
+
return (React.createElement(FormField.FormFieldWrapper, { disabled: params.disabled, size: params.size, align: params.align, inline: params.inline, name: params.name, error: params.error || "", identifier: id, descriptionIdentifier: `descriptionUUID--${id}`, invalid: Boolean(params.invalid), description: params.description, clearable: (_c = params.clearable) !== null && _c !== void 0 ? _c : "never", onClear: handleClear, type: "time", readonly: params.readonly, placeholder: params.placeholder, value: dateToTimeString(value) },
|
|
214
|
+
React.createElement("input", { ref: ref, type: "time", name: params.name, className: inputStyle, onBlur: handleBlur, disabled: params.disabled, readOnly: params.readonly, onChange: handleChangeEvent, onFocus: handleFocus, "data-testid": "ATL-InputTime-input", onKeyUp: e => {
|
|
215
|
+
if (params.disabled || params.readonly)
|
|
216
|
+
return;
|
|
217
|
+
!isNaN(parseInt(e.key, 10)) && setTypedTime(prev => prev + e.key);
|
|
218
|
+
}, value: dateToTimeString(value) })));
|
|
219
|
+
function handleChangeEvent(event) {
|
|
220
|
+
handleChange(event.target.value);
|
|
221
|
+
}
|
|
222
|
+
function handleChange(newValue) {
|
|
223
|
+
onChange === null || onChange === void 0 ? void 0 : onChange(timeStringToDate(newValue));
|
|
224
|
+
}
|
|
225
|
+
function handleBlur(event) {
|
|
226
|
+
var _a;
|
|
227
|
+
(_a = params.onBlur) === null || _a === void 0 ? void 0 : _a.call(params, event);
|
|
228
|
+
if (ref.current) {
|
|
229
|
+
if (!ref.current.checkValidity()) {
|
|
230
|
+
ref.current.value = "";
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
function handleClear() {
|
|
235
|
+
var _a;
|
|
236
|
+
handleBlur();
|
|
237
|
+
onChange === null || onChange === void 0 ? void 0 : onChange(undefined);
|
|
238
|
+
(_a = ref.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
239
|
+
}
|
|
240
|
+
function handleFocus(event) {
|
|
241
|
+
var _a;
|
|
242
|
+
(_a = params.onFocus) === null || _a === void 0 ? void 0 : _a.call(params, event);
|
|
243
|
+
}
|
|
244
|
+
function getId(props) {
|
|
245
|
+
const generatedId = React.useId();
|
|
246
|
+
return props.id || generatedId;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
23
249
|
|
|
250
|
+
function InputTime$1(_a) {
|
|
251
|
+
var { defaultValue, value, onChange } = _a, params = tslib_es6.__rest(_a, ["defaultValue", "value", "onChange"]);
|
|
252
|
+
const ref = React.useRef(null);
|
|
253
|
+
const { setTypedTime } = useTimePredict({ value, handleChange });
|
|
254
|
+
const fieldProps = omit.omit(Object.assign(Object.assign(Object.assign({ onChange: handleChange }, (defaultValue && { defaultValue: dateToTimeString(defaultValue) })), (!defaultValue && { value: dateToTimeString(value) })), params), ["version"]);
|
|
255
|
+
return (React.createElement(FormField.FormField, Object.assign({ inputRef: ref, type: "time" }, fieldProps, { onBlur: handleBlur, onKeyUp: e => {
|
|
256
|
+
var _a;
|
|
257
|
+
(_a = fieldProps.onKeyUp) === null || _a === void 0 ? void 0 : _a.call(fieldProps, e);
|
|
258
|
+
!isNaN(parseInt(e.key, 10)) && setTypedTime(prev => prev + e.key);
|
|
259
|
+
} })));
|
|
260
|
+
function handleChange(newValue) {
|
|
261
|
+
onChange === null || onChange === void 0 ? void 0 : onChange(timeStringToDate(newValue));
|
|
262
|
+
}
|
|
263
|
+
function handleBlur() {
|
|
264
|
+
var _a;
|
|
265
|
+
(_a = params.onBlur) === null || _a === void 0 ? void 0 : _a.call(params);
|
|
266
|
+
// Time inputs doesn't clear the typed value when it's invalid. This should
|
|
267
|
+
// force it to reset the input value when the typed value is invalid.
|
|
268
|
+
if (ref.current) {
|
|
269
|
+
if (!ref.current.checkValidity()) {
|
|
270
|
+
ref.current.value = "";
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
24
275
|
|
|
276
|
+
function isNewInputTimeProps(props) {
|
|
277
|
+
return props.version === 2;
|
|
278
|
+
}
|
|
279
|
+
function InputTime(props) {
|
|
280
|
+
if (isNewInputTimeProps(props)) {
|
|
281
|
+
return React.createElement(InputTimeRebuilt, Object.assign({}, props));
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
return React.createElement(InputTime$1, Object.assign({}, props));
|
|
285
|
+
}
|
|
286
|
+
}
|
|
25
287
|
|
|
26
|
-
exports.InputTime = InputTime
|
|
288
|
+
exports.InputTime = InputTime;
|