@skalfa/skalfa-component 1.0.53 → 1.0.55
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/input/InputDate.component.d.ts +1 -0
- package/dist/input/InputDate.component.js +47 -29
- package/dist/input/InputDatetime.component.js +2 -2
- package/dist/input/InputTime.component.d.ts +5 -3
- package/dist/input/InputTime.component.js +109 -28
- package/dist/input/Select.component.d.ts +7 -2
- package/dist/input/Select.component.js +91 -38
- package/dist/supervision/TableSupervision.component.js +90 -4
- package/package.json +1 -1
- package/src/input/InputDate.component.tsx +95 -55
- package/src/input/InputDatetime.component.tsx +2 -0
- package/src/input/InputTime.component.tsx +218 -58
- package/src/input/Select.component.tsx +111 -53
- package/src/supervision/TableSupervision.component.tsx +102 -10
|
@@ -16,6 +16,7 @@ export interface InputDateProps extends Omit<InputHTMLAttributes<HTMLInputElemen
|
|
|
16
16
|
}
|
|
17
17
|
export declare function InputDateComponent({ label, tip, leftIcon, rightIcon, value, invalid, validations, register, unregister, onChange, className, ...props }: InputDateProps): import("@types/react").JSX.Element;
|
|
18
18
|
export interface InputDatePickerProps {
|
|
19
|
+
value?: string;
|
|
19
20
|
onChange?: (date: string) => void;
|
|
20
21
|
minDate?: string;
|
|
21
22
|
maxDate?: string;
|
|
@@ -27,45 +27,62 @@ function InputDateComponent({ label, tip, leftIcon, rightIcon, value, invalid, v
|
|
|
27
27
|
const [invalidMessage] = (0, _utils_1.useValidation)(inputHandler.value, validations, invalid, inputHandler.idle);
|
|
28
28
|
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "input-container", children: [(0, jsx_runtime_1.jsxs)("label", { htmlFor: randomId, className: (0, _utils_1.cn)("input-label", props.disabled && "input-label-disabled", inputHandler.focus && "input-label-focus", !!invalidMessage && "input-label-error", (0, _utils_1.pcn)(className, "label"), props.disabled && (0, _utils_1.pcn)(className, "label", "disabled"), inputHandler.focus && (0, _utils_1.pcn)(className, "label", "focus"), !!invalidMessage && (0, _utils_1.pcn)(className, "label", "error")), children: [label, validations && _utils_1.validation.hasRules(validations, "required") && (0, jsx_runtime_1.jsx)("span", { className: "text-danger ml-1", children: "*" })] }), tip && ((0, jsx_runtime_1.jsx)("small", { className: (0, _utils_1.cn)("input-tip", props.disabled && "input-tip-disabled", (0, _utils_1.pcn)(className, "tip"), props.disabled && (0, _utils_1.pcn)(className, "tip", "disabled")), children: tip })), (0, jsx_runtime_1.jsx)(OutsideClick_component_1.OutsideClickComponent, { onOutsideClick: !isSm ? () => inputHandler.setFocus(false) : undefined, children: (0, jsx_runtime_1.jsxs)("div", { className: "relative", children: [(0, jsx_runtime_1.jsx)("input", { ...props, id: randomId, className: (0, _utils_1.cn)("input", leftIcon && "input-with-left-icon", rightIcon && "input-with-right-icon", (0, _utils_1.pcn)(className, "input"), !!invalidMessage && "input-error", !!invalidMessage && (0, _utils_1.pcn)(className, "input", "error")), value: inputHandler.value, onChange: (e) => {
|
|
29
29
|
inputHandler.setValue(e.target.value);
|
|
30
|
-
inputHandler.
|
|
30
|
+
inputHandler.setIdle(false);
|
|
31
31
|
onChange?.(e.target.value);
|
|
32
32
|
}, onFocus: (e) => {
|
|
33
33
|
props.onFocus?.(e);
|
|
34
34
|
inputHandler.setFocus(true);
|
|
35
35
|
}, onBlur: (e) => {
|
|
36
36
|
props.onBlur?.(e);
|
|
37
|
-
}, autoComplete: "off", inputMode: isSm ? "none" : undefined }), leftIcon && ((0, jsx_runtime_1.jsx)(skalfa_icon_1.Icon, { className: (0, _utils_1.cn)("input-icon", "input-icon-left", props.disabled && "input-icon-disabled", inputHandler.focus && "input-icon-focus", (0, _utils_1.pcn)(className, "icon"), props.disabled && (0, _utils_1.pcn)(className, "icon", "disabled"), inputHandler.focus && (0, _utils_1.pcn)(className, "icon", "focus")), icon: leftIcon })), rightIcon && ((0, jsx_runtime_1.jsx)(skalfa_icon_1.Icon, { className: (0, _utils_1.cn)("input-icon", "input-icon-right", props.disabled && "input-icon-disabled", inputHandler.focus && "input-icon-focus", (0, _utils_1.pcn)(className, "icon"), props.disabled && (0, _utils_1.pcn)(className, "icon", "disabled"), inputHandler.focus && (0, _utils_1.pcn)(className, "icon", "focus")), icon: rightIcon })), !isSm && inputHandler.focus && ((0, jsx_runtime_1.jsx)("div", { className: "input-date-picker-popover", children: (0, jsx_runtime_1.jsx)(exports.InputDatePickerComponent, { onChange: (e) => {
|
|
37
|
+
}, autoComplete: "off", inputMode: isSm ? "none" : undefined }), leftIcon && ((0, jsx_runtime_1.jsx)(skalfa_icon_1.Icon, { className: (0, _utils_1.cn)("input-icon", "input-icon-left", props.disabled && "input-icon-disabled", inputHandler.focus && "input-icon-focus", (0, _utils_1.pcn)(className, "icon"), props.disabled && (0, _utils_1.pcn)(className, "icon", "disabled"), inputHandler.focus && (0, _utils_1.pcn)(className, "icon", "focus")), icon: leftIcon })), rightIcon && ((0, jsx_runtime_1.jsx)(skalfa_icon_1.Icon, { className: (0, _utils_1.cn)("input-icon", "input-icon-right", props.disabled && "input-icon-disabled", inputHandler.focus && "input-icon-focus", (0, _utils_1.pcn)(className, "icon"), props.disabled && (0, _utils_1.pcn)(className, "icon", "disabled"), inputHandler.focus && (0, _utils_1.pcn)(className, "icon", "focus")), icon: rightIcon })), !isSm && inputHandler.focus && ((0, jsx_runtime_1.jsx)("div", { className: "input-date-picker-popover", children: (0, jsx_runtime_1.jsx)(exports.InputDatePickerComponent, { value: inputHandler.value, onChange: (e) => {
|
|
38
38
|
inputHandler.setValue(e);
|
|
39
|
+
inputHandler.setIdle(false);
|
|
39
40
|
onChange?.(e);
|
|
40
|
-
|
|
41
|
+
inputHandler.setFocus(false);
|
|
42
|
+
} }) }))] }) }), invalidMessage && ((0, jsx_runtime_1.jsx)("small", { className: (0, _utils_1.cn)("input-error-message", (0, _utils_1.pcn)(className, "error")), children: invalidMessage }))] }), isSm && ((0, jsx_runtime_1.jsx)(BottomSheet_component_1.BottomSheetComponent, { show: inputHandler.focus, onClose: () => inputHandler.setFocus(false), size: 380, footer: (0, jsx_runtime_1.jsx)("div", { className: "p-4", children: (0, jsx_runtime_1.jsx)(Button_component_1.ButtonComponent, { label: "Selesai", variant: "outline", onClick: () => inputHandler.setFocus(false), block: true }) }), children: (0, jsx_runtime_1.jsx)("div", { className: "p-4", children: (0, jsx_runtime_1.jsx)(exports.InputDatePickerComponent, { value: inputHandler.value, onChange: (e) => {
|
|
41
43
|
inputHandler.setValue(e);
|
|
44
|
+
inputHandler.setIdle(false);
|
|
42
45
|
onChange?.(e);
|
|
43
46
|
} }) }) }))] }));
|
|
44
47
|
}
|
|
45
48
|
;
|
|
46
|
-
const InputDatePickerComponent = ({ onChange, minDate, maxDate, rightElement, }) => {
|
|
49
|
+
const InputDatePickerComponent = ({ value, onChange, minDate, maxDate, rightElement, }) => {
|
|
47
50
|
const activeYearRef = (0, react_1.useRef)(null);
|
|
48
51
|
const containerYearRef = (0, react_1.useRef)(null);
|
|
49
|
-
const
|
|
50
|
-
|
|
52
|
+
const initialDate = (0, react_1.useMemo)(() => {
|
|
53
|
+
return value && (0, moment_1.default)(value).isValid() ? (0, moment_1.default)(value) : (0, moment_1.default)();
|
|
54
|
+
}, [value]);
|
|
55
|
+
const [currentDate, setCurrentDate] = (0, react_1.useState)(initialDate);
|
|
56
|
+
const [selectedDate, setSelectedDate] = (0, react_1.useState)(initialDate);
|
|
57
|
+
(0, react_1.useEffect)(() => {
|
|
58
|
+
if (value && (0, moment_1.default)(value).isValid()) {
|
|
59
|
+
const m = (0, moment_1.default)(value);
|
|
60
|
+
setCurrentDate(m);
|
|
61
|
+
setSelectedDate(m);
|
|
62
|
+
}
|
|
63
|
+
}, [value]);
|
|
51
64
|
const startDate = (0, moment_1.default)(currentDate).startOf("month").startOf("week");
|
|
52
65
|
const endDate = (0, moment_1.default)(currentDate).endOf("month").endOf("week");
|
|
53
|
-
const handlePrevMonth = () =>
|
|
54
|
-
|
|
66
|
+
const handlePrevMonth = (e) => {
|
|
67
|
+
e?.preventDefault();
|
|
68
|
+
e?.stopPropagation();
|
|
69
|
+
setCurrentDate((0, moment_1.default)(currentDate).subtract(1, "month"));
|
|
70
|
+
};
|
|
71
|
+
const handleNextMonth = (e) => {
|
|
72
|
+
e?.preventDefault();
|
|
73
|
+
e?.stopPropagation();
|
|
74
|
+
setCurrentDate((0, moment_1.default)(currentDate).add(1, "month"));
|
|
75
|
+
};
|
|
55
76
|
const handleDateClick = (date) => {
|
|
56
|
-
if ((minDate && date.isBefore((0, moment_1.default)(minDate))) || (maxDate && date.isAfter((0, moment_1.default)(maxDate)))) {
|
|
77
|
+
if ((minDate && date.isBefore((0, moment_1.default)(minDate), "day")) || (maxDate && date.isAfter((0, moment_1.default)(maxDate), "day"))) {
|
|
57
78
|
return;
|
|
58
79
|
}
|
|
59
80
|
setSelectedDate(date);
|
|
60
81
|
onChange?.(date.format("YYYY-MM-DD"));
|
|
61
82
|
};
|
|
62
83
|
const renderDays = () => {
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
for (let i = 0; i < 7; i++) {
|
|
66
|
-
days.push((0, jsx_runtime_1.jsx)("div", { className: "text-center font-bold", children: startDay.add(i, "days").format("dd") }, i));
|
|
67
|
-
}
|
|
68
|
-
return days;
|
|
84
|
+
const dayNames = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
|
|
85
|
+
return dayNames.map((d, i) => ((0, jsx_runtime_1.jsx)("div", { className: "text-center text-[11px] font-semibold text-light-foreground", children: d }, i)));
|
|
69
86
|
};
|
|
70
87
|
const renderCells = () => {
|
|
71
88
|
const rows = [];
|
|
@@ -74,35 +91,36 @@ const InputDatePickerComponent = ({ onChange, minDate, maxDate, rightElement, })
|
|
|
74
91
|
while (day.isBefore(endDate) || day.isSame(endDate, "day")) {
|
|
75
92
|
for (let i = 0; i < 7; i++) {
|
|
76
93
|
const cloneDay = (0, moment_1.default)(day);
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
94
|
+
const isCurrentMonth = day.isSame(currentDate, "month");
|
|
95
|
+
const isSelected = day.isSame(selectedDate, "day");
|
|
96
|
+
const isToday = day.isSame((0, moment_1.default)(), "day");
|
|
97
|
+
const isDisabled = (minDate && day.isBefore((0, moment_1.default)(minDate), "day")) ||
|
|
98
|
+
(maxDate && day.isAfter((0, moment_1.default)(maxDate), "day"));
|
|
99
|
+
days.push((0, jsx_runtime_1.jsx)("button", { type: "button", className: (0, _utils_1.cn)("w-8 h-8 text-xs flex items-center justify-center text-center rounded-lg transition-all border-none select-none", isCurrentMonth ? "text-foreground font-medium" : "text-light-foreground/40", isSelected ? "bg-primary text-white font-bold hover:bg-primary" : (isToday ? "border border-primary font-semibold hover:bg-light-primary" : "hover:bg-light-primary"), isDisabled ? "opacity-20 cursor-not-allowed pointer-events-none" : "cursor-pointer"), onClick: () => !isDisabled && handleDateClick(cloneDay), children: day.format("D") }, day.format("YYYY-MM-DD")));
|
|
82
100
|
day.add(1, "day");
|
|
83
101
|
}
|
|
84
|
-
rows.push((0, jsx_runtime_1.jsx)("div", { className: "grid grid-cols-7 gap-1", children: days }, day.
|
|
102
|
+
rows.push((0, jsx_runtime_1.jsx)("div", { className: "grid grid-cols-7 gap-1", children: days }, day.format("YYYY-MM-DD-row")));
|
|
85
103
|
days = [];
|
|
86
104
|
}
|
|
87
105
|
return rows;
|
|
88
106
|
};
|
|
89
107
|
const years = (0, react_1.useMemo)(() => {
|
|
90
108
|
const dumpYears = [];
|
|
91
|
-
for (let i =
|
|
109
|
+
for (let i = 1940; i <= (0, moment_1.default)().year() + 10; i++) {
|
|
92
110
|
dumpYears.push(i);
|
|
93
111
|
}
|
|
94
112
|
return dumpYears;
|
|
95
113
|
}, []);
|
|
96
114
|
(0, react_1.useEffect)(() => {
|
|
97
115
|
if (activeYearRef.current && containerYearRef.current) {
|
|
98
|
-
containerYearRef.current
|
|
99
|
-
|
|
100
|
-
|
|
116
|
+
const container = containerYearRef.current;
|
|
117
|
+
const activeEl = activeYearRef.current;
|
|
118
|
+
container.scrollTop = activeEl.offsetTop - container.offsetTop - (container.clientHeight / 2) + (activeEl.clientHeight / 2);
|
|
101
119
|
}
|
|
102
|
-
}, []);
|
|
103
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: "w-full flex gap-2
|
|
120
|
+
}, [currentDate.year()]);
|
|
121
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "w-full flex gap-2.5 h-[260px] select-none", children: [(0, jsx_runtime_1.jsx)("div", { className: "w-[68px] shrink-0 h-full overflow-y-auto input-scroll pr-1 border-r border-stroke", ref: containerYearRef, children: (0, jsx_runtime_1.jsx)("div", { className: "flex flex-col gap-0.5", children: years?.map((item) => {
|
|
104
122
|
const isActive = currentDate?.year() === item;
|
|
105
|
-
return ((0, jsx_runtime_1.jsx)(
|
|
106
|
-
}) }) }), (0, jsx_runtime_1.jsxs)("div", { className: "
|
|
123
|
+
return ((0, jsx_runtime_1.jsx)("div", { ref: isActive ? activeYearRef : null, className: (0, _utils_1.cn)("py-1 px-2 font-semibold rounded-md cursor-pointer transition-colors text-center select-none", isActive ? "bg-primary text-white" : "hover:bg-light-primary text-foreground"), onClick: () => setCurrentDate((0, moment_1.default)(currentDate).set("year", item)), children: item }, item));
|
|
124
|
+
}) }) }), (0, jsx_runtime_1.jsxs)("div", { className: "flex-1 flex flex-col justify-between pl-0.5", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-center mb-1.5", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", onClick: handlePrevMonth, className: "w-7 h-7 flex items-center justify-center text-xs rounded-full hover:bg-light-primary transition-colors cursor-pointer border-none bg-transparent", children: (0, jsx_runtime_1.jsx)(skalfa_icon_1.Icon, { icon: "solid/chevron-left", className: "w-3.5 h-3.5" }) }), (0, jsx_runtime_1.jsx)("h2", { className: "font-semibold", children: currentDate.format("MMMM YYYY") }), (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: handleNextMonth, className: "w-7 h-7 flex items-center justify-center text-xs rounded-full hover:bg-light-primary transition-colors cursor-pointer border-none bg-transparent", children: (0, jsx_runtime_1.jsx)(skalfa_icon_1.Icon, { icon: "solid/chevron-right", className: "w-3.5 h-3.5" }) })] }), (0, jsx_runtime_1.jsx)("div", { className: "grid grid-cols-7 gap-1 mb-1", children: renderDays() }), (0, jsx_runtime_1.jsx)("div", { className: "flex flex-col gap-1", children: renderCells() })] }), rightElement && (0, jsx_runtime_1.jsx)("div", { children: rightElement })] }));
|
|
107
125
|
};
|
|
108
126
|
exports.InputDatePickerComponent = InputDatePickerComponent;
|
|
@@ -55,7 +55,7 @@ function InputDatetimeComponent({ label, tip, leftIcon, rightIcon, value, invali
|
|
|
55
55
|
label: "Jam",
|
|
56
56
|
value: 'time'
|
|
57
57
|
},
|
|
58
|
-
], active: pickerType, onChange: (e) => setPickerType(e), className: "mb-4" }), pickerType === "date" ? ((0, jsx_runtime_1.jsx)(InputDate_component_1.InputDatePickerComponent, { onChange: (e) => {
|
|
58
|
+
], active: pickerType, onChange: (e) => setPickerType(e), className: "mb-4" }), pickerType === "date" ? ((0, jsx_runtime_1.jsx)(InputDate_component_1.InputDatePickerComponent, { value: dateValue, onChange: (e) => {
|
|
59
59
|
setDateValue(e);
|
|
60
60
|
handleChange(e, timeValue);
|
|
61
61
|
} })) : ((0, jsx_runtime_1.jsx)(InputTime_component_1.InputTimePickerComponent, { onChange: (e) => {
|
|
@@ -70,7 +70,7 @@ function InputDatetimeComponent({ label, tip, leftIcon, rightIcon, value, invali
|
|
|
70
70
|
label: "Jam",
|
|
71
71
|
value: 'time'
|
|
72
72
|
},
|
|
73
|
-
], active: pickerType, onChange: (e) => setPickerType(e), className: "mb-4" }), pickerType === "date" ? ((0, jsx_runtime_1.jsx)(InputDate_component_1.InputDatePickerComponent, { onChange: (e) => {
|
|
73
|
+
], active: pickerType, onChange: (e) => setPickerType(e), className: "mb-4" }), pickerType === "date" ? ((0, jsx_runtime_1.jsx)(InputDate_component_1.InputDatePickerComponent, { value: dateValue, onChange: (e) => {
|
|
74
74
|
setDateValue(e);
|
|
75
75
|
handleChange(e, timeValue);
|
|
76
76
|
} })) : ((0, jsx_runtime_1.jsx)(InputTime_component_1.InputTimePickerComponent, { onChange: (e) => {
|
|
@@ -8,16 +8,18 @@ export interface InputTimeProps extends Omit<InputHTMLAttributes<HTMLInputElemen
|
|
|
8
8
|
value?: string;
|
|
9
9
|
invalid?: string;
|
|
10
10
|
validations?: ValidationRules;
|
|
11
|
+
showSeconds?: boolean;
|
|
11
12
|
onChange?: (value: string) => any;
|
|
12
13
|
register?: (name: string, validations?: ValidationRules) => void;
|
|
13
14
|
unregister?: (name: string) => void;
|
|
14
15
|
/** Use custom class with: "label::", "tip::", "error::", "icon::". */
|
|
15
16
|
className?: string;
|
|
16
17
|
}
|
|
17
|
-
export declare function InputTimeComponent({ label, tip, leftIcon, rightIcon, value, invalid, validations, register, unregister, onChange, className, ...props }: InputTimeProps): import("@types/react").JSX.Element;
|
|
18
|
-
interface InputTimePickerProps {
|
|
18
|
+
export declare function InputTimeComponent({ label, tip, leftIcon, rightIcon, value, invalid, validations, showSeconds, register, unregister, onChange, className, ...props }: InputTimeProps): import("@types/react").JSX.Element;
|
|
19
|
+
export interface InputTimePickerProps {
|
|
20
|
+
value?: string;
|
|
21
|
+
showSeconds?: boolean;
|
|
19
22
|
onChange?: (time: string) => void;
|
|
20
23
|
rightElement?: ReactNode;
|
|
21
24
|
}
|
|
22
25
|
export declare const InputTimePickerComponent: FC<InputTimePickerProps>;
|
|
23
|
-
export {};
|
|
@@ -10,7 +10,7 @@ const _utils_1 = require("@utils");
|
|
|
10
10
|
const BottomSheet_component_1 = require("../modal/BottomSheet.component");
|
|
11
11
|
const Button_component_1 = require("../button/Button.component");
|
|
12
12
|
const OutsideClick_component_1 = require("../wrap/OutsideClick.component");
|
|
13
|
-
function InputTimeComponent({ label, tip, leftIcon, rightIcon, value, invalid, validations, register, unregister, onChange, className = "", ...props }) {
|
|
13
|
+
function InputTimeComponent({ label, tip, leftIcon, rightIcon, value, invalid, validations, showSeconds, register, unregister, onChange, className = "", ...props }) {
|
|
14
14
|
const { isSm } = (0, _utils_1.useResponsive)();
|
|
15
15
|
// =========================>
|
|
16
16
|
// ## Initial
|
|
@@ -28,48 +28,129 @@ function InputTimeComponent({ label, tip, leftIcon, rightIcon, value, invalid, v
|
|
|
28
28
|
}, onFocus: (e) => {
|
|
29
29
|
props.onFocus?.(e);
|
|
30
30
|
inputHandler.setFocus(true);
|
|
31
|
-
}, autoComplete: "off", inputMode: isSm ? "none" : undefined }), leftIcon && ((0, jsx_runtime_1.jsx)(skalfa_icon_1.Icon, { className: (0, _utils_1.cn)("input-icon", "input-icon-left", props.disabled && "input-icon-disabled", inputHandler.focus && "input-icon-focus", (0, _utils_1.pcn)(className, "icon")), icon: leftIcon })), rightIcon && ((0, jsx_runtime_1.jsx)(skalfa_icon_1.Icon, { className: (0, _utils_1.cn)("input-icon", "input-icon-right", props.disabled && "input-icon-disabled", inputHandler.focus && "input-icon-focus", (0, _utils_1.pcn)(className, "icon")), icon: rightIcon })), !isSm && inputHandler.focus && ((0, jsx_runtime_1.jsx)("div", { className: "input-time-picker-popover", children: (0, jsx_runtime_1.jsx)(exports.InputTimePickerComponent, { onChange: (time) => {
|
|
31
|
+
}, autoComplete: "off", inputMode: isSm ? "none" : undefined }), leftIcon && ((0, jsx_runtime_1.jsx)(skalfa_icon_1.Icon, { className: (0, _utils_1.cn)("input-icon", "input-icon-left", props.disabled && "input-icon-disabled", inputHandler.focus && "input-icon-focus", (0, _utils_1.pcn)(className, "icon")), icon: leftIcon })), rightIcon && ((0, jsx_runtime_1.jsx)(skalfa_icon_1.Icon, { className: (0, _utils_1.cn)("input-icon", "input-icon-right", props.disabled && "input-icon-disabled", inputHandler.focus && "input-icon-focus", (0, _utils_1.pcn)(className, "icon")), icon: rightIcon })), !isSm && inputHandler.focus && ((0, jsx_runtime_1.jsx)("div", { className: "input-time-picker-popover", children: (0, jsx_runtime_1.jsx)(exports.InputTimePickerComponent, { value: inputHandler.value, showSeconds: showSeconds, onChange: (time) => {
|
|
32
32
|
inputHandler.setValue(time);
|
|
33
|
+
inputHandler.setIdle(false);
|
|
33
34
|
onChange?.(time);
|
|
34
|
-
} }) }))] }) }), invalidMessage && ((0, jsx_runtime_1.jsx)("small", { className: (0, _utils_1.cn)("input-error-message", (0, _utils_1.pcn)(className, "error")), children: invalidMessage }))] }), isSm && ((0, jsx_runtime_1.jsx)(BottomSheet_component_1.BottomSheetComponent, { show: inputHandler.focus, onClose: () => inputHandler.setFocus(false), size: 380, footer: (0, jsx_runtime_1.jsx)("div", { className: "p-4", children: (0, jsx_runtime_1.jsx)(Button_component_1.ButtonComponent, { label: "Selesai", variant: "outline", onClick: () => inputHandler.setFocus(false), block: true }) }), children: (0, jsx_runtime_1.jsx)("div", { className: "p-4", children: (0, jsx_runtime_1.jsx)(exports.InputTimePickerComponent, { onChange: (time) => {
|
|
35
|
+
} }) }))] }) }), invalidMessage && ((0, jsx_runtime_1.jsx)("small", { className: (0, _utils_1.cn)("input-error-message", (0, _utils_1.pcn)(className, "error")), children: invalidMessage }))] }), isSm && ((0, jsx_runtime_1.jsx)(BottomSheet_component_1.BottomSheetComponent, { show: inputHandler.focus, onClose: () => inputHandler.setFocus(false), size: 380, footer: (0, jsx_runtime_1.jsx)("div", { className: "p-4", children: (0, jsx_runtime_1.jsx)(Button_component_1.ButtonComponent, { label: "Selesai", variant: "outline", onClick: () => inputHandler.setFocus(false), block: true }) }), children: (0, jsx_runtime_1.jsx)("div", { className: "p-4", children: (0, jsx_runtime_1.jsx)(exports.InputTimePickerComponent, { value: inputHandler.value, showSeconds: showSeconds, onChange: (time) => {
|
|
35
36
|
inputHandler.setValue(time);
|
|
37
|
+
inputHandler.setIdle(false);
|
|
36
38
|
onChange?.(time);
|
|
37
39
|
} }) }) }))] }));
|
|
38
40
|
}
|
|
39
41
|
;
|
|
40
|
-
const InputTimePickerComponent = ({ onChange, rightElement, }) => {
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
const InputTimePickerComponent = ({ value, showSeconds = false, onChange, rightElement, }) => {
|
|
43
|
+
const parsed = (0, react_1.useMemo)(() => {
|
|
44
|
+
if (!value || typeof value !== "string") {
|
|
45
|
+
return { h: 0, m: 0, s: 0, hasValue: false };
|
|
46
|
+
}
|
|
47
|
+
const parts = value.split(":").map((p) => parseInt(p, 10));
|
|
48
|
+
return {
|
|
49
|
+
h: isNaN(parts[0]) ? 0 : Math.min(23, Math.max(0, parts[0])),
|
|
50
|
+
m: isNaN(parts[1]) ? 0 : Math.min(59, Math.max(0, parts[1])),
|
|
51
|
+
s: isNaN(parts[2]) ? 0 : Math.min(59, Math.max(0, parts[2])),
|
|
52
|
+
hasValue: true,
|
|
53
|
+
};
|
|
54
|
+
}, [value]);
|
|
55
|
+
const [hour, setHour] = (0, react_1.useState)(parsed.h);
|
|
56
|
+
const [minute, setMinute] = (0, react_1.useState)(parsed.m);
|
|
57
|
+
const [second, setSecond] = (0, react_1.useState)(parsed.s);
|
|
58
|
+
const shouldShowSeconds = showSeconds || (typeof value === "string" && value.split(":").length >= 3 && value.split(":")[2] !== "");
|
|
59
|
+
(0, react_1.useEffect)(() => {
|
|
60
|
+
if (parsed.hasValue) {
|
|
61
|
+
setHour(parsed.h);
|
|
62
|
+
setMinute(parsed.m);
|
|
63
|
+
setSecond(parsed.s);
|
|
64
|
+
}
|
|
65
|
+
}, [parsed]);
|
|
44
66
|
const hours = Array.from({ length: 24 }, (_, i) => String(i).padStart(2, "0"));
|
|
45
67
|
const minutes = Array.from({ length: 60 }, (_, i) => String(i).padStart(2, "0"));
|
|
46
68
|
const seconds = Array.from({ length: 60 }, (_, i) => String(i).padStart(2, "0"));
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
69
|
+
const presetContainerRef = (0, react_1.useRef)(null);
|
|
70
|
+
const activePresetRef = (0, react_1.useRef)(null);
|
|
71
|
+
const hourContainerRef = (0, react_1.useRef)(null);
|
|
72
|
+
const activeHourRef = (0, react_1.useRef)(null);
|
|
73
|
+
const minuteContainerRef = (0, react_1.useRef)(null);
|
|
74
|
+
const activeMinuteRef = (0, react_1.useRef)(null);
|
|
75
|
+
const secondContainerRef = (0, react_1.useRef)(null);
|
|
76
|
+
const activeSecondRef = (0, react_1.useRef)(null);
|
|
77
|
+
const scrollToActive = (container, active) => {
|
|
78
|
+
if (container && active) {
|
|
79
|
+
container.scrollTop = active.offsetTop - container.offsetTop - (container.clientHeight / 2) + (active.clientHeight / 2);
|
|
80
|
+
}
|
|
54
81
|
};
|
|
55
82
|
(0, react_1.useEffect)(() => {
|
|
56
|
-
|
|
83
|
+
scrollToActive(hourContainerRef.current, activeHourRef.current);
|
|
84
|
+
scrollToActive(minuteContainerRef.current, activeMinuteRef.current);
|
|
85
|
+
if (shouldShowSeconds) {
|
|
86
|
+
scrollToActive(secondContainerRef.current, activeSecondRef.current);
|
|
87
|
+
}
|
|
88
|
+
scrollToActive(presetContainerRef.current, activePresetRef.current);
|
|
89
|
+
}, []);
|
|
90
|
+
const emitChange = (newH, newM, newS) => {
|
|
91
|
+
const hh = String(newH).padStart(2, "0");
|
|
92
|
+
const mm = String(newM).padStart(2, "0");
|
|
93
|
+
const ss = String(newS).padStart(2, "0");
|
|
94
|
+
const formatted = shouldShowSeconds ? `${hh}:${mm}:${ss}` : `${hh}:${mm}`;
|
|
57
95
|
onChange?.(formatted);
|
|
58
|
-
}
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
96
|
+
};
|
|
97
|
+
const handleSelect = (type, val) => {
|
|
98
|
+
let newH = hour;
|
|
99
|
+
let newM = minute;
|
|
100
|
+
let newS = second;
|
|
101
|
+
if (type === "h") {
|
|
102
|
+
newH = val;
|
|
103
|
+
setHour(val);
|
|
104
|
+
}
|
|
105
|
+
else if (type === "m") {
|
|
106
|
+
newM = val;
|
|
107
|
+
setMinute(val);
|
|
108
|
+
}
|
|
109
|
+
else if (type === "s") {
|
|
110
|
+
newS = val;
|
|
111
|
+
setSecond(val);
|
|
112
|
+
}
|
|
113
|
+
emitChange(newH, newM, newS);
|
|
114
|
+
};
|
|
115
|
+
const handlePresetSelect = (presetStr) => {
|
|
116
|
+
const parts = presetStr.split(":").map(Number);
|
|
117
|
+
const newH = parts[0] ?? 0;
|
|
118
|
+
const newM = parts[1] ?? 0;
|
|
119
|
+
const newS = 0;
|
|
120
|
+
setHour(newH);
|
|
121
|
+
setMinute(newM);
|
|
122
|
+
setSecond(newS);
|
|
123
|
+
emitChange(newH, newM, newS);
|
|
124
|
+
};
|
|
63
125
|
const timeSlots = (0, react_1.useMemo)(() => {
|
|
64
|
-
const
|
|
65
|
-
for (let i = 0; i
|
|
66
|
-
const
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
newTimeSlots.push(label);
|
|
126
|
+
const slots = [];
|
|
127
|
+
for (let i = 0; i < 24 * 60; i += 30) {
|
|
128
|
+
const h = Math.floor(i / 60);
|
|
129
|
+
const m = i % 60;
|
|
130
|
+
slots.push(`${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}`);
|
|
70
131
|
}
|
|
71
|
-
return
|
|
132
|
+
return slots;
|
|
72
133
|
}, []);
|
|
73
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: "w-full
|
|
134
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "w-full flex gap-2 h-[260px] select-none text-xs", children: [(0, jsx_runtime_1.jsxs)("div", { className: "w-20 shrink-0 h-full flex flex-col border-r border-stroke pr-1.5", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-[11px] font-semibold text-light-foreground text-center py-1 mb-1 border-b border-stroke", children: "Preset" }), (0, jsx_runtime_1.jsx)("div", { className: "flex-1 overflow-y-auto input-scroll flex flex-col gap-0.5", ref: presetContainerRef, children: timeSlots.map((time) => {
|
|
135
|
+
const isPresetActive = `${String(hour).padStart(2, "0")}:${String(minute).padStart(2, "0")}` === time;
|
|
136
|
+
return ((0, jsx_runtime_1.jsx)("div", { ref: isPresetActive ? activePresetRef : null, className: (0, _utils_1.cn)("py-1.5 px-1 text-center font-medium rounded-md cursor-pointer transition-colors", isPresetActive
|
|
137
|
+
? "bg-primary text-white font-semibold"
|
|
138
|
+
: "hover:bg-light-primary text-foreground"), onClick: () => handlePresetSelect(time), children: time }, time));
|
|
139
|
+
}) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex-1 h-full flex flex-col", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-[11px] font-semibold text-light-foreground text-center py-1 mb-1 border-b border-stroke", children: "Jam" }), (0, jsx_runtime_1.jsx)("div", { className: "flex-1 overflow-y-auto input-scroll flex flex-col gap-0.5", ref: hourContainerRef, children: hours.map((item) => {
|
|
140
|
+
const active = Number(item) === hour;
|
|
141
|
+
return ((0, jsx_runtime_1.jsx)("div", { ref: active ? activeHourRef : null, onClick: () => handleSelect("h", Number(item)), className: (0, _utils_1.cn)("py-1.5 text-center font-medium rounded-md cursor-pointer transition-colors", active
|
|
142
|
+
? "bg-primary text-white font-semibold"
|
|
143
|
+
: "hover:bg-light-primary text-foreground"), children: item }, item));
|
|
144
|
+
}) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex-1 h-full flex flex-col", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-[11px] font-semibold text-light-foreground text-center py-1 mb-1 border-b border-stroke", children: "Menit" }), (0, jsx_runtime_1.jsx)("div", { className: "flex-1 overflow-y-auto input-scroll flex flex-col gap-0.5", ref: minuteContainerRef, children: minutes.map((item) => {
|
|
145
|
+
const active = Number(item) === minute;
|
|
146
|
+
return ((0, jsx_runtime_1.jsx)("div", { ref: active ? activeMinuteRef : null, onClick: () => handleSelect("m", Number(item)), className: (0, _utils_1.cn)("py-1.5 text-center font-medium rounded-md cursor-pointer transition-colors", active
|
|
147
|
+
? "bg-primary text-white font-semibold"
|
|
148
|
+
: "hover:bg-light-primary text-foreground"), children: item }, item));
|
|
149
|
+
}) })] }), shouldShowSeconds && ((0, jsx_runtime_1.jsxs)("div", { className: "flex-1 h-full flex flex-col", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-[11px] font-semibold text-light-foreground text-center py-1 mb-1 border-b border-stroke", children: "Detik" }), (0, jsx_runtime_1.jsx)("div", { className: "flex-1 overflow-y-auto input-scroll flex flex-col gap-0.5", ref: secondContainerRef, children: seconds.map((item) => {
|
|
150
|
+
const active = Number(item) === second;
|
|
151
|
+
return ((0, jsx_runtime_1.jsx)("div", { ref: active ? activeSecondRef : null, onClick: () => handleSelect("s", Number(item)), className: (0, _utils_1.cn)("py-1.5 text-center font-medium rounded-md cursor-pointer transition-colors", active
|
|
152
|
+
? "bg-primary text-white font-semibold"
|
|
153
|
+
: "hover:bg-light-primary text-foreground"), children: item }, item));
|
|
154
|
+
}) })] })), rightElement && (0, jsx_runtime_1.jsx)("div", { children: rightElement })] }));
|
|
74
155
|
};
|
|
75
156
|
exports.InputTimePickerComponent = InputTimePickerComponent;
|
|
@@ -5,6 +5,8 @@ export interface SelectOptionProps {
|
|
|
5
5
|
value: string | number;
|
|
6
6
|
searchable?: string[];
|
|
7
7
|
customLabel?: ReactNode;
|
|
8
|
+
customOption?: ((option: any) => ReactNode) | ReactNode;
|
|
9
|
+
[key: string]: any;
|
|
8
10
|
}
|
|
9
11
|
export interface SelectProps {
|
|
10
12
|
name: string;
|
|
@@ -23,7 +25,8 @@ export interface SelectProps {
|
|
|
23
25
|
options?: SelectOptionProps[];
|
|
24
26
|
searchable?: boolean;
|
|
25
27
|
serverOptionControl?: ApiType & {
|
|
26
|
-
cacheName?: string |
|
|
28
|
+
cacheName?: string | boolean;
|
|
29
|
+
selectableOption?: string[];
|
|
27
30
|
};
|
|
28
31
|
idbOptionControl?: {
|
|
29
32
|
store: string;
|
|
@@ -38,6 +41,8 @@ export interface SelectProps {
|
|
|
38
41
|
maxShowOption?: number;
|
|
39
42
|
creatable?: boolean | string;
|
|
40
43
|
creatableLabel?: string;
|
|
44
|
+
customOption?: (option: any) => ReactNode;
|
|
45
|
+
selectableOption?: string[];
|
|
41
46
|
onChange?: (value: any, data?: any) => any;
|
|
42
47
|
register?: (name: string, validations?: ValidationRules) => void;
|
|
43
48
|
unregister?: (name: string) => void;
|
|
@@ -46,4 +51,4 @@ export interface SelectProps {
|
|
|
46
51
|
/** Use custom class with: "label::", "tip::", "error::", "icon::", "suggest::", "suggest-item::". */
|
|
47
52
|
className?: string;
|
|
48
53
|
}
|
|
49
|
-
export declare function SelectComponent({ name, label, placeholder, tip, leftIcon, rightIcon, value, invalid, disabled, validations, multiple, autoFocus, clearable, options, searchable, serverOptionControl, idbOptionControl, serverSearchable, includedOptions, exceptOptions, tempOptions, newOption, maxShowOption, creatable, creatableLabel, register, unregister, onChange, onFocus, onBlur, className, }: SelectProps): import("@types/react").JSX.Element;
|
|
54
|
+
export declare function SelectComponent({ name, label, placeholder, tip, leftIcon, rightIcon, value, invalid, disabled, validations, multiple, autoFocus, clearable, options, searchable, serverOptionControl, idbOptionControl, serverSearchable, includedOptions, exceptOptions, tempOptions, newOption, maxShowOption, creatable, creatableLabel, customOption, selectableOption, register, unregister, onChange, onFocus, onBlur, className, }: SelectProps): import("@types/react").JSX.Element;
|