@pushwoosh/dumb-components 1.1.47 → 1.1.48
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/Calendar/CalendarDropdown/CalendarDropdown.d.ts +3 -0
- package/Calendar/CalendarDropdown/CalendarDropdown.js +158 -0
- package/Calendar/CalendarDropdown/helpers.d.ts +3 -0
- package/Calendar/CalendarDropdown/helpers.js +29 -0
- package/Calendar/CalendarDropdown/index.d.ts +2 -0
- package/Calendar/CalendarDropdown/index.js +1 -0
- package/Calendar/CalendarDropdown/styles.d.ts +61 -0
- package/Calendar/CalendarDropdown/styles.js +16 -0
- package/Calendar/CalendarDropdown/types.d.ts +40 -0
- package/Calendar/CalendarDropdown/types.js +1 -0
- package/Calendar/CalendarMonth/CalendarMonth.d.ts +3 -0
- package/Calendar/CalendarMonth/CalendarMonth.js +109 -0
- package/Calendar/CalendarMonth/styles.d.ts +7 -0
- package/Calendar/CalendarMonth/styles.js +48 -0
- package/Calendar/CalendarMonth/types.d.ts +17 -0
- package/Calendar/CalendarMonth/types.js +1 -0
- package/Calendar/CalendarMonthSlider/CalendarMonthSlider.d.ts +11 -0
- package/Calendar/CalendarMonthSlider/CalendarMonthSlider.js +141 -0
- package/Calendar/CalendarMonthSlider/styles.d.ts +67 -0
- package/Calendar/CalendarMonthSlider/styles.js +40 -0
- package/Calendar/CalendarSuperForm/CalendarSuperForm.d.ts +3 -0
- package/Calendar/CalendarSuperForm/CalendarSuperForm.js +101 -0
- package/Calendar/CalendarSuperForm/components/CalendarRangePicker/CalendarRangePicker.d.ts +19 -0
- package/Calendar/CalendarSuperForm/components/CalendarRangePicker/CalendarRangePicker.js +57 -0
- package/Calendar/CalendarSuperForm/components/CalendarRangePicker/getDisabledRanges.d.ts +14 -0
- package/Calendar/CalendarSuperForm/components/CalendarRangePicker/getDisabledRanges.js +62 -0
- package/Calendar/CalendarSuperForm/components/CalendarTimeAndTimezoneSection/CalendarTimeAndTimezoneSection.d.ts +3 -0
- package/Calendar/CalendarSuperForm/components/CalendarTimeAndTimezoneSection/CalendarTimeAndTimezoneSection.js +135 -0
- package/Calendar/CalendarSuperForm/components/CalendarTimeAndTimezoneSection/types.d.ts +18 -0
- package/Calendar/CalendarSuperForm/components/CalendarTimeAndTimezoneSection/types.js +1 -0
- package/Calendar/CalendarSuperForm/components/CalendarTimeInput.d.ts +19 -0
- package/Calendar/CalendarSuperForm/components/CalendarTimeInput.js +25 -0
- package/Calendar/CalendarSuperForm/components/CalendarTimezoneSelect.d.ts +9 -0
- package/Calendar/CalendarSuperForm/components/CalendarTimezoneSelect.js +26 -0
- package/Calendar/CalendarSuperForm/index.d.ts +2 -0
- package/Calendar/CalendarSuperForm/index.js +1 -0
- package/Calendar/CalendarSuperForm/types.d.ts +56 -0
- package/Calendar/CalendarSuperForm/types.js +1 -0
- package/Calendar/constants.d.ts +5 -0
- package/Calendar/constants.js +10 -0
- package/Calendar/helpers-tz.d.ts +7 -0
- package/Calendar/helpers-tz.js +100 -0
- package/Calendar/helpers.d.ts +22 -0
- package/Calendar/helpers.js +134 -0
- package/Calendar/index.d.ts +2 -0
- package/Calendar/index.js +2 -0
- package/Calendar/types.d.ts +19 -0
- package/Calendar/types.js +1 -0
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/native/NativeTimeInput.js +2 -2
- package/package.json +3 -2
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { Horizontal, usePersistentFunction, Vertical } from '@pushwoosh/kit-helpers';
|
|
3
|
+
import { ArrowIcon } from '@pushwoosh/kit-icons';
|
|
4
|
+
import { Root, Viewport, Strip, Panel, NavButtonLeft, NavButtonRight, StyledSelect } from './styles';
|
|
5
|
+
import { Button } from '../../Button';
|
|
6
|
+
import { CalendarMonth } from '../CalendarMonth/CalendarMonth';
|
|
7
|
+
import { addPeriod, monthName } from '../helpers';
|
|
8
|
+
function makeBaseline(a, count) {
|
|
9
|
+
return Array.from({
|
|
10
|
+
length: count
|
|
11
|
+
}, (_, i) => addPeriod(a, 'month', i));
|
|
12
|
+
}
|
|
13
|
+
function delayCallback(fn) {
|
|
14
|
+
return setTimeout(() => {
|
|
15
|
+
requestAnimationFrame(fn);
|
|
16
|
+
}, 10);
|
|
17
|
+
}
|
|
18
|
+
export const CalendarMonthSlider = ({
|
|
19
|
+
startMonth,
|
|
20
|
+
monthWidth = 224,
|
|
21
|
+
gap = 16,
|
|
22
|
+
visibleCount = 1,
|
|
23
|
+
renderAfter,
|
|
24
|
+
...monthProps
|
|
25
|
+
}) => {
|
|
26
|
+
const [anchor, setAnchor] = useState(startMonth);
|
|
27
|
+
const [inTransition, setInTransition] = useState(false);
|
|
28
|
+
const [index, setIndex] = useState(0);
|
|
29
|
+
const [panels, setPanels] = useState(() => makeBaseline(anchor, visibleCount));
|
|
30
|
+
const stepPx = monthWidth + gap;
|
|
31
|
+
const shiftPx = index * (stepPx * -1);
|
|
32
|
+
const toBaseline = usePersistentFunction(mon => {
|
|
33
|
+
setInTransition(false);
|
|
34
|
+
setPanels(makeBaseline(mon, visibleCount));
|
|
35
|
+
setIndex(0);
|
|
36
|
+
});
|
|
37
|
+
const animateForward = () => {
|
|
38
|
+
const newAnchor = addPeriod(anchor, 'month', 1);
|
|
39
|
+
setPanels(makeBaseline(anchor, visibleCount + 1));
|
|
40
|
+
setIndex(0);
|
|
41
|
+
delayCallback(() => {
|
|
42
|
+
setInTransition(true);
|
|
43
|
+
setIndex(1);
|
|
44
|
+
});
|
|
45
|
+
setAnchor(newAnchor);
|
|
46
|
+
};
|
|
47
|
+
const animateBackward = () => {
|
|
48
|
+
const newAnchor = addPeriod(anchor, 'month', -1);
|
|
49
|
+
setPanels(makeBaseline(newAnchor, visibleCount + 1));
|
|
50
|
+
setIndex(1);
|
|
51
|
+
delayCallback(() => {
|
|
52
|
+
setInTransition(true);
|
|
53
|
+
setIndex(0);
|
|
54
|
+
});
|
|
55
|
+
setAnchor(newAnchor);
|
|
56
|
+
};
|
|
57
|
+
const handleMonthChange = (event, panelIndex, currentPanel) => {
|
|
58
|
+
const monthNumber = parseInt(event.target.value, 10);
|
|
59
|
+
const selectedDate = {
|
|
60
|
+
...currentPanel,
|
|
61
|
+
month: monthNumber
|
|
62
|
+
};
|
|
63
|
+
const newAnchor = addPeriod(selectedDate, 'month', -panelIndex);
|
|
64
|
+
setAnchor(newAnchor);
|
|
65
|
+
setPanels(makeBaseline(newAnchor, visibleCount));
|
|
66
|
+
};
|
|
67
|
+
const handleYearChange = (event, panelIndex, currentPanel) => {
|
|
68
|
+
const yearNumber = parseInt(event.target.value, 10);
|
|
69
|
+
const selectedDate = {
|
|
70
|
+
...currentPanel,
|
|
71
|
+
year: yearNumber
|
|
72
|
+
};
|
|
73
|
+
const newAnchor = addPeriod(selectedDate, 'month', -panelIndex);
|
|
74
|
+
setAnchor(newAnchor);
|
|
75
|
+
setPanels(makeBaseline(newAnchor, visibleCount));
|
|
76
|
+
};
|
|
77
|
+
const currentYear = new Date().getFullYear();
|
|
78
|
+
const yearOptions = Array.from({
|
|
79
|
+
length: 11
|
|
80
|
+
}, (_, i) => currentYear - 5 + i);
|
|
81
|
+
const viewportWidth = `${visibleCount * monthWidth + gap * (visibleCount - 1)}px`;
|
|
82
|
+
return React.createElement(Root, {
|
|
83
|
+
style: {
|
|
84
|
+
['--slider-width']: viewportWidth,
|
|
85
|
+
['--col-width']: `${monthWidth}px`,
|
|
86
|
+
['--gap']: `${gap}px`,
|
|
87
|
+
['--shift']: `${shiftPx}px`
|
|
88
|
+
}
|
|
89
|
+
}, React.createElement(Viewport, null, React.createElement(Strip, {
|
|
90
|
+
withTransition: inTransition,
|
|
91
|
+
onTransitionEnd: () => {
|
|
92
|
+
toBaseline(anchor);
|
|
93
|
+
}
|
|
94
|
+
}, panels.map((p, i) =>
|
|
95
|
+
// eslint-disable-next-line react/no-array-index-key
|
|
96
|
+
React.createElement(Panel, {
|
|
97
|
+
key: `${p.year}-${p.month}-${i}`
|
|
98
|
+
}, React.createElement(Vertical, {
|
|
99
|
+
"$gap": 4
|
|
100
|
+
}, React.createElement(Horizontal, {
|
|
101
|
+
"$justifyContent": "center",
|
|
102
|
+
"$gap": 6
|
|
103
|
+
}, React.createElement(StyledSelect, {
|
|
104
|
+
value: p.month,
|
|
105
|
+
onChange: e => handleMonthChange(e, i, p)
|
|
106
|
+
}, Array.from({
|
|
107
|
+
length: 12
|
|
108
|
+
}, (_, idx) => React.createElement("option", {
|
|
109
|
+
key: idx + 1,
|
|
110
|
+
value: idx + 1
|
|
111
|
+
}, monthName(idx + 1, 'long')))), React.createElement(StyledSelect, {
|
|
112
|
+
value: p.year,
|
|
113
|
+
onChange: e => handleYearChange(e, i, p)
|
|
114
|
+
}, yearOptions.map(year => React.createElement("option", {
|
|
115
|
+
key: year,
|
|
116
|
+
value: year
|
|
117
|
+
}, year)))), React.createElement(CalendarMonth, {
|
|
118
|
+
month: p,
|
|
119
|
+
...monthProps
|
|
120
|
+
})))))), React.createElement(NavButtonLeft, null, React.createElement(Button, {
|
|
121
|
+
color: "secondary",
|
|
122
|
+
size: "compact",
|
|
123
|
+
view: "ghost",
|
|
124
|
+
icon: React.createElement(ArrowIcon, {
|
|
125
|
+
size: "small",
|
|
126
|
+
direction: "left"
|
|
127
|
+
}),
|
|
128
|
+
onClick: animateBackward,
|
|
129
|
+
isDisabled: inTransition
|
|
130
|
+
})), React.createElement(NavButtonRight, null, React.createElement(Button, {
|
|
131
|
+
color: "secondary",
|
|
132
|
+
size: "compact",
|
|
133
|
+
view: "ghost",
|
|
134
|
+
icon: React.createElement(ArrowIcon, {
|
|
135
|
+
size: "small",
|
|
136
|
+
direction: "right"
|
|
137
|
+
}),
|
|
138
|
+
onClick: animateForward,
|
|
139
|
+
isDisabled: inTransition
|
|
140
|
+
})), renderAfter === null || renderAfter === void 0 ? void 0 : renderAfter());
|
|
141
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export declare const Root: import("styled-components").StyledComponent<"div", any, {
|
|
2
|
+
$alignContent?: "end" | "start" | "center" | "space-between" | "space-around" | "space-evenly" | "stretch" | undefined;
|
|
3
|
+
$alignItems?: "end" | "start" | "center" | "stretch" | "baseline" | undefined;
|
|
4
|
+
$bgColor?: string | undefined;
|
|
5
|
+
$border?: string | ({
|
|
6
|
+
top?: string | undefined;
|
|
7
|
+
right?: string | undefined;
|
|
8
|
+
bottom?: string | undefined;
|
|
9
|
+
left?: string | undefined;
|
|
10
|
+
} | {
|
|
11
|
+
horizontal: string;
|
|
12
|
+
top?: string | undefined;
|
|
13
|
+
bottom?: string | undefined;
|
|
14
|
+
} | {
|
|
15
|
+
vertical: string;
|
|
16
|
+
right?: string | undefined;
|
|
17
|
+
left?: string | undefined;
|
|
18
|
+
}) | undefined;
|
|
19
|
+
$borderRadius?: (string | number) | undefined;
|
|
20
|
+
$boxShadow?: string | undefined;
|
|
21
|
+
$gap?: (string | number) | undefined;
|
|
22
|
+
$gridAutoFlow?: "row" | "column" | "dense" | "row dense" | "column dense" | undefined;
|
|
23
|
+
$justifyContent?: "end" | "start" | "center" | "space-between" | "space-around" | "space-evenly" | "stretch" | undefined;
|
|
24
|
+
$justifyItems?: "end" | "start" | "center" | "stretch" | "baseline" | undefined;
|
|
25
|
+
$margin?: (string | number) | ({
|
|
26
|
+
top?: (string | number) | undefined;
|
|
27
|
+
right?: (string | number) | undefined;
|
|
28
|
+
bottom?: (string | number) | undefined;
|
|
29
|
+
left?: (string | number) | undefined;
|
|
30
|
+
} | {
|
|
31
|
+
horizontal: string | number;
|
|
32
|
+
top?: (string | number) | undefined;
|
|
33
|
+
bottom?: (string | number) | undefined;
|
|
34
|
+
} | {
|
|
35
|
+
vertical: string | number;
|
|
36
|
+
right?: (string | number) | undefined;
|
|
37
|
+
left?: (string | number) | undefined;
|
|
38
|
+
}) | undefined;
|
|
39
|
+
$padding?: (string | number) | ({
|
|
40
|
+
top?: (string | number) | undefined;
|
|
41
|
+
right?: (string | number) | undefined;
|
|
42
|
+
bottom?: (string | number) | undefined;
|
|
43
|
+
left?: (string | number) | undefined;
|
|
44
|
+
} | {
|
|
45
|
+
horizontal: string | number;
|
|
46
|
+
top?: (string | number) | undefined;
|
|
47
|
+
bottom?: (string | number) | undefined;
|
|
48
|
+
} | {
|
|
49
|
+
vertical: string | number;
|
|
50
|
+
right?: (string | number) | undefined;
|
|
51
|
+
left?: (string | number) | undefined;
|
|
52
|
+
}) | undefined;
|
|
53
|
+
$placeItems?: "end" | "start" | "center" | "stretch" | undefined;
|
|
54
|
+
} & {
|
|
55
|
+
$gridAutoFlow: string;
|
|
56
|
+
}, "$gridAutoFlow">;
|
|
57
|
+
export declare const Viewport: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
58
|
+
export declare const Strip: import("styled-components").StyledComponent<"div", any, {
|
|
59
|
+
withTransition: boolean;
|
|
60
|
+
}, never>;
|
|
61
|
+
export declare const Panel: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
62
|
+
export declare const Arrow: import("styled-components").StyledComponent<import("react").FC<import("@pushwoosh/kit-icons").ArrowIconProps>, any, {
|
|
63
|
+
size: "small";
|
|
64
|
+
}, "size">;
|
|
65
|
+
export declare const NavButtonLeft: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
66
|
+
export declare const NavButtonRight: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
67
|
+
export declare const StyledSelect: import("styled-components").StyledComponent<"select", any, {}, never>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import styled, { css } from 'styled-components';
|
|
2
|
+
import { Color, FontFamily, FontSize, FontWeight, LineHeight, UnitSize } from '@pushwoosh/kit-constants';
|
|
3
|
+
import { Vertical } from '@pushwoosh/kit-helpers';
|
|
4
|
+
import { ArrowIcon } from '@pushwoosh/kit-icons';
|
|
5
|
+
export const Root = styled(Vertical).withConfig({
|
|
6
|
+
displayName: "Root",
|
|
7
|
+
componentId: "sc-1qqlxvi-0"
|
|
8
|
+
})(["position:relative;width:var(--slider-width,0px);"]);
|
|
9
|
+
export const Viewport = styled.div.withConfig({
|
|
10
|
+
displayName: "Viewport",
|
|
11
|
+
componentId: "sc-1qqlxvi-1"
|
|
12
|
+
})(["position:relative;overflow:hidden;width:var(--slider-width,0px);"]);
|
|
13
|
+
export const Strip = styled.div.withConfig({
|
|
14
|
+
displayName: "Strip",
|
|
15
|
+
componentId: "sc-1qqlxvi-2"
|
|
16
|
+
})(["display:grid;grid-auto-flow:column;grid-auto-columns:var(--col-width,0px);column-gap:var(--gap,0px);transform:translateX(var(--shift,0px));", ""], ({
|
|
17
|
+
withTransition
|
|
18
|
+
}) => withTransition && css(["transition:transform var(--duration,150ms) ease-out;"]));
|
|
19
|
+
export const Panel = styled.div.withConfig({
|
|
20
|
+
displayName: "Panel",
|
|
21
|
+
componentId: "sc-1qqlxvi-3"
|
|
22
|
+
})(["width:var(--col-width,0px);"]);
|
|
23
|
+
export const Arrow = styled(ArrowIcon).attrs({
|
|
24
|
+
size: 'small'
|
|
25
|
+
}).withConfig({
|
|
26
|
+
displayName: "Arrow",
|
|
27
|
+
componentId: "sc-1qqlxvi-4"
|
|
28
|
+
})(["color:", ";cursor:pointer;&:hover{color:", ";transform:scale(1.2);transition:transform 0.2s ease-in-out;}"], Color.SOFT_HOVER, Color.SOFT_HOVER);
|
|
29
|
+
export const NavButtonLeft = styled.div.withConfig({
|
|
30
|
+
displayName: "NavButtonLeft",
|
|
31
|
+
componentId: "sc-1qqlxvi-5"
|
|
32
|
+
})(["position:absolute;top:0;left:0;"]);
|
|
33
|
+
export const NavButtonRight = styled.div.withConfig({
|
|
34
|
+
displayName: "NavButtonRight",
|
|
35
|
+
componentId: "sc-1qqlxvi-6"
|
|
36
|
+
})(["position:absolute;top:0;right:0;"]);
|
|
37
|
+
export const StyledSelect = styled.select.withConfig({
|
|
38
|
+
displayName: "StyledSelect",
|
|
39
|
+
componentId: "sc-1qqlxvi-7"
|
|
40
|
+
})(["appearance:none;background:transparent;border:none;padding:0;height:", ";cursor:pointer;color:", ";font-family:", ";font-size:", ";font-weight:", ";line-height:", ";text-transform:uppercase;&:hover{color:", ";}&:focus{outline:none;}"], UnitSize.COMPACT_HEIGHT, Color.SOFT, FontFamily.MAIN, FontSize.HEADING5, FontWeight.MEDIUM, LineHeight.HEADING5, Color.PRIMARY_HOVER);
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Color } from '@pushwoosh/kit-constants';
|
|
3
|
+
import { Vertical } from '@pushwoosh/kit-helpers';
|
|
4
|
+
import { Text } from '@pushwoosh/kit-typography';
|
|
5
|
+
import { CalendarRangePicker } from './components/CalendarRangePicker/CalendarRangePicker';
|
|
6
|
+
import { CalendarTimeAndTimezoneSection } from './components/CalendarTimeAndTimezoneSection/CalendarTimeAndTimezoneSection';
|
|
7
|
+
export const CalendarSuperForm = props => {
|
|
8
|
+
const {
|
|
9
|
+
mode,
|
|
10
|
+
value,
|
|
11
|
+
onChange,
|
|
12
|
+
timezone,
|
|
13
|
+
onChangeTimezone,
|
|
14
|
+
disableOnAndBefore,
|
|
15
|
+
disableOnAndAfter,
|
|
16
|
+
minDays,
|
|
17
|
+
maxDays,
|
|
18
|
+
visibleCount,
|
|
19
|
+
monthWidth,
|
|
20
|
+
gap,
|
|
21
|
+
firstDayOfWeek
|
|
22
|
+
} = props;
|
|
23
|
+
const isRangePicker = mode === 'range-date' || mode === 'range-datetime';
|
|
24
|
+
const withTime = mode === 'single-datetime' || mode === 'range-datetime';
|
|
25
|
+
return React.createElement(Vertical, {
|
|
26
|
+
"$gap": 8
|
|
27
|
+
}, React.createElement(CalendarRangePicker, {
|
|
28
|
+
disableOnAndBefore: disableOnAndBefore,
|
|
29
|
+
disableOnAndAfter: disableOnAndAfter,
|
|
30
|
+
minDays: minDays,
|
|
31
|
+
maxDays: maxDays,
|
|
32
|
+
value: isRangePicker ? value : value ? [value] : [],
|
|
33
|
+
onChange: val => {
|
|
34
|
+
if (isRangePicker) {
|
|
35
|
+
if (withTime) {
|
|
36
|
+
if (val.length === 2) {
|
|
37
|
+
onChange([{
|
|
38
|
+
...val[0],
|
|
39
|
+
hour: 0,
|
|
40
|
+
minute: 0,
|
|
41
|
+
second: 0,
|
|
42
|
+
millisecond: 0
|
|
43
|
+
}, {
|
|
44
|
+
...val[1],
|
|
45
|
+
hour: 23,
|
|
46
|
+
minute: 59,
|
|
47
|
+
second: 59,
|
|
48
|
+
millisecond: 999
|
|
49
|
+
}]);
|
|
50
|
+
} else if (val.length === 1) {
|
|
51
|
+
onChange([{
|
|
52
|
+
hour: 0,
|
|
53
|
+
minute: 0,
|
|
54
|
+
second: 0,
|
|
55
|
+
millisecond: 0,
|
|
56
|
+
...val[0]
|
|
57
|
+
}]);
|
|
58
|
+
}
|
|
59
|
+
} else {
|
|
60
|
+
onChange(val);
|
|
61
|
+
}
|
|
62
|
+
} else if (val[0]) {
|
|
63
|
+
if (withTime) {
|
|
64
|
+
onChange({
|
|
65
|
+
hour: 0,
|
|
66
|
+
minute: 0,
|
|
67
|
+
second: 0,
|
|
68
|
+
millisecond: 0,
|
|
69
|
+
...value,
|
|
70
|
+
...val[0]
|
|
71
|
+
});
|
|
72
|
+
} else {
|
|
73
|
+
onChange(val[0]);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
singleMode: !isRangePicker,
|
|
78
|
+
visibleCount: visibleCount !== undefined ? visibleCount : isRangePicker ? 2 : 1,
|
|
79
|
+
monthWidth: monthWidth,
|
|
80
|
+
gap: gap,
|
|
81
|
+
renderAfter: withTime || maxDays && maxDays > 0 ? () => {
|
|
82
|
+
return React.createElement(Vertical, {
|
|
83
|
+
"$gap": 8,
|
|
84
|
+
"$margin": {
|
|
85
|
+
top: 16
|
|
86
|
+
}
|
|
87
|
+
}, maxDays && maxDays > 0 && React.createElement(Text, {
|
|
88
|
+
"$variant": "footnote",
|
|
89
|
+
"$color": Color.LOCKED
|
|
90
|
+
}, `Max length: ${maxDays} days`), withTime && timezone && onChangeTimezone && React.createElement(CalendarTimeAndTimezoneSection, {
|
|
91
|
+
isRangePicker: isRangePicker,
|
|
92
|
+
value: value,
|
|
93
|
+
onChange: onChange,
|
|
94
|
+
timezone: timezone,
|
|
95
|
+
onChangeTimezone: onChangeTimezone,
|
|
96
|
+
visibleCount: visibleCount
|
|
97
|
+
}));
|
|
98
|
+
} : undefined,
|
|
99
|
+
firstDayOfWeek: firstDayOfWeek
|
|
100
|
+
}));
|
|
101
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React, { type FC } from 'react';
|
|
2
|
+
import { type DateStruct } from '../../../types';
|
|
3
|
+
export type RangePickerValue = [DateStruct, DateStruct] | [DateStruct] | [];
|
|
4
|
+
type CalendarRangePickerProps = {
|
|
5
|
+
value: RangePickerValue;
|
|
6
|
+
visibleCount?: number;
|
|
7
|
+
monthWidth?: number;
|
|
8
|
+
gap?: number;
|
|
9
|
+
singleMode?: boolean;
|
|
10
|
+
disableOnAndBefore?: DateStruct;
|
|
11
|
+
disableOnAndAfter?: DateStruct;
|
|
12
|
+
minDays?: number;
|
|
13
|
+
maxDays?: number;
|
|
14
|
+
onChange: (range: RangePickerValue) => void;
|
|
15
|
+
renderAfter?: () => React.ReactNode;
|
|
16
|
+
firstDayOfWeek?: 0 | 1;
|
|
17
|
+
};
|
|
18
|
+
export declare const CalendarRangePicker: FC<CalendarRangePickerProps>;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import React, { useRef } from 'react';
|
|
2
|
+
import { getDisabledRanges } from './getDisabledRanges';
|
|
3
|
+
import { CalendarMonthSlider } from '../../../CalendarMonthSlider/CalendarMonthSlider';
|
|
4
|
+
import { compareStructs } from '../../../helpers';
|
|
5
|
+
export const CalendarRangePicker = ({
|
|
6
|
+
value,
|
|
7
|
+
visibleCount,
|
|
8
|
+
monthWidth = 224,
|
|
9
|
+
gap = 16,
|
|
10
|
+
singleMode,
|
|
11
|
+
disableOnAndBefore,
|
|
12
|
+
disableOnAndAfter,
|
|
13
|
+
minDays,
|
|
14
|
+
maxDays,
|
|
15
|
+
onChange,
|
|
16
|
+
renderAfter,
|
|
17
|
+
firstDayOfWeek
|
|
18
|
+
}) => {
|
|
19
|
+
const startMonthRef = useRef();
|
|
20
|
+
if (!startMonthRef.current) {
|
|
21
|
+
const d = new Date();
|
|
22
|
+
startMonthRef.current = value[0] || {
|
|
23
|
+
year: d.getFullYear(),
|
|
24
|
+
month: d.getMonth() + 1,
|
|
25
|
+
day: d.getDate()
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
return React.createElement(CalendarMonthSlider, {
|
|
29
|
+
startMonth: startMonthRef.current,
|
|
30
|
+
visibleCount: visibleCount,
|
|
31
|
+
monthWidth: monthWidth,
|
|
32
|
+
gap: gap,
|
|
33
|
+
renderAfter: renderAfter,
|
|
34
|
+
firstDayOfWeek: firstDayOfWeek,
|
|
35
|
+
selectedDay: singleMode ? value[0] : undefined,
|
|
36
|
+
periodFrom: !singleMode ? value[0] : undefined,
|
|
37
|
+
periodTo: !singleMode ? value[1] : undefined,
|
|
38
|
+
...getDisabledRanges({
|
|
39
|
+
value,
|
|
40
|
+
disableOnAndBefore,
|
|
41
|
+
disableOnAndAfter,
|
|
42
|
+
minDays,
|
|
43
|
+
maxDays
|
|
44
|
+
}),
|
|
45
|
+
onDaySelect: day => {
|
|
46
|
+
if (singleMode || !value[0] || value.length === 2) {
|
|
47
|
+
onChange([day]);
|
|
48
|
+
} else if (value.length === 1) {
|
|
49
|
+
if (compareStructs(day, value[0]) < 0) {
|
|
50
|
+
onChange([day, value[0]]);
|
|
51
|
+
} else {
|
|
52
|
+
onChange([value[0], day]);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type DateStruct } from '../../../types';
|
|
2
|
+
export type DisableSpec = {
|
|
3
|
+
disableOnAndBefore?: DateStruct;
|
|
4
|
+
disableOnAndAfter?: DateStruct;
|
|
5
|
+
disablePeriod?: [from: DateStruct, to: DateStruct];
|
|
6
|
+
};
|
|
7
|
+
export type GetDisabledArgs = {
|
|
8
|
+
value?: [from: DateStruct, to: DateStruct] | [from: DateStruct] | [];
|
|
9
|
+
disableOnAndBefore?: DateStruct;
|
|
10
|
+
disableOnAndAfter?: DateStruct;
|
|
11
|
+
minDays?: number;
|
|
12
|
+
maxDays?: number;
|
|
13
|
+
};
|
|
14
|
+
export declare function getDisabledRanges(args: GetDisabledArgs): DisableSpec;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { addPeriod, compareStructs } from '../../../helpers';
|
|
2
|
+
export function getDisabledRanges(args) {
|
|
3
|
+
const {
|
|
4
|
+
value,
|
|
5
|
+
disableOnAndBefore,
|
|
6
|
+
disableOnAndAfter,
|
|
7
|
+
minDays,
|
|
8
|
+
maxDays
|
|
9
|
+
} = args;
|
|
10
|
+
if (!value || value.length === 0) {
|
|
11
|
+
return {
|
|
12
|
+
disableOnAndBefore,
|
|
13
|
+
disableOnAndAfter
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
const result = {};
|
|
17
|
+
if (value.length === 1) {
|
|
18
|
+
const startDate = value[0];
|
|
19
|
+
if (minDays !== undefined && minDays > 1) {
|
|
20
|
+
const beforeDate = addPeriod(startDate, 'day', -(minDays - 2));
|
|
21
|
+
const afterDate = addPeriod(startDate, 'day', minDays - 2);
|
|
22
|
+
result.disablePeriod = [beforeDate, afterDate];
|
|
23
|
+
}
|
|
24
|
+
if (maxDays !== undefined) {
|
|
25
|
+
const maxBefore = addPeriod(startDate, 'day', -maxDays);
|
|
26
|
+
const maxAfter = addPeriod(startDate, 'day', maxDays);
|
|
27
|
+
if (result.disableOnAndBefore) {
|
|
28
|
+
if (compareStructs(maxBefore, result.disableOnAndBefore) > 0) {
|
|
29
|
+
result.disableOnAndBefore = maxBefore;
|
|
30
|
+
}
|
|
31
|
+
} else {
|
|
32
|
+
result.disableOnAndBefore = maxBefore;
|
|
33
|
+
}
|
|
34
|
+
if (result.disableOnAndAfter) {
|
|
35
|
+
if (compareStructs(maxAfter, result.disableOnAndAfter) < 0) {
|
|
36
|
+
result.disableOnAndAfter = maxAfter;
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
result.disableOnAndAfter = maxAfter;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (disableOnAndBefore) {
|
|
44
|
+
if (result.disableOnAndBefore) {
|
|
45
|
+
if (compareStructs(disableOnAndBefore, result.disableOnAndBefore) > 0) {
|
|
46
|
+
result.disableOnAndBefore = disableOnAndBefore;
|
|
47
|
+
}
|
|
48
|
+
} else {
|
|
49
|
+
result.disableOnAndBefore = disableOnAndBefore;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (disableOnAndAfter) {
|
|
53
|
+
if (result.disableOnAndAfter) {
|
|
54
|
+
if (compareStructs(disableOnAndAfter, result.disableOnAndAfter) < 0) {
|
|
55
|
+
result.disableOnAndAfter = disableOnAndAfter;
|
|
56
|
+
}
|
|
57
|
+
} else {
|
|
58
|
+
result.disableOnAndAfter = disableOnAndAfter;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { Color, ShapeRadius } from '@pushwoosh/kit-constants';
|
|
3
|
+
import { Columns, Horizontal, Vertical } from '@pushwoosh/kit-helpers';
|
|
4
|
+
import { TimeIcon } from '@pushwoosh/kit-icons';
|
|
5
|
+
import { H5, Text } from '@pushwoosh/kit-typography';
|
|
6
|
+
import { Button } from '../../../../Button';
|
|
7
|
+
import { extendPeriodStruct, formatTwoDigitNumber } from '../../../helpers';
|
|
8
|
+
import { formatTimezoneShort } from '../../../helpers-tz';
|
|
9
|
+
import { CalendarTimeInput } from '../CalendarTimeInput';
|
|
10
|
+
import { CalendarTimezoneSelect } from '../CalendarTimezoneSelect';
|
|
11
|
+
export const CalendarTimeAndTimezoneSection = ({
|
|
12
|
+
isRangePicker,
|
|
13
|
+
value,
|
|
14
|
+
onChange,
|
|
15
|
+
timezone,
|
|
16
|
+
onChangeTimezone,
|
|
17
|
+
visibleCount
|
|
18
|
+
}) => {
|
|
19
|
+
const [expanded, setExpanded] = useState(false);
|
|
20
|
+
const timezoneShort = formatTimezoneShort(timezone);
|
|
21
|
+
const getSelectedTimeText = () => {
|
|
22
|
+
if (isRangePicker) {
|
|
23
|
+
const [startValue, endValue] = value;
|
|
24
|
+
const startTime = startValue ? `${formatTwoDigitNumber(startValue.hour || 0)}:${formatTwoDigitNumber(startValue.minute || 0)}` : '00:00';
|
|
25
|
+
const endTime = endValue ? `${formatTwoDigitNumber(endValue.hour || 0)}:${formatTwoDigitNumber(endValue.minute || 0)}` : '23:59';
|
|
26
|
+
return `${startTime} – ${endTime}`;
|
|
27
|
+
}
|
|
28
|
+
return value ? `${formatTwoDigitNumber(value.hour || 0)}:${formatTwoDigitNumber(value.minute || 0)}` : '00:00';
|
|
29
|
+
};
|
|
30
|
+
const showCollapsed = isRangePicker && !expanded;
|
|
31
|
+
const isDisabled = isRangePicker ? value.length !== 2 : !value;
|
|
32
|
+
let padding;
|
|
33
|
+
let backgroundColor;
|
|
34
|
+
let borderRadius;
|
|
35
|
+
if (!isRangePicker) {
|
|
36
|
+
padding = 0;
|
|
37
|
+
backgroundColor = undefined;
|
|
38
|
+
borderRadius = undefined;
|
|
39
|
+
} else if (showCollapsed) {
|
|
40
|
+
padding = {
|
|
41
|
+
vertical: 6,
|
|
42
|
+
horizontal: 12
|
|
43
|
+
};
|
|
44
|
+
backgroundColor = Color.SOFT_LIGHT;
|
|
45
|
+
borderRadius = ShapeRadius.SECTION;
|
|
46
|
+
} else {
|
|
47
|
+
padding = {
|
|
48
|
+
top: 6,
|
|
49
|
+
horizontal: 12,
|
|
50
|
+
bottom: 12
|
|
51
|
+
};
|
|
52
|
+
backgroundColor = Color.SOFT_LIGHT;
|
|
53
|
+
borderRadius = ShapeRadius.SECTION;
|
|
54
|
+
}
|
|
55
|
+
return React.createElement(Vertical, {
|
|
56
|
+
"$padding": padding,
|
|
57
|
+
"$borderRadius": borderRadius,
|
|
58
|
+
"$bgColor": backgroundColor
|
|
59
|
+
}, showCollapsed ? React.createElement(Columns, {
|
|
60
|
+
"$sizes": "max-content 1fr max-content",
|
|
61
|
+
"$gap": 6,
|
|
62
|
+
"$alignItems": "center"
|
|
63
|
+
}, React.createElement(TimeIcon, {
|
|
64
|
+
size: "small",
|
|
65
|
+
view: "lined"
|
|
66
|
+
}), React.createElement(Text, {
|
|
67
|
+
"$variant": "footnote"
|
|
68
|
+
}, getSelectedTimeText(), ' ', timezoneShort), React.createElement(Button, {
|
|
69
|
+
color: "secondary",
|
|
70
|
+
size: "compact",
|
|
71
|
+
view: "ghost",
|
|
72
|
+
onClick: () => setExpanded(true)
|
|
73
|
+
}, "Expand time")) : React.createElement(React.Fragment, null, isRangePicker && React.createElement(Columns, {
|
|
74
|
+
"$sizes": "1fr max-content",
|
|
75
|
+
"$gap": 8,
|
|
76
|
+
"$alignItems": "center"
|
|
77
|
+
}, React.createElement(H5, null, "Time range:"), React.createElement(Button, {
|
|
78
|
+
color: "secondary",
|
|
79
|
+
size: "compact",
|
|
80
|
+
view: "ghost",
|
|
81
|
+
onClick: () => setExpanded(false)
|
|
82
|
+
}, "Collapse time")), !isRangePicker ? React.createElement(Horizontal, {
|
|
83
|
+
"$alignItems": "center",
|
|
84
|
+
"$gap": 8,
|
|
85
|
+
"$justifyContent": "start"
|
|
86
|
+
}, React.createElement(CalendarTimeInput, {
|
|
87
|
+
value: value,
|
|
88
|
+
onChange: time => {
|
|
89
|
+
const newStruct = extendPeriodStruct(value, time);
|
|
90
|
+
onChange(newStruct);
|
|
91
|
+
},
|
|
92
|
+
disabled: isDisabled
|
|
93
|
+
}), React.createElement(CalendarTimezoneSelect, {
|
|
94
|
+
timezone: timezone,
|
|
95
|
+
onChange: onChangeTimezone,
|
|
96
|
+
isDisabled: isDisabled
|
|
97
|
+
})) : React.createElement(Columns, {
|
|
98
|
+
"$sizes": visibleCount === 1 ? '1fr' : 'auto 1fr',
|
|
99
|
+
"$gap": 8
|
|
100
|
+
}, React.createElement(Horizontal, {
|
|
101
|
+
"$alignItems": "center",
|
|
102
|
+
"$gap": 8,
|
|
103
|
+
"$justifyContent": "start"
|
|
104
|
+
}, React.createElement(CalendarTimeInput, {
|
|
105
|
+
value: value[0],
|
|
106
|
+
onChange: time => {
|
|
107
|
+
const oldStruct = value[0];
|
|
108
|
+
const newStruct = extendPeriodStruct(oldStruct, time);
|
|
109
|
+
const newValue = value.length === 2 ? [newStruct, value[1]] : [newStruct];
|
|
110
|
+
onChange(newValue);
|
|
111
|
+
},
|
|
112
|
+
disabled: isDisabled
|
|
113
|
+
}), React.createElement("span", null, "\u2013"), React.createElement(CalendarTimeInput, {
|
|
114
|
+
value: value[1],
|
|
115
|
+
onChange: time => {
|
|
116
|
+
const oldStruct = value[1];
|
|
117
|
+
const newStruct = extendPeriodStruct(oldStruct, time);
|
|
118
|
+
const newValue = value.length === 2 ? [value[0], newStruct] : [newStruct];
|
|
119
|
+
onChange(newValue);
|
|
120
|
+
},
|
|
121
|
+
endPeriod: true,
|
|
122
|
+
disabled: isDisabled
|
|
123
|
+
})), React.createElement(CalendarTimezoneSelect, {
|
|
124
|
+
timezone: timezone,
|
|
125
|
+
onChange: onChangeTimezone,
|
|
126
|
+
isDisabled: isDisabled
|
|
127
|
+
})), isDisabled && React.createElement(Horizontal, {
|
|
128
|
+
"$margin": {
|
|
129
|
+
top: 4
|
|
130
|
+
}
|
|
131
|
+
}, React.createElement(Text, {
|
|
132
|
+
"$variant": "footnote",
|
|
133
|
+
"$color": Color.LOCKED
|
|
134
|
+
}, "Please select", ' ', isRangePicker ? 'date range' : 'date', ' ', "first to set time"))));
|
|
135
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type DateTimeStruct, type RangeValue, type SingleValue } from '../../../types';
|
|
2
|
+
interface BaseProps {
|
|
3
|
+
timezone: string;
|
|
4
|
+
onChangeTimezone: (timezone: string) => void;
|
|
5
|
+
visibleCount?: number;
|
|
6
|
+
}
|
|
7
|
+
export interface CalendarTimeAndTimezoneSectionSingleProps extends BaseProps {
|
|
8
|
+
isRangePicker?: false;
|
|
9
|
+
value?: SingleValue<DateTimeStruct>;
|
|
10
|
+
onChange: (value: SingleValue<DateTimeStruct>) => void;
|
|
11
|
+
}
|
|
12
|
+
export interface CalendarTimeAndTimezoneSectionRangeProps extends BaseProps {
|
|
13
|
+
isRangePicker: true;
|
|
14
|
+
value: RangeValue<DateTimeStruct>;
|
|
15
|
+
onChange: (value: RangeValue<DateTimeStruct>) => void;
|
|
16
|
+
}
|
|
17
|
+
export type CalendarTimeAndTimezoneSectionProps = CalendarTimeAndTimezoneSectionSingleProps | CalendarTimeAndTimezoneSectionRangeProps;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|