@swan-io/lake 15.5.3 → 16.0.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/package.json +1 -1
- package/src/components/LakeAlert.d.ts +2 -1
- package/src/components/LakeAlert.js +7 -3
- package/src/components/LakeCopyButton.d.ts +0 -1
- package/src/components/LakeCopyButton.js +1 -1
- package/src/components/LakeStepper.d.ts +0 -2
- package/src/components/LakeStepper.js +0 -39
- package/src/components/Popover.d.ts +0 -1
- package/src/components/Popover.js +1 -1
- package/src/components/SortBottomPanel.d.ts +0 -20
- package/src/components/SortBottomPanel.js +0 -41
- package/src/components/TimePicker.d.ts +0 -55
- package/src/components/TimePicker.js +0 -171
package/package.json
CHANGED
|
@@ -3,6 +3,7 @@ import { StyleProp, ViewStyle } from "react-native";
|
|
|
3
3
|
type AlertVariant = "info" | "warning" | "error" | "success" | "neutral";
|
|
4
4
|
type Props = {
|
|
5
5
|
anchored?: boolean;
|
|
6
|
+
inPopover?: boolean;
|
|
6
7
|
variant: AlertVariant;
|
|
7
8
|
children?: ReactNode;
|
|
8
9
|
callToAction?: ReactNode;
|
|
@@ -11,5 +12,5 @@ type Props = {
|
|
|
11
12
|
style?: StyleProp<ViewStyle>;
|
|
12
13
|
tag?: string;
|
|
13
14
|
};
|
|
14
|
-
export declare const LakeAlert: ({ anchored, variant, title, subtitle, children, style, callToAction, tag, }: Props) => import("react").JSX.Element;
|
|
15
|
+
export declare const LakeAlert: ({ anchored, inPopover, variant, title, subtitle, children, style, callToAction, tag, }: Props) => import("react").JSX.Element;
|
|
15
16
|
export {};
|
|
@@ -2,7 +2,7 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
2
2
|
import { StyleSheet, View } from "react-native";
|
|
3
3
|
import { match } from "ts-pattern";
|
|
4
4
|
import { commonStyles } from "../constants/commonStyles";
|
|
5
|
-
import { breakpoints, colors, shadows } from "../constants/design";
|
|
5
|
+
import { breakpoints, colors, radii, shadows } from "../constants/design";
|
|
6
6
|
import { useResponsive } from "../hooks/useResponsive";
|
|
7
7
|
import { isNotNullish, isNotNullishOrEmpty } from "../utils/nullish";
|
|
8
8
|
import { Box } from "./Box";
|
|
@@ -14,7 +14,7 @@ const styles = StyleSheet.create({
|
|
|
14
14
|
base: {
|
|
15
15
|
paddingVertical: 20,
|
|
16
16
|
paddingHorizontal: 24,
|
|
17
|
-
borderRadius: 4,
|
|
17
|
+
borderRadius: radii[4],
|
|
18
18
|
borderWidth: 0.5,
|
|
19
19
|
borderLeftWidth: 4,
|
|
20
20
|
boxShadow: shadows.tile,
|
|
@@ -25,6 +25,9 @@ const styles = StyleSheet.create({
|
|
|
25
25
|
marginBottom: -1,
|
|
26
26
|
boxShadow: "none",
|
|
27
27
|
},
|
|
28
|
+
inPopover: {
|
|
29
|
+
borderRadius: radii[8],
|
|
30
|
+
},
|
|
28
31
|
content: {
|
|
29
32
|
marginLeft: 40,
|
|
30
33
|
},
|
|
@@ -71,7 +74,7 @@ const alertLeftBorder = {
|
|
|
71
74
|
neutral: colors.gray[500],
|
|
72
75
|
};
|
|
73
76
|
const isText = (node) => typeof node === "string" || typeof node === "number";
|
|
74
|
-
export const LakeAlert = ({ anchored = false, variant, title, subtitle, children, style, callToAction, tag, }) => {
|
|
77
|
+
export const LakeAlert = ({ anchored = false, inPopover = false, variant, title, subtitle, children, style, callToAction, tag, }) => {
|
|
75
78
|
const color = alertColor[variant];
|
|
76
79
|
const icon = alertIcon[variant];
|
|
77
80
|
const { desktop } = useResponsive(breakpoints.medium);
|
|
@@ -90,6 +93,7 @@ export const LakeAlert = ({ anchored = false, variant, title, subtitle, children
|
|
|
90
93
|
borderColor: alertBorder[variant],
|
|
91
94
|
},
|
|
92
95
|
anchored ? styles.anchored : { borderLeftColor: alertLeftBorder[variant] },
|
|
96
|
+
inPopover && styles.inPopover,
|
|
93
97
|
style,
|
|
94
98
|
], children: [_jsxs(Box, { direction: "row", alignItems: "center", children: [icon != null ? (_jsxs(_Fragment, { children: [_jsx(Icon, { name: icon, color: color, size: 20 }), _jsx(Space, { width: 20 })] })) : null, _jsxs(View, { style: commonStyles.fill, children: [_jsxs(Box, { direction: "row", justifyContent: "spaceBetween", children: [_jsx(LakeText, { color: color, variant: "medium", children: title }), tag && _jsx(Tag, { color: translateColorTag(), children: tag })] }), isNotNullishOrEmpty(subtitle) && _jsx(LakeText, { color: color, children: subtitle })] }), isNotNullish(callToAction) && _jsx(View, { style: styles.callToAction, children: callToAction })] }), isNotNullish(children) && (_jsxs(View, { style: desktop && icon != null && styles.content, children: [_jsx(Space, { height: 12 }), isText(children) ? _jsx(LakeText, { color: color, children: children }) : children] }))] }));
|
|
95
99
|
};
|
|
@@ -4,7 +4,7 @@ import { setClipboardText } from "../utils/clipboard";
|
|
|
4
4
|
import { Icon } from "./Icon";
|
|
5
5
|
import { LakeTooltip } from "./LakeTooltip";
|
|
6
6
|
import { Pressable } from "./Pressable";
|
|
7
|
-
|
|
7
|
+
const copyButtondefaultSize = 21;
|
|
8
8
|
export const LakeCopyButton = ({ color, copiedText, copyText, size = copyButtondefaultSize, valueToCopy, }) => {
|
|
9
9
|
const [visibleState, setVisibleState] = useState("copy");
|
|
10
10
|
return (_jsx(LakeTooltip, { describedBy: "copy", onHide: () => setVisibleState("copy"), togglableOnFocus: true, content: visibleState === "copy" ? copyText : copiedText, children: _jsx(Pressable, { onPress: event => {
|
|
@@ -16,7 +16,5 @@ type Props = {
|
|
|
16
16
|
style?: StyleProp<ViewStyle>;
|
|
17
17
|
};
|
|
18
18
|
export declare const LakeStepper: ({ steps, activeStepId, style }: Props) => import("react").JSX.Element;
|
|
19
|
-
/** @deprecated Use <MobileStepper> instead */
|
|
20
|
-
export declare const MobileStepTitle: ({ steps, activeStepId }: Props) => import("react").JSX.Element | null;
|
|
21
19
|
export declare const MobileStepper: ({ steps, activeStepId }: Props) => import("react").JSX.Element | null;
|
|
22
20
|
export {};
|
|
@@ -4,9 +4,7 @@ import { Link } from "@swan-io/chicane";
|
|
|
4
4
|
import { StyleSheet, View } from "react-native";
|
|
5
5
|
import { match, P } from "ts-pattern";
|
|
6
6
|
import { colors } from "../constants/design";
|
|
7
|
-
import { Box } from "./Box";
|
|
8
7
|
import { Grid } from "./Grid";
|
|
9
|
-
import { LakeHeading } from "./LakeHeading";
|
|
10
8
|
import { LakeText } from "./LakeText";
|
|
11
9
|
import { Space } from "./Space";
|
|
12
10
|
const linkStyle = {
|
|
@@ -44,23 +42,6 @@ const styles = StyleSheet.create({
|
|
|
44
42
|
progressBarError: {
|
|
45
43
|
backgroundColor: colors.negative[500],
|
|
46
44
|
},
|
|
47
|
-
mobileContainer: {
|
|
48
|
-
borderBottomWidth: 1,
|
|
49
|
-
borderBottomColor: colors.gray[100],
|
|
50
|
-
paddingBottom: 10,
|
|
51
|
-
},
|
|
52
|
-
mobileNumber: {
|
|
53
|
-
minWidth: 28,
|
|
54
|
-
height: 24,
|
|
55
|
-
borderRadius: 12,
|
|
56
|
-
borderWidth: 1,
|
|
57
|
-
borderColor: colors.current[100],
|
|
58
|
-
backgroundColor: colors.current[50],
|
|
59
|
-
},
|
|
60
|
-
mobileNumberError: {
|
|
61
|
-
borderColor: colors.negative[100],
|
|
62
|
-
backgroundColor: colors.negative[50],
|
|
63
|
-
},
|
|
64
45
|
});
|
|
65
46
|
const stylesMobile = StyleSheet.create({
|
|
66
47
|
progress: {
|
|
@@ -127,26 +108,6 @@ export const LakeStepper = ({ steps, activeStepId, style }) => {
|
|
|
127
108
|
}) })] }, currentId));
|
|
128
109
|
}) }));
|
|
129
110
|
};
|
|
130
|
-
/** @deprecated Use <MobileStepper> instead */
|
|
131
|
-
export const MobileStepTitle = ({ steps, activeStepId }) => {
|
|
132
|
-
const currentStep = Option.fromNullable(steps
|
|
133
|
-
.flatMap((step, index) => match(step)
|
|
134
|
-
.with({ id: P.string }, step => ({ ...step, number: `${index + 1}` }))
|
|
135
|
-
.with({ children: P.array(P.any) }, ({ children }) => children.map((child, subIndex) => ({
|
|
136
|
-
...child,
|
|
137
|
-
number: `${index + 1}.${subIndex + 1}`,
|
|
138
|
-
})))
|
|
139
|
-
.exhaustive())
|
|
140
|
-
.find(({ id }) => id === activeStepId)).map(({ label, hasErrors, number }) => ({
|
|
141
|
-
number,
|
|
142
|
-
label,
|
|
143
|
-
isErrorState: hasErrors === true,
|
|
144
|
-
}));
|
|
145
|
-
return currentStep.match({
|
|
146
|
-
Some: ({ number, label, isErrorState }) => (_jsxs(Box, { direction: "row", alignItems: "center", justifyContent: "center", style: styles.mobileContainer, children: [_jsx(Box, { alignItems: "center", justifyContent: "center", style: [styles.mobileNumber, isErrorState && styles.mobileNumberError], children: _jsx(LakeText, { variant: "smallMedium", color: isErrorState ? colors.negative[500] : colors.current[500], children: number }) }), _jsx(Space, { width: 8 }), _jsx(LakeHeading, { level: 4, variant: "h4", color: isErrorState ? colors.negative[500] : colors.current[500], children: label })] })),
|
|
147
|
-
None: () => null,
|
|
148
|
-
});
|
|
149
|
-
};
|
|
150
111
|
export const MobileStepper = ({ steps, activeStepId }) => {
|
|
151
112
|
const total = steps.length;
|
|
152
113
|
const currentStep = Option.fromNullable(steps
|
|
@@ -55,7 +55,7 @@ const animation = {
|
|
|
55
55
|
{ animationDuration: "100ms" },
|
|
56
56
|
],
|
|
57
57
|
};
|
|
58
|
-
|
|
58
|
+
const VIEWPORT_WIDTH_THRESHOLD = 600;
|
|
59
59
|
export const Popover = memo(({ children, id, label, placement, verticalPlacement, role = "dialog", describedBy, matchReferenceWidth = false, matchReferenceMinWidth = false, onDismiss = noop, onEscapeKey = onDismiss, referenceRef, returnFocus = true, autoFocus = true, visible, underlay = true, forcedMode, }) => {
|
|
60
60
|
const [rootElement, setRootElement] = useState(null);
|
|
61
61
|
const underlayRef = useRef(null);
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
type SortDirection = "Asc" | "Desc";
|
|
2
|
-
export type SortField<T> = {
|
|
3
|
-
name: T;
|
|
4
|
-
ascLabel: string;
|
|
5
|
-
descLabel: string;
|
|
6
|
-
};
|
|
7
|
-
export type SortValue<T extends string> = {
|
|
8
|
-
field: T;
|
|
9
|
-
direction: SortDirection;
|
|
10
|
-
};
|
|
11
|
-
type Props<T extends string> = {
|
|
12
|
-
visible: boolean;
|
|
13
|
-
title: string;
|
|
14
|
-
fields: SortField<T>[];
|
|
15
|
-
value: SortValue<T> | undefined;
|
|
16
|
-
onChange: (value: SortValue<T>) => void;
|
|
17
|
-
onClose: () => void;
|
|
18
|
-
};
|
|
19
|
-
export declare const SortBottomPanel: <T extends string>({ visible, title, value, fields, onChange, onClose, }: Props<T>) => import("react").JSX.Element;
|
|
20
|
-
export {};
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Fragment } from "react";
|
|
3
|
-
import { StyleSheet, View } from "react-native";
|
|
4
|
-
import { commonStyles } from "../constants/commonStyles";
|
|
5
|
-
import { colors, spacings } from "../constants/design";
|
|
6
|
-
import { BottomPanel } from "./BottomPanel";
|
|
7
|
-
import { Icon } from "./Icon";
|
|
8
|
-
import { LakeHeading } from "./LakeHeading";
|
|
9
|
-
import { LakeRadio } from "./LakeRadio";
|
|
10
|
-
import { LakeText } from "./LakeText";
|
|
11
|
-
import { Pressable } from "./Pressable";
|
|
12
|
-
import { Separator } from "./Separator";
|
|
13
|
-
import { Space } from "./Space";
|
|
14
|
-
const styles = StyleSheet.create({
|
|
15
|
-
head: {
|
|
16
|
-
padding: 24,
|
|
17
|
-
paddingBottom: 12,
|
|
18
|
-
},
|
|
19
|
-
option: {
|
|
20
|
-
display: "flex",
|
|
21
|
-
flexDirection: "row",
|
|
22
|
-
alignItems: "center",
|
|
23
|
-
paddingHorizontal: spacings[24],
|
|
24
|
-
paddingVertical: spacings[12],
|
|
25
|
-
},
|
|
26
|
-
arrowDown: {
|
|
27
|
-
transform: "rotate(180deg)",
|
|
28
|
-
},
|
|
29
|
-
text: {
|
|
30
|
-
...commonStyles.fill,
|
|
31
|
-
},
|
|
32
|
-
});
|
|
33
|
-
export const SortBottomPanel = ({ visible, title, value, fields, onChange, onClose, }) => {
|
|
34
|
-
return (_jsxs(BottomPanel, { visible: visible, onPressClose: onClose, children: [_jsx(View, { style: styles.head, children: _jsx(LakeHeading, { level: 3, variant: "h3", children: title }) }), fields.map((field, index) => (_jsxs(Fragment, { children: [_jsxs(Pressable, { style: styles.option, onPress: () => {
|
|
35
|
-
onChange({ field: field.name, direction: "Asc" });
|
|
36
|
-
onClose();
|
|
37
|
-
}, children: [_jsx(Icon, { name: "arrow-up-filled", size: 12, color: colors.gray[600], style: styles.arrowDown }), _jsx(Space, { width: 12 }), _jsx(LakeText, { variant: "smallRegular", color: colors.gray[600], style: styles.text, children: field.ascLabel }), _jsx(Space, { width: 16 }), _jsx(LakeRadio, { value: (value === null || value === void 0 ? void 0 : value.field) === field.name && value.direction === "Asc" })] }), _jsxs(Pressable, { style: styles.option, onPress: () => {
|
|
38
|
-
onChange({ field: field.name, direction: "Desc" });
|
|
39
|
-
onClose();
|
|
40
|
-
}, children: [_jsx(Icon, { name: "arrow-up-filled", size: 12, color: colors.gray[600] }), _jsx(Space, { width: 12 }), _jsx(LakeText, { variant: "smallRegular", color: colors.gray[600], style: styles.text, children: field.descLabel }), _jsx(Space, { width: 16 }), _jsx(LakeRadio, { value: (value === null || value === void 0 ? void 0 : value.field) === field.name && value.direction === "Desc" })] }), index < fields.length - 1 && _jsx(Separator, {})] }, field.name))), _jsx(Space, { height: 12 })] }));
|
|
41
|
-
};
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { Option } from "@swan-io/boxed";
|
|
2
|
-
type Time = {
|
|
3
|
-
hour: number;
|
|
4
|
-
minute: number;
|
|
5
|
-
};
|
|
6
|
-
export declare const parseTime: (time: string) => Option<Time>;
|
|
7
|
-
export declare const parseTimeRange: (value: {
|
|
8
|
-
start?: string;
|
|
9
|
-
end?: string;
|
|
10
|
-
}) => {
|
|
11
|
-
start: Option<Time>;
|
|
12
|
-
end: Option<Time>;
|
|
13
|
-
};
|
|
14
|
-
export declare const validateTime: (time: Time) => boolean;
|
|
15
|
-
export declare const validateTimeRange: (range: {
|
|
16
|
-
start: Option<Time>;
|
|
17
|
-
end: Option<Time>;
|
|
18
|
-
}) => boolean;
|
|
19
|
-
export type TimePickerProps = {
|
|
20
|
-
value?: string;
|
|
21
|
-
onChangeText: (value: string) => void;
|
|
22
|
-
suggestionStart?: Time;
|
|
23
|
-
suggestionEnd?: Time;
|
|
24
|
-
intervalInMinutes?: number;
|
|
25
|
-
nbMaxSuggestions?: number;
|
|
26
|
-
suggestionSuffix?: (option: Time) => string;
|
|
27
|
-
readOnly?: boolean;
|
|
28
|
-
disabled?: boolean;
|
|
29
|
-
error?: string;
|
|
30
|
-
hideErrors?: boolean;
|
|
31
|
-
noSuggestionLabel: string;
|
|
32
|
-
};
|
|
33
|
-
export declare const TimePicker: ({ value, onChangeText, suggestionStart, suggestionEnd, intervalInMinutes, nbMaxSuggestions, suggestionSuffix, readOnly, disabled, error, hideErrors, noSuggestionLabel, }: TimePickerProps) => import("react").JSX.Element;
|
|
34
|
-
export type TimeRangePickerProps = {
|
|
35
|
-
value: {
|
|
36
|
-
start?: string;
|
|
37
|
-
end?: string;
|
|
38
|
-
};
|
|
39
|
-
onChange: (value: {
|
|
40
|
-
start?: string;
|
|
41
|
-
end?: string;
|
|
42
|
-
}) => void;
|
|
43
|
-
intervalInMinutes?: number;
|
|
44
|
-
nbMaxSuggestions?: number;
|
|
45
|
-
readOnly?: boolean;
|
|
46
|
-
disabled?: boolean;
|
|
47
|
-
error?: string;
|
|
48
|
-
startLabel: string;
|
|
49
|
-
endLabel: string;
|
|
50
|
-
minutesLabel: string;
|
|
51
|
-
hoursLabel: string;
|
|
52
|
-
noSuggestionLabel: string;
|
|
53
|
-
};
|
|
54
|
-
export declare const TimeRangePicker: ({ value, onChange, intervalInMinutes, nbMaxSuggestions, readOnly, disabled, error, startLabel, endLabel, minutesLabel, hoursLabel, noSuggestionLabel, }: TimeRangePickerProps) => import("react").JSX.Element;
|
|
55
|
-
export {};
|
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { AsyncData, Option, Result } from "@swan-io/boxed";
|
|
3
|
-
import { useMemo } from "react";
|
|
4
|
-
import { StyleSheet, View } from "react-native";
|
|
5
|
-
import { Rifm } from "rifm";
|
|
6
|
-
import { colors } from "../constants/design";
|
|
7
|
-
import { noop } from "../utils/function";
|
|
8
|
-
import { isNotNullishOrEmpty, isNullish } from "../utils/nullish";
|
|
9
|
-
import { getRifmProps } from "../utils/rifm";
|
|
10
|
-
import { Box } from "./Box";
|
|
11
|
-
import { Fill } from "./Fill";
|
|
12
|
-
import { Icon } from "./Icon";
|
|
13
|
-
import { LakeCombobox } from "./LakeCombobox";
|
|
14
|
-
import { LakeLabel } from "./LakeLabel";
|
|
15
|
-
import { LakeText } from "./LakeText";
|
|
16
|
-
import { Space } from "./Space";
|
|
17
|
-
const styles = StyleSheet.create({
|
|
18
|
-
label: {
|
|
19
|
-
flex: 1,
|
|
20
|
-
},
|
|
21
|
-
arrowContainer: {
|
|
22
|
-
height: 40, // input height
|
|
23
|
-
},
|
|
24
|
-
});
|
|
25
|
-
const DEFAULT_START_TIME = { hour: 0, minute: 0 };
|
|
26
|
-
const DEFAULT_END_TIME = { hour: 23, minute: 59 };
|
|
27
|
-
const DEFAULT_INTERVAL_IN_MINUTES = 15;
|
|
28
|
-
const rifmTimeProps = getRifmProps({
|
|
29
|
-
accept: "numeric",
|
|
30
|
-
charMap: { 2: ":" },
|
|
31
|
-
maxLength: 4,
|
|
32
|
-
});
|
|
33
|
-
export const parseTime = (time) => {
|
|
34
|
-
const [hours, minutes] = time.split(":").map(Number);
|
|
35
|
-
if (isNullish(hours) || Number.isNaN(hours) || isNullish(minutes) || Number.isNaN(minutes)) {
|
|
36
|
-
return Option.None();
|
|
37
|
-
}
|
|
38
|
-
return Option.Some({ hour: hours, minute: minutes });
|
|
39
|
-
};
|
|
40
|
-
export const parseTimeRange = (value) => {
|
|
41
|
-
const start = isNotNullishOrEmpty(value.start) ? parseTime(value.start) : Option.None();
|
|
42
|
-
const end = isNotNullishOrEmpty(value.end) ? parseTime(value.end) : Option.None();
|
|
43
|
-
return { start, end };
|
|
44
|
-
};
|
|
45
|
-
const parseTypingHours = (time) => {
|
|
46
|
-
const [hours, minutes] = time.split(":");
|
|
47
|
-
if (isNullish(hours) || (hours === null || hours === void 0 ? void 0 : hours.length) !== 2 || isNotNullishOrEmpty(minutes)) {
|
|
48
|
-
return Option.None();
|
|
49
|
-
}
|
|
50
|
-
const parsedHours = Number(hours);
|
|
51
|
-
if (parsedHours < 0 || parsedHours > 23) {
|
|
52
|
-
return Option.None();
|
|
53
|
-
}
|
|
54
|
-
if (Number.isNaN(parsedHours)) {
|
|
55
|
-
return Option.None();
|
|
56
|
-
}
|
|
57
|
-
return Option.Some(parsedHours);
|
|
58
|
-
};
|
|
59
|
-
const stringifyTime = (time) => {
|
|
60
|
-
return `${time.hour.toString().padStart(2, "0")}:${time.minute.toString().padStart(2, "0")}`;
|
|
61
|
-
};
|
|
62
|
-
const timeToMinutes = (time) => {
|
|
63
|
-
return time.hour * 60 + time.minute;
|
|
64
|
-
};
|
|
65
|
-
const minutesToTime = (minutes) => {
|
|
66
|
-
return {
|
|
67
|
-
hour: Math.floor(minutes / 60),
|
|
68
|
-
minute: minutes % 60,
|
|
69
|
-
};
|
|
70
|
-
};
|
|
71
|
-
const addMinutes = (time, minutes) => {
|
|
72
|
-
return minutesToTime(timeToMinutes(time) + minutes);
|
|
73
|
-
};
|
|
74
|
-
const floorTime = (time, intervalInMinutes) => {
|
|
75
|
-
const minutes = timeToMinutes(time);
|
|
76
|
-
const flooredMinutes = Math.floor(minutes / intervalInMinutes) * intervalInMinutes;
|
|
77
|
-
return minutesToTime(flooredMinutes);
|
|
78
|
-
};
|
|
79
|
-
export const validateTime = (time) => {
|
|
80
|
-
return time.hour >= 0 && time.hour <= 23 && time.minute >= 0 && time.minute <= 59;
|
|
81
|
-
};
|
|
82
|
-
const isTimeBefore = (time1, time2) => {
|
|
83
|
-
return timeToMinutes(time1) < timeToMinutes(time2);
|
|
84
|
-
};
|
|
85
|
-
export const validateTimeRange = (range) => {
|
|
86
|
-
if (range.start.isNone() || range.end.isNone()) {
|
|
87
|
-
return true;
|
|
88
|
-
}
|
|
89
|
-
return isTimeBefore(range.start.value, range.end.value);
|
|
90
|
-
};
|
|
91
|
-
const minTime = (...times) => {
|
|
92
|
-
const timesInMinutes = times.map(timeToMinutes);
|
|
93
|
-
const minTimeInMinutes = Math.min(...timesInMinutes);
|
|
94
|
-
return minutesToTime(minTimeInMinutes);
|
|
95
|
-
};
|
|
96
|
-
const maxTime = (...times) => {
|
|
97
|
-
const timesInMinutes = times.map(timeToMinutes);
|
|
98
|
-
const maxTimeInMinutes = Math.max(...timesInMinutes);
|
|
99
|
-
return minutesToTime(maxTimeInMinutes);
|
|
100
|
-
};
|
|
101
|
-
const generateTimeList = (start, end, intervalInMinutes) => {
|
|
102
|
-
const startMinutes = timeToMinutes(start);
|
|
103
|
-
const endMinutes = timeToMinutes(end);
|
|
104
|
-
const timeList = [];
|
|
105
|
-
for (let i = startMinutes; i <= endMinutes; i += intervalInMinutes) {
|
|
106
|
-
const time = minutesToTime(i);
|
|
107
|
-
timeList.push(time);
|
|
108
|
-
}
|
|
109
|
-
return timeList;
|
|
110
|
-
};
|
|
111
|
-
const formatTimeDuration = (time, minutesLabel, hoursLabel) => {
|
|
112
|
-
if (time.hour === 0) {
|
|
113
|
-
return `${time.minute} ${minutesLabel}`;
|
|
114
|
-
}
|
|
115
|
-
if (time.minute === 0) {
|
|
116
|
-
return `${time.hour} ${hoursLabel}`;
|
|
117
|
-
}
|
|
118
|
-
return `${time.hour} ${hoursLabel} ${time.minute} ${minutesLabel}`;
|
|
119
|
-
};
|
|
120
|
-
export const TimePicker = ({ value, onChangeText, suggestionStart = DEFAULT_START_TIME, suggestionEnd = DEFAULT_END_TIME, intervalInMinutes = DEFAULT_INTERVAL_IN_MINUTES, nbMaxSuggestions, suggestionSuffix, readOnly, disabled, error, hideErrors, noSuggestionLabel, }) => {
|
|
121
|
-
const typingHour = parseTypingHours(value !== null && value !== void 0 ? value : "");
|
|
122
|
-
const optionsInterval = useMemo(() => typingHour.match({
|
|
123
|
-
Some: hour => [
|
|
124
|
-
maxTime({ hour, minute: 0 }, suggestionStart),
|
|
125
|
-
minTime({ hour, minute: 59 }, suggestionEnd),
|
|
126
|
-
],
|
|
127
|
-
None: () => [suggestionStart, suggestionEnd],
|
|
128
|
-
}), [typingHour, suggestionStart, suggestionEnd]);
|
|
129
|
-
const options = useMemo(() => generateTimeList(optionsInterval[0], optionsInterval[1], intervalInMinutes).slice(0, nbMaxSuggestions), [optionsInterval, intervalInMinutes, nbMaxSuggestions]);
|
|
130
|
-
const items = useMemo(() => AsyncData.Done(Result.Ok(options)), [options]);
|
|
131
|
-
return (_jsx(Rifm, { value: value !== null && value !== void 0 ? value : "", onChange: onChangeText, ...rifmTimeProps, children: ({ value, onChange }) => (_jsx(LakeCombobox, { keyExtractor: stringifyTime, placeholder: "HH:MM", value: value, items: items, itemHeight: 40, nbItemsDisplayed: 4.5, renderItem: item => {
|
|
132
|
-
const text = stringifyTime(item);
|
|
133
|
-
const selected = text === value;
|
|
134
|
-
const suffix = suggestionSuffix === null || suggestionSuffix === void 0 ? void 0 : suggestionSuffix(item);
|
|
135
|
-
const label = isNotNullishOrEmpty(suffix) ? `${text} ${suffix}` : text;
|
|
136
|
-
return (_jsxs(Box, { direction: "row", alignItems: "center", children: [_jsx(LakeText, { color: selected ? colors.gray[700] : colors.gray[900], variant: selected ? "smallRegular" : "medium", children: label }), _jsx(Fill, { minWidth: 8 }), selected && (_jsx(Icon, { name: "checkmark-filled", color: colors.positive[500], size: 16 }))] }));
|
|
137
|
-
}, readOnly: readOnly, disabled: disabled, error: error, hideErrors: hideErrors, emptyResult: noSuggestionLabel, onChange: onChange, onValueChange: noop, onSelectItem: item => onChangeText(stringifyTime(item)) })) }));
|
|
138
|
-
};
|
|
139
|
-
export const TimeRangePicker = ({ value, onChange, intervalInMinutes = DEFAULT_INTERVAL_IN_MINUTES, nbMaxSuggestions, readOnly, disabled, error, startLabel, endLabel, minutesLabel, hoursLabel, noSuggestionLabel, }) => {
|
|
140
|
-
var _a;
|
|
141
|
-
const start = parseTime((_a = value.start) !== null && _a !== void 0 ? _a : "");
|
|
142
|
-
const handleStartChange = (startValue) => {
|
|
143
|
-
onChange({
|
|
144
|
-
start: startValue,
|
|
145
|
-
end: value.end,
|
|
146
|
-
});
|
|
147
|
-
};
|
|
148
|
-
const handleEndChange = (endValue) => {
|
|
149
|
-
onChange({
|
|
150
|
-
start: value.start,
|
|
151
|
-
end: endValue,
|
|
152
|
-
});
|
|
153
|
-
};
|
|
154
|
-
return (_jsxs(View, { children: [_jsxs(Box, { direction: "row", alignItems: "end", children: [_jsx(LakeLabel, { label: startLabel, style: styles.label, render: () => (_jsx(TimePicker, { value: value.start, intervalInMinutes: intervalInMinutes, nbMaxSuggestions: nbMaxSuggestions, error: error, hideErrors: true, disabled: disabled, readOnly: readOnly, noSuggestionLabel: noSuggestionLabel, onChangeText: handleStartChange })) }), _jsx(Space, { width: 12 }), _jsx(Box, { style: styles.arrowContainer, justifyContent: "center", children: _jsx(Icon, { name: "arrow-right-filled", size: 20 }) }), _jsx(Space, { width: 12 }), _jsx(LakeLabel, { label: endLabel, style: styles.label, render: () => (_jsx(TimePicker, { value: value.end, intervalInMinutes: intervalInMinutes, nbMaxSuggestions: nbMaxSuggestions, suggestionStart: start
|
|
155
|
-
.map(time => floorTime(time, intervalInMinutes))
|
|
156
|
-
.map(time => addMinutes(time, intervalInMinutes))
|
|
157
|
-
.match({
|
|
158
|
-
Some: time => time,
|
|
159
|
-
None: () => undefined,
|
|
160
|
-
}), suggestionSuffix: time => {
|
|
161
|
-
if (start.isNone()) {
|
|
162
|
-
return "";
|
|
163
|
-
}
|
|
164
|
-
const durationInMinutes = timeToMinutes(time) - timeToMinutes(start.value);
|
|
165
|
-
if (durationInMinutes > 0 && durationInMinutes <= 60) {
|
|
166
|
-
const timeDuration = minutesToTime(durationInMinutes);
|
|
167
|
-
return `(${formatTimeDuration(timeDuration, minutesLabel, hoursLabel)})`;
|
|
168
|
-
}
|
|
169
|
-
return "";
|
|
170
|
-
}, error: error, hideErrors: true, disabled: disabled, readOnly: readOnly, noSuggestionLabel: noSuggestionLabel, onChangeText: handleEndChange })) })] }), _jsx(Space, { height: 4 }), _jsx(LakeText, { variant: "smallRegular", color: colors.negative[500], children: error !== null && error !== void 0 ? error : " " })] }));
|
|
171
|
-
};
|