sellmate-design-system-react 0.3.0 → 0.4.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/README.md +84 -21
- package/dist/components/STable/STable.cjs +1 -1
- package/dist/components/STable/STable.cjs.map +1 -1
- package/dist/components/STable/STable.js +1 -1
- package/dist/components/STable/STable.js.map +1 -1
- package/dist/components/STimePicker/STimePicker.cjs +3834 -0
- package/dist/components/STimePicker/STimePicker.cjs.map +1 -0
- package/dist/components/STimePicker/STimePicker.d.ts +50 -0
- package/dist/components/STimePicker/STimePicker.js +3811 -0
- package/dist/components/STimePicker/STimePicker.js.map +1 -0
- package/dist/components/STimePicker/index.d.ts +2 -0
- package/dist/components/STimePicker/timepicker.config.d.ts +23 -0
- package/dist/components/STimeRangePicker/STimeRangePicker.cjs +3908 -0
- package/dist/components/STimeRangePicker/STimeRangePicker.cjs.map +1 -0
- package/dist/components/STimeRangePicker/STimeRangePicker.d.ts +53 -0
- package/dist/components/STimeRangePicker/STimeRangePicker.js +3885 -0
- package/dist/components/STimeRangePicker/STimeRangePicker.js.map +1 -0
- package/dist/components/STimeRangePicker/index.d.ts +1 -0
- package/dist/components/STimeRangePicker/time-range-picker.config.d.ts +9 -0
- package/dist/index.cjs +854 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +851 -3
- package/dist/index.js.map +1 -1
- package/dist/styles.css +132 -69
- package/dist/theme.css +81 -69
- package/package.json +4 -1
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { clsx } from 'clsx';
|
|
2
3
|
import { extendTailwindMerge } from 'tailwind-merge';
|
|
3
4
|
import { forwardRef, useState, useEffect, useRef, useCallback, createContext, useImperativeHandle, useMemo, useContext, useId, useLayoutEffect, useSyncExternalStore, Fragment as Fragment$1 } from 'react';
|
|
@@ -12,7 +13,6 @@ import * as RDialog from '@radix-ui/react-dialog';
|
|
|
12
13
|
import * as RCheckbox from '@radix-ui/react-checkbox';
|
|
13
14
|
import * as Ariakit from '@ariakit/react';
|
|
14
15
|
|
|
15
|
-
// src/lib/cn.ts
|
|
16
16
|
var twMerge = extendTailwindMerge({
|
|
17
17
|
extend: {
|
|
18
18
|
classGroups: {
|
|
@@ -6632,7 +6632,7 @@ var STable = forwardRef(function STable2({
|
|
|
6632
6632
|
ref: scrollRef,
|
|
6633
6633
|
onScroll: handleScroll,
|
|
6634
6634
|
className: cn(
|
|
6635
|
-
"relative overflow-auto border border-solid border-[color:var(--cmp-table-border-color)]",
|
|
6635
|
+
"bg-white relative overflow-auto border border-solid border-[color:var(--cmp-table-border-color)]",
|
|
6636
6636
|
radiusClass,
|
|
6637
6637
|
// 원본 sd-table__scroll-container--loading/--no-data: 로딩·데이터 없음 시 스크롤·인터랙션 차단
|
|
6638
6638
|
(isLoading || rowCount === 0) && "overflow-hidden pointer-events-none"
|
|
@@ -9806,6 +9806,854 @@ var SBarcodeInput = forwardRef(
|
|
|
9806
9806
|
}
|
|
9807
9807
|
);
|
|
9808
9808
|
|
|
9809
|
-
|
|
9809
|
+
// src/components/STimePicker/timepicker.config.ts
|
|
9810
|
+
var V2 = (path) => `var(--cmp-timepicker-${path})`;
|
|
9811
|
+
var TIMEPICKER_SIZES = ["sm", "md"];
|
|
9812
|
+
var TIMEPICKER_SIZE_CONFIG = {
|
|
9813
|
+
sm: {
|
|
9814
|
+
height: V2("sm-height"),
|
|
9815
|
+
paddingX: V2("sm-paddingX"),
|
|
9816
|
+
gap: V2("sm-gap"),
|
|
9817
|
+
icon: V2("sm-icon"),
|
|
9818
|
+
radius: V2("sm-radius"),
|
|
9819
|
+
// TODO: component.timepicker 토큰에 typography가 추가되면 CSS 변수로 교체한다.
|
|
9820
|
+
fontSize: 12,
|
|
9821
|
+
lineHeight: 20,
|
|
9822
|
+
minWidth: 80,
|
|
9823
|
+
fieldMinWidth: 128
|
|
9824
|
+
},
|
|
9825
|
+
md: {
|
|
9826
|
+
height: V2("md-height"),
|
|
9827
|
+
paddingX: V2("md-paddingX"),
|
|
9828
|
+
gap: V2("md-gap"),
|
|
9829
|
+
icon: V2("md-icon"),
|
|
9830
|
+
radius: V2("md-radius"),
|
|
9831
|
+
// TODO: component.timepicker 토큰에 typography가 추가되면 CSS 변수로 교체한다.
|
|
9832
|
+
fontSize: 14,
|
|
9833
|
+
lineHeight: 24,
|
|
9834
|
+
minWidth: 96,
|
|
9835
|
+
fieldMinWidth: 160
|
|
9836
|
+
}
|
|
9837
|
+
};
|
|
9838
|
+
function clampTimePart(value, min, max) {
|
|
9839
|
+
if (!Number.isFinite(value)) return min;
|
|
9840
|
+
return Math.min(Math.max(value, min), max);
|
|
9841
|
+
}
|
|
9842
|
+
function padTimePart(value) {
|
|
9843
|
+
return String(value).padStart(2, "0");
|
|
9844
|
+
}
|
|
9845
|
+
function parseTimeValue(value) {
|
|
9846
|
+
const match = /^(\d{1,2}):(\d{1,2})$/.exec(value ?? "");
|
|
9847
|
+
if (!match) return { hour: 0, minute: 0 };
|
|
9848
|
+
return {
|
|
9849
|
+
hour: clampTimePart(Number(match[1]), 0, 23),
|
|
9850
|
+
minute: clampTimePart(Number(match[2]), 0, 59)
|
|
9851
|
+
};
|
|
9852
|
+
}
|
|
9853
|
+
function formatTimeValue(hour, minute) {
|
|
9854
|
+
return `${padTimePart(clampTimePart(hour, 0, 23))}:${padTimePart(clampTimePart(minute, 0, 59))}`;
|
|
9855
|
+
}
|
|
9856
|
+
function formatTimeDisplay(value, type) {
|
|
9857
|
+
if (value == null || value === "") return "";
|
|
9858
|
+
const { hour, minute } = parseTimeValue(value);
|
|
9859
|
+
if (type === "default") return formatTimeValue(hour, minute);
|
|
9860
|
+
const meridiem = hour >= 12 ? "\uC624\uD6C4" : "\uC624\uC804";
|
|
9861
|
+
const displayHour = hour % 12 === 0 ? 12 : hour % 12;
|
|
9862
|
+
return `${meridiem} ${padTimePart(displayHour)}:${padTimePart(minute)}`;
|
|
9863
|
+
}
|
|
9864
|
+
function TimeSelector({
|
|
9865
|
+
value,
|
|
9866
|
+
useMeridiem,
|
|
9867
|
+
minuteStep,
|
|
9868
|
+
onChange
|
|
9869
|
+
}) {
|
|
9870
|
+
const parsed = useMemo(() => parseTimeValue(value), [value]);
|
|
9871
|
+
const [hour, setHour] = useState(parsed.hour);
|
|
9872
|
+
const [minute, setMinute] = useState(parsed.minute);
|
|
9873
|
+
const [editingPart, setEditingPart] = useState(null);
|
|
9874
|
+
const [inputDraft, setInputDraft] = useState({});
|
|
9875
|
+
useEffect(() => {
|
|
9876
|
+
setHour(parsed.hour);
|
|
9877
|
+
setMinute(parsed.minute);
|
|
9878
|
+
}, [parsed.hour, parsed.minute]);
|
|
9879
|
+
const meridiem = hour >= 12 ? "PM" : "AM";
|
|
9880
|
+
const displayHour = useMeridiem ? hour % 12 === 0 ? 12 : hour % 12 : hour;
|
|
9881
|
+
const commit = (nextHour, nextMinute) => {
|
|
9882
|
+
const h = clampTimePart(nextHour, 0, 23);
|
|
9883
|
+
const m = clampTimePart(nextMinute, 0, 59);
|
|
9884
|
+
setHour(h);
|
|
9885
|
+
setMinute(m);
|
|
9886
|
+
onChange(formatTimeValue(h, m));
|
|
9887
|
+
};
|
|
9888
|
+
const setMeridiem = (next) => {
|
|
9889
|
+
if (next === meridiem) return;
|
|
9890
|
+
commit(next === "AM" ? hour - 12 : hour + 12, minute);
|
|
9891
|
+
};
|
|
9892
|
+
const changeMinute = (delta) => {
|
|
9893
|
+
const next = minute + delta;
|
|
9894
|
+
if (next > 59) {
|
|
9895
|
+
commit((hour + 1) % 24, next - 60);
|
|
9896
|
+
return;
|
|
9897
|
+
}
|
|
9898
|
+
if (next < 0) {
|
|
9899
|
+
commit((hour + 23) % 24, next + 60);
|
|
9900
|
+
return;
|
|
9901
|
+
}
|
|
9902
|
+
commit(hour, next);
|
|
9903
|
+
};
|
|
9904
|
+
const changeHour = (delta) => commit((hour + delta + 24) % 24, minute);
|
|
9905
|
+
const sanitizeInput = (next) => next.replace(/\D/g, "").slice(0, 2);
|
|
9906
|
+
const beginEdit = (part, currentValue) => {
|
|
9907
|
+
setEditingPart(part);
|
|
9908
|
+
setInputDraft((prev) => ({ ...prev, [part]: String(currentValue).padStart(2, "0") }));
|
|
9909
|
+
};
|
|
9910
|
+
const commitHourDraft = (draft) => {
|
|
9911
|
+
const clamped = clampTimePart(Number(draft), useMeridiem ? 1 : 0, useMeridiem ? 12 : 23);
|
|
9912
|
+
const nextHour = useMeridiem ? meridiem === "PM" ? clamped === 12 ? 12 : clamped + 12 : clamped === 12 ? 0 : clamped : clamped;
|
|
9913
|
+
commit(nextHour, minute);
|
|
9914
|
+
return clamped;
|
|
9915
|
+
};
|
|
9916
|
+
const commitMinuteDraft = (draft) => {
|
|
9917
|
+
const clamped = clampTimePart(Number(draft), 0, 59);
|
|
9918
|
+
commit(hour, clamped);
|
|
9919
|
+
return clamped;
|
|
9920
|
+
};
|
|
9921
|
+
const endEdit = (part) => {
|
|
9922
|
+
const draft = inputDraft[part];
|
|
9923
|
+
if (part === "hour" && draft != null && draft !== "") {
|
|
9924
|
+
commitHourDraft(draft);
|
|
9925
|
+
}
|
|
9926
|
+
if (part === "minute" && draft != null && draft !== "") {
|
|
9927
|
+
commitMinuteDraft(draft);
|
|
9928
|
+
}
|
|
9929
|
+
setEditingPart(null);
|
|
9930
|
+
setInputDraft({});
|
|
9931
|
+
};
|
|
9932
|
+
const inputStyle = {
|
|
9933
|
+
width: "var(--cmp-timepicker-selector-input-width)",
|
|
9934
|
+
height: "var(--cmp-textinput-sm-height)",
|
|
9935
|
+
borderRadius: "var(--cmp-textinput-sm-radius)",
|
|
9936
|
+
border: "var(--cmp-textinput-borderWidth) solid var(--cmp-textinput-border-default)",
|
|
9937
|
+
color: "var(--cmp-textinput-text-default)",
|
|
9938
|
+
fontSize: 12,
|
|
9939
|
+
lineHeight: "20px"
|
|
9940
|
+
};
|
|
9941
|
+
const renderColumn = (type) => {
|
|
9942
|
+
const isHour = type === "hour";
|
|
9943
|
+
const val = isHour ? displayHour : minute;
|
|
9944
|
+
const displayValue = editingPart === type ? inputDraft[type] ?? "" : String(val).padStart(2, "0");
|
|
9945
|
+
return /* @__PURE__ */ jsxs(
|
|
9946
|
+
"div",
|
|
9947
|
+
{
|
|
9948
|
+
className: "flex flex-col items-center justify-center",
|
|
9949
|
+
style: { gap: "var(--cmp-timepicker-selector-time-column-gap)" },
|
|
9950
|
+
children: [
|
|
9951
|
+
/* @__PURE__ */ jsx(
|
|
9952
|
+
SGhostButton,
|
|
9953
|
+
{
|
|
9954
|
+
icon: "chevronUp",
|
|
9955
|
+
size: "xs",
|
|
9956
|
+
ariaLabel: `${isHour ? "\uC2DC" : "\uBD84"} \uC99D\uAC00`,
|
|
9957
|
+
onClick: () => isHour ? changeHour(1) : changeMinute(minuteStep)
|
|
9958
|
+
}
|
|
9959
|
+
),
|
|
9960
|
+
/* @__PURE__ */ jsx(
|
|
9961
|
+
"input",
|
|
9962
|
+
{
|
|
9963
|
+
"aria-label": isHour ? "\uC2DC" : "\uBD84",
|
|
9964
|
+
inputMode: "numeric",
|
|
9965
|
+
value: displayValue,
|
|
9966
|
+
placeholder: "-",
|
|
9967
|
+
onFocus: () => beginEdit(type, val),
|
|
9968
|
+
onBlur: () => endEdit(type),
|
|
9969
|
+
onChange: (event) => {
|
|
9970
|
+
const draft = sanitizeInput(event.target.value);
|
|
9971
|
+
setInputDraft((prev) => ({ ...prev, [type]: draft }));
|
|
9972
|
+
if (draft === "") return;
|
|
9973
|
+
const raw = Number(draft);
|
|
9974
|
+
if (isHour) {
|
|
9975
|
+
if (draft.length < 2) return;
|
|
9976
|
+
const clamped2 = commitHourDraft(draft);
|
|
9977
|
+
const displayDraft2 = raw === clamped2 ? draft : String(clamped2);
|
|
9978
|
+
setInputDraft((prev) => ({ ...prev, [type]: displayDraft2 }));
|
|
9979
|
+
return;
|
|
9980
|
+
}
|
|
9981
|
+
if (draft.length < 2) return;
|
|
9982
|
+
const clamped = commitMinuteDraft(draft);
|
|
9983
|
+
const displayDraft = raw === clamped ? draft : String(clamped);
|
|
9984
|
+
setInputDraft((prev) => ({ ...prev, [type]: displayDraft }));
|
|
9985
|
+
},
|
|
9986
|
+
className: "box-border bg-white text-center outline-none",
|
|
9987
|
+
style: inputStyle
|
|
9988
|
+
}
|
|
9989
|
+
),
|
|
9990
|
+
/* @__PURE__ */ jsx(
|
|
9991
|
+
SGhostButton,
|
|
9992
|
+
{
|
|
9993
|
+
icon: "chevronDown",
|
|
9994
|
+
size: "xs",
|
|
9995
|
+
ariaLabel: `${isHour ? "\uC2DC" : "\uBD84"} \uAC10\uC18C`,
|
|
9996
|
+
onClick: () => isHour ? changeHour(-1) : changeMinute(-minuteStep)
|
|
9997
|
+
}
|
|
9998
|
+
)
|
|
9999
|
+
]
|
|
10000
|
+
}
|
|
10001
|
+
);
|
|
10002
|
+
};
|
|
10003
|
+
return /* @__PURE__ */ jsxs(
|
|
10004
|
+
"div",
|
|
10005
|
+
{
|
|
10006
|
+
className: "flex flex-col items-stretch justify-center overflow-hidden",
|
|
10007
|
+
style: {
|
|
10008
|
+
background: "var(--cmp-timepicker-selector-bg)",
|
|
10009
|
+
borderRadius: "var(--cmp-timepicker-selector-radius)",
|
|
10010
|
+
boxShadow: "4px 8px 16px -4px rgba(34,34,34,0.1), 0 0 24px -6px rgba(34,34,34,0.12)"
|
|
10011
|
+
},
|
|
10012
|
+
children: [
|
|
10013
|
+
useMeridiem && /* @__PURE__ */ jsx(
|
|
10014
|
+
"div",
|
|
10015
|
+
{
|
|
10016
|
+
className: "flex items-center justify-center",
|
|
10017
|
+
style: {
|
|
10018
|
+
padding: "var(--cmp-timepicker-selector-section-paddingY) var(--cmp-timepicker-selector-section-paddingX)"
|
|
10019
|
+
},
|
|
10020
|
+
children: /* @__PURE__ */ jsx("div", { className: "isolate flex", children: ["AM", "PM"].map((item, index) => {
|
|
10021
|
+
const selected = item === meridiem;
|
|
10022
|
+
return /* @__PURE__ */ jsx(
|
|
10023
|
+
"button",
|
|
10024
|
+
{
|
|
10025
|
+
type: "button",
|
|
10026
|
+
onClick: () => setMeridiem(item),
|
|
10027
|
+
className: cn(
|
|
10028
|
+
"box-border h-[var(--cmp-textinput-sm-height)] w-[61px] cursor-pointer border border-solid bg-white text-center text-[12px] font-medium leading-[20px]",
|
|
10029
|
+
index === 0 ? "rounded-l-[var(--cmp-select-sm-radius)]" : "rounded-r-[var(--cmp-select-sm-radius)]",
|
|
10030
|
+
index === 0 ? "-mr-px" : "",
|
|
10031
|
+
selected ? "z-[1] border-[var(--cmp-timepicker-border-focus)] text-[var(--cmp-timepicker-border-focus)]" : "border-[var(--cmp-timepicker-border-default)] text-[var(--cmp-field-hint-color)]"
|
|
10032
|
+
),
|
|
10033
|
+
children: item === "AM" ? "\uC624\uC804" : "\uC624\uD6C4"
|
|
10034
|
+
},
|
|
10035
|
+
item
|
|
10036
|
+
);
|
|
10037
|
+
}) })
|
|
10038
|
+
}
|
|
10039
|
+
),
|
|
10040
|
+
useMeridiem && /* @__PURE__ */ jsx("div", { className: "h-px w-full bg-[var(--sys-color-divider-default)]" }),
|
|
10041
|
+
/* @__PURE__ */ jsxs(
|
|
10042
|
+
"div",
|
|
10043
|
+
{
|
|
10044
|
+
className: "flex items-center justify-center",
|
|
10045
|
+
style: {
|
|
10046
|
+
gap: "var(--cmp-timepicker-selector-time-gap)",
|
|
10047
|
+
padding: "var(--cmp-timepicker-selector-section-paddingY) var(--cmp-timepicker-selector-section-paddingX)"
|
|
10048
|
+
},
|
|
10049
|
+
children: [
|
|
10050
|
+
renderColumn("hour"),
|
|
10051
|
+
/* @__PURE__ */ jsx(
|
|
10052
|
+
"span",
|
|
10053
|
+
{
|
|
10054
|
+
className: "text-center",
|
|
10055
|
+
style: {
|
|
10056
|
+
width: "var(--cmp-timepicker-selector-colon-size)",
|
|
10057
|
+
color: "var(--cmp-field-hint-color)",
|
|
10058
|
+
fontSize: "var(--cmp-timepicker-selector-colon-size)",
|
|
10059
|
+
lineHeight: "var(--cmp-timepicker-selector-colon-size)"
|
|
10060
|
+
},
|
|
10061
|
+
children: ":"
|
|
10062
|
+
}
|
|
10063
|
+
),
|
|
10064
|
+
renderColumn("minute")
|
|
10065
|
+
]
|
|
10066
|
+
}
|
|
10067
|
+
)
|
|
10068
|
+
]
|
|
10069
|
+
}
|
|
10070
|
+
);
|
|
10071
|
+
}
|
|
10072
|
+
function STimePicker({
|
|
10073
|
+
value,
|
|
10074
|
+
onValueChange,
|
|
10075
|
+
onOpenChange,
|
|
10076
|
+
type = "default",
|
|
10077
|
+
size = "sm",
|
|
10078
|
+
placeholder = "00:00",
|
|
10079
|
+
disabled = false,
|
|
10080
|
+
clearable = false,
|
|
10081
|
+
useMeridiem,
|
|
10082
|
+
minuteStep = 1,
|
|
10083
|
+
width,
|
|
10084
|
+
name,
|
|
10085
|
+
rules,
|
|
10086
|
+
status,
|
|
10087
|
+
label,
|
|
10088
|
+
labelWidth,
|
|
10089
|
+
icon,
|
|
10090
|
+
iconColor,
|
|
10091
|
+
labelTooltip,
|
|
10092
|
+
labelTooltipProps,
|
|
10093
|
+
addonLabel,
|
|
10094
|
+
addonAlign,
|
|
10095
|
+
hint,
|
|
10096
|
+
error,
|
|
10097
|
+
errorMessage,
|
|
10098
|
+
className,
|
|
10099
|
+
style
|
|
10100
|
+
}) {
|
|
10101
|
+
const portalContainer = usePortalContainer();
|
|
10102
|
+
const [open, setOpen] = useState(false);
|
|
10103
|
+
const [focused, setFocused] = useState(false);
|
|
10104
|
+
const [ruleError, setRuleError] = useState("");
|
|
10105
|
+
const dims = TIMEPICKER_SIZE_CONFIG[size] ?? TIMEPICKER_SIZE_CONFIG.sm;
|
|
10106
|
+
const normalized = value ? formatTimeValue(parseTimeValue(value).hour, parseTimeValue(value).minute) : null;
|
|
10107
|
+
const effectiveUseMeridiem = useMeridiem ?? type === "midday";
|
|
10108
|
+
const displayText = formatTimeDisplay(normalized, effectiveUseMeridiem ? "midday" : "default");
|
|
10109
|
+
const hasValue = normalized != null && normalized !== "";
|
|
10110
|
+
useFormField({
|
|
10111
|
+
name,
|
|
10112
|
+
validate: () => {
|
|
10113
|
+
const msg = runRules(value, rules);
|
|
10114
|
+
setRuleError(msg);
|
|
10115
|
+
return msg === "";
|
|
10116
|
+
},
|
|
10117
|
+
resetValidation: () => setRuleError("")
|
|
10118
|
+
});
|
|
10119
|
+
const resolvedError = error || ruleError !== "";
|
|
10120
|
+
const resolvedStatus = status ?? (rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0);
|
|
10121
|
+
const commitOpen = (next) => {
|
|
10122
|
+
if (disabled) return;
|
|
10123
|
+
setOpen(next);
|
|
10124
|
+
onOpenChange?.(next);
|
|
10125
|
+
if (!next && rules && rules.length > 0) setRuleError(runRules(value, rules));
|
|
10126
|
+
};
|
|
10127
|
+
const commitValue = (next) => {
|
|
10128
|
+
onValueChange?.(next);
|
|
10129
|
+
if (rules && rules.length > 0) setRuleError(runRules(next, rules));
|
|
10130
|
+
};
|
|
10131
|
+
return /* @__PURE__ */ jsx(
|
|
10132
|
+
SField,
|
|
10133
|
+
{
|
|
10134
|
+
label,
|
|
10135
|
+
labelWidth,
|
|
10136
|
+
icon,
|
|
10137
|
+
iconColor,
|
|
10138
|
+
labelTooltip,
|
|
10139
|
+
labelTooltipProps,
|
|
10140
|
+
addonLabel,
|
|
10141
|
+
addonAlign,
|
|
10142
|
+
size,
|
|
10143
|
+
hint,
|
|
10144
|
+
error: resolvedError,
|
|
10145
|
+
status: resolvedStatus,
|
|
10146
|
+
focused: focused || open,
|
|
10147
|
+
errorMessage: ruleError !== "" ? ruleError : errorMessage,
|
|
10148
|
+
width,
|
|
10149
|
+
disabled,
|
|
10150
|
+
className,
|
|
10151
|
+
style: { minWidth: dims.fieldMinWidth, ...style },
|
|
10152
|
+
children: /* @__PURE__ */ jsxs(RPopover2.Root, { open, onOpenChange: commitOpen, children: [
|
|
10153
|
+
/* @__PURE__ */ jsx(RPopover2.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
10154
|
+
"button",
|
|
10155
|
+
{
|
|
10156
|
+
type: "button",
|
|
10157
|
+
name,
|
|
10158
|
+
disabled,
|
|
10159
|
+
onFocus: () => setFocused(true),
|
|
10160
|
+
onBlur: () => setFocused(false),
|
|
10161
|
+
className: "flex h-full w-full items-center overflow-hidden bg-transparent outline-none disabled:cursor-not-allowed",
|
|
10162
|
+
style: { padding: `0 ${dims.paddingX}`, gap: dims.gap, borderRadius: dims.radius },
|
|
10163
|
+
children: [
|
|
10164
|
+
/* @__PURE__ */ jsx(
|
|
10165
|
+
SIcon,
|
|
10166
|
+
{
|
|
10167
|
+
name: "clockOutline",
|
|
10168
|
+
size: dims.icon,
|
|
10169
|
+
color: disabled ? "var(--cmp-timepicker-icon-disabled)" : "var(--cmp-timepicker-icon-default)",
|
|
10170
|
+
className: "flex-shrink-0"
|
|
10171
|
+
}
|
|
10172
|
+
),
|
|
10173
|
+
/* @__PURE__ */ jsx(
|
|
10174
|
+
"span",
|
|
10175
|
+
{
|
|
10176
|
+
className: "flex-1 truncate text-center",
|
|
10177
|
+
style: {
|
|
10178
|
+
minWidth: dims.minWidth,
|
|
10179
|
+
fontSize: dims.fontSize,
|
|
10180
|
+
lineHeight: `${dims.lineHeight}px`,
|
|
10181
|
+
color: disabled ? "var(--cmp-timepicker-text-disabled)" : hasValue ? "var(--cmp-timepicker-text-default)" : "var(--cmp-field-hint-color)"
|
|
10182
|
+
},
|
|
10183
|
+
children: hasValue ? displayText : placeholder
|
|
10184
|
+
}
|
|
10185
|
+
),
|
|
10186
|
+
clearable && hasValue && !disabled && /* @__PURE__ */ jsx(
|
|
10187
|
+
SGhostButton,
|
|
10188
|
+
{
|
|
10189
|
+
icon: "close",
|
|
10190
|
+
size: "xs",
|
|
10191
|
+
ariaLabel: "\uC2DC\uAC04 \uC9C0\uC6B0\uAE30",
|
|
10192
|
+
onClick: (event) => {
|
|
10193
|
+
event.stopPropagation();
|
|
10194
|
+
commitValue(null);
|
|
10195
|
+
}
|
|
10196
|
+
}
|
|
10197
|
+
)
|
|
10198
|
+
]
|
|
10199
|
+
}
|
|
10200
|
+
) }),
|
|
10201
|
+
/* @__PURE__ */ jsx(RPopover2.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
|
|
10202
|
+
RPopover2.Content,
|
|
10203
|
+
{
|
|
10204
|
+
side: "bottom",
|
|
10205
|
+
align: "start",
|
|
10206
|
+
sideOffset: 4,
|
|
10207
|
+
className: cn("z-50", FLOATING_SLIDE_ANIM),
|
|
10208
|
+
children: /* @__PURE__ */ jsx(
|
|
10209
|
+
TimeSelector,
|
|
10210
|
+
{
|
|
10211
|
+
value: normalized,
|
|
10212
|
+
useMeridiem: effectiveUseMeridiem,
|
|
10213
|
+
minuteStep,
|
|
10214
|
+
onChange: commitValue
|
|
10215
|
+
}
|
|
10216
|
+
)
|
|
10217
|
+
}
|
|
10218
|
+
) })
|
|
10219
|
+
] })
|
|
10220
|
+
}
|
|
10221
|
+
);
|
|
10222
|
+
}
|
|
10223
|
+
|
|
10224
|
+
// src/components/STimeRangePicker/time-range-picker.config.ts
|
|
10225
|
+
function getTimeMinutes(value) {
|
|
10226
|
+
const { hour, minute } = parseTimeValue(value);
|
|
10227
|
+
return hour * 60 + minute;
|
|
10228
|
+
}
|
|
10229
|
+
function normalizeTimeRangeValue(value, rangeOrder = "strict") {
|
|
10230
|
+
if (value == null) return null;
|
|
10231
|
+
const normalized = value.map((item) => {
|
|
10232
|
+
const parsed = parseTimeValue(item);
|
|
10233
|
+
return formatTimeValue(parsed.hour, parsed.minute);
|
|
10234
|
+
});
|
|
10235
|
+
if (rangeOrder === "strict" && getTimeMinutes(normalized[0]) > getTimeMinutes(normalized[1])) {
|
|
10236
|
+
return [normalized[0], normalized[0]];
|
|
10237
|
+
}
|
|
10238
|
+
return normalized;
|
|
10239
|
+
}
|
|
10240
|
+
function formatTimeRangeDisplay(value, type) {
|
|
10241
|
+
if (value == null || value[0] === "" || value[1] === "") return "";
|
|
10242
|
+
return `${formatTimeDisplay(value[0], type)} ~ ${formatTimeDisplay(value[1], type)}`;
|
|
10243
|
+
}
|
|
10244
|
+
function RangeTimeSelector({
|
|
10245
|
+
value,
|
|
10246
|
+
useMeridiem,
|
|
10247
|
+
minuteStep,
|
|
10248
|
+
rangeOrder,
|
|
10249
|
+
onChange
|
|
10250
|
+
}) {
|
|
10251
|
+
const range = useMemo(() => value ?? ["00:00", "23:59"], [value]);
|
|
10252
|
+
const [editingKey, setEditingKey] = useState(null);
|
|
10253
|
+
const [inputDraft, setInputDraft] = useState({});
|
|
10254
|
+
const autoAdjustedRef = useRef(null);
|
|
10255
|
+
const getParts = (side) => parseTimeValue(side === "start" ? range[0] : range[1]);
|
|
10256
|
+
const getMeridiem = (side) => getParts(side).hour >= 12 ? "PM" : "AM";
|
|
10257
|
+
const getDisplayHour = (side) => {
|
|
10258
|
+
const { hour } = getParts(side);
|
|
10259
|
+
if (!useMeridiem) return hour;
|
|
10260
|
+
const displayHour = hour % 12;
|
|
10261
|
+
return displayHour === 0 ? 12 : displayHour;
|
|
10262
|
+
};
|
|
10263
|
+
const commit = (side, hour, minute, direction = "unknown") => {
|
|
10264
|
+
const next = formatTimeValue(hour, minute);
|
|
10265
|
+
onChange(normalizeNextRange(side === "start" ? [next, range[1]] : [range[0], next], side, direction));
|
|
10266
|
+
};
|
|
10267
|
+
const getTimeMinutes2 = (time) => {
|
|
10268
|
+
const { hour, minute } = parseTimeValue(time);
|
|
10269
|
+
return hour * 60 + minute;
|
|
10270
|
+
};
|
|
10271
|
+
const normalizeNextRange = (nextRange, changedSide, direction) => {
|
|
10272
|
+
if (rangeOrder === "allow-cross-day") return nextRange;
|
|
10273
|
+
const [start, end] = nextRange;
|
|
10274
|
+
const [currentStart, currentEnd] = range;
|
|
10275
|
+
if (getTimeMinutes2(start) <= getTimeMinutes2(end)) {
|
|
10276
|
+
const shouldKeepSynced = autoAdjustedRef.current?.side === changedSide && currentStart === currentEnd && start !== end && (direction === "unknown" || autoAdjustedRef.current.direction === direction);
|
|
10277
|
+
if (shouldKeepSynced) {
|
|
10278
|
+
return changedSide === "start" ? [start, start] : [end, end];
|
|
10279
|
+
}
|
|
10280
|
+
autoAdjustedRef.current = null;
|
|
10281
|
+
return nextRange;
|
|
10282
|
+
}
|
|
10283
|
+
autoAdjustedRef.current = {
|
|
10284
|
+
side: changedSide,
|
|
10285
|
+
direction: changedSide === "start" ? "increase" : "decrease"
|
|
10286
|
+
};
|
|
10287
|
+
return changedSide === "start" ? [start, start] : [end, end];
|
|
10288
|
+
};
|
|
10289
|
+
const changeHour = (side, delta) => {
|
|
10290
|
+
const { hour, minute } = getParts(side);
|
|
10291
|
+
commit(side, (hour + delta + 24) % 24, minute, delta > 0 ? "increase" : "decrease");
|
|
10292
|
+
};
|
|
10293
|
+
const changeMinute = (side, delta) => {
|
|
10294
|
+
const { hour, minute } = getParts(side);
|
|
10295
|
+
const next = minute + delta;
|
|
10296
|
+
if (next > 59) {
|
|
10297
|
+
commit(side, (hour + 1) % 24, next - 60, delta > 0 ? "increase" : "decrease");
|
|
10298
|
+
return;
|
|
10299
|
+
}
|
|
10300
|
+
if (next < 0) {
|
|
10301
|
+
commit(side, (hour + 23) % 24, next + 60, delta > 0 ? "increase" : "decrease");
|
|
10302
|
+
return;
|
|
10303
|
+
}
|
|
10304
|
+
commit(side, hour, next, delta > 0 ? "increase" : "decrease");
|
|
10305
|
+
};
|
|
10306
|
+
const setMeridiem = (side, next) => {
|
|
10307
|
+
const current = getMeridiem(side);
|
|
10308
|
+
if (current === next) return;
|
|
10309
|
+
const { hour, minute } = getParts(side);
|
|
10310
|
+
commit(side, next === "AM" ? hour - 12 : hour + 12, minute);
|
|
10311
|
+
};
|
|
10312
|
+
const getEditingKey = (side, part) => `${side}-${part}`;
|
|
10313
|
+
const sanitizeInput = (next) => next.replace(/\D/g, "").slice(0, 2);
|
|
10314
|
+
const beginEdit = (side, part, currentValue) => {
|
|
10315
|
+
const key = getEditingKey(side, part);
|
|
10316
|
+
setEditingKey(key);
|
|
10317
|
+
setInputDraft((prev) => ({ ...prev, [key]: String(currentValue).padStart(2, "0") }));
|
|
10318
|
+
};
|
|
10319
|
+
const commitHourDraft = (side, draft) => {
|
|
10320
|
+
const clamped = clampTimePart(Number(draft), useMeridiem ? 1 : 0, useMeridiem ? 12 : 23);
|
|
10321
|
+
const parts = getParts(side);
|
|
10322
|
+
const meridiem = getMeridiem(side);
|
|
10323
|
+
const nextHour = useMeridiem ? meridiem === "PM" ? clamped === 12 ? 12 : clamped + 12 : clamped === 12 ? 0 : clamped : clamped;
|
|
10324
|
+
commit(side, nextHour, parts.minute);
|
|
10325
|
+
return clamped;
|
|
10326
|
+
};
|
|
10327
|
+
const commitMinuteDraft = (side, draft) => {
|
|
10328
|
+
const { hour } = getParts(side);
|
|
10329
|
+
const clamped = clampTimePart(Number(draft), 0, 59);
|
|
10330
|
+
commit(side, hour, clamped);
|
|
10331
|
+
return clamped;
|
|
10332
|
+
};
|
|
10333
|
+
const endEdit = (side, part) => {
|
|
10334
|
+
const key = getEditingKey(side, part);
|
|
10335
|
+
const draft = inputDraft[key];
|
|
10336
|
+
if (part === "hour" && draft != null && draft !== "") {
|
|
10337
|
+
commitHourDraft(side, draft);
|
|
10338
|
+
}
|
|
10339
|
+
if (part === "minute" && draft != null && draft !== "") {
|
|
10340
|
+
commitMinuteDraft(side, draft);
|
|
10341
|
+
}
|
|
10342
|
+
setEditingKey(null);
|
|
10343
|
+
setInputDraft({});
|
|
10344
|
+
};
|
|
10345
|
+
const inputStyle = {
|
|
10346
|
+
width: "var(--cmp-timepicker-selector-input-width)",
|
|
10347
|
+
height: "var(--cmp-textinput-sm-height)",
|
|
10348
|
+
borderRadius: "var(--cmp-textinput-sm-radius)",
|
|
10349
|
+
border: "var(--cmp-textinput-borderWidth) solid var(--cmp-textinput-border-default)",
|
|
10350
|
+
color: "var(--cmp-textinput-text-default)",
|
|
10351
|
+
fontSize: 12,
|
|
10352
|
+
lineHeight: "20px"
|
|
10353
|
+
};
|
|
10354
|
+
const renderColumn = (side, kind) => {
|
|
10355
|
+
const isHour = kind === "hour";
|
|
10356
|
+
const { minute } = getParts(side);
|
|
10357
|
+
const val = isHour ? getDisplayHour(side) : minute;
|
|
10358
|
+
const currentEditingKey = getEditingKey(side, kind);
|
|
10359
|
+
const displayValue = editingKey === currentEditingKey ? inputDraft[currentEditingKey] ?? "" : String(val).padStart(2, "0");
|
|
10360
|
+
return /* @__PURE__ */ jsxs(
|
|
10361
|
+
"div",
|
|
10362
|
+
{
|
|
10363
|
+
className: "flex flex-col items-center justify-center",
|
|
10364
|
+
style: { gap: "var(--cmp-timepicker-selector-time-column-gap)" },
|
|
10365
|
+
children: [
|
|
10366
|
+
/* @__PURE__ */ jsx(
|
|
10367
|
+
SGhostButton,
|
|
10368
|
+
{
|
|
10369
|
+
icon: "chevronUp",
|
|
10370
|
+
size: "xs",
|
|
10371
|
+
ariaLabel: `${side === "start" ? "\uC2DC\uC791" : "\uC885\uB8CC"} ${isHour ? "\uC2DC" : "\uBD84"} \uC99D\uAC00`,
|
|
10372
|
+
onClick: () => isHour ? changeHour(side, 1) : changeMinute(side, minuteStep)
|
|
10373
|
+
}
|
|
10374
|
+
),
|
|
10375
|
+
/* @__PURE__ */ jsx(
|
|
10376
|
+
"input",
|
|
10377
|
+
{
|
|
10378
|
+
"aria-label": `${side === "start" ? "\uC2DC\uC791" : "\uC885\uB8CC"} ${isHour ? "\uC2DC" : "\uBD84"}`,
|
|
10379
|
+
inputMode: "numeric",
|
|
10380
|
+
value: displayValue,
|
|
10381
|
+
placeholder: "-",
|
|
10382
|
+
onFocus: () => beginEdit(side, kind, val),
|
|
10383
|
+
onBlur: () => endEdit(side, kind),
|
|
10384
|
+
onChange: (event) => {
|
|
10385
|
+
const draft = sanitizeInput(event.target.value);
|
|
10386
|
+
setInputDraft((prev) => ({ ...prev, [currentEditingKey]: draft }));
|
|
10387
|
+
if (draft === "") return;
|
|
10388
|
+
const raw = Number(draft);
|
|
10389
|
+
if (isHour) {
|
|
10390
|
+
if (draft.length < 2) return;
|
|
10391
|
+
const clamped2 = commitHourDraft(side, draft);
|
|
10392
|
+
const displayDraft2 = raw === clamped2 ? draft : String(clamped2);
|
|
10393
|
+
setInputDraft((prev) => ({ ...prev, [currentEditingKey]: displayDraft2 }));
|
|
10394
|
+
return;
|
|
10395
|
+
}
|
|
10396
|
+
if (draft.length < 2) return;
|
|
10397
|
+
const clamped = commitMinuteDraft(side, draft);
|
|
10398
|
+
const displayDraft = raw === clamped ? draft : String(clamped);
|
|
10399
|
+
setInputDraft((prev) => ({ ...prev, [currentEditingKey]: displayDraft }));
|
|
10400
|
+
},
|
|
10401
|
+
className: "box-border bg-white text-center outline-none",
|
|
10402
|
+
style: inputStyle
|
|
10403
|
+
}
|
|
10404
|
+
),
|
|
10405
|
+
/* @__PURE__ */ jsx(
|
|
10406
|
+
SGhostButton,
|
|
10407
|
+
{
|
|
10408
|
+
icon: "chevronDown",
|
|
10409
|
+
size: "xs",
|
|
10410
|
+
ariaLabel: `${side === "start" ? "\uC2DC\uC791" : "\uC885\uB8CC"} ${isHour ? "\uC2DC" : "\uBD84"} \uAC10\uC18C`,
|
|
10411
|
+
onClick: () => isHour ? changeHour(side, -1) : changeMinute(side, -minuteStep)
|
|
10412
|
+
}
|
|
10413
|
+
)
|
|
10414
|
+
]
|
|
10415
|
+
}
|
|
10416
|
+
);
|
|
10417
|
+
};
|
|
10418
|
+
const renderPanel = (side, title) => /* @__PURE__ */ jsxs(
|
|
10419
|
+
"div",
|
|
10420
|
+
{
|
|
10421
|
+
className: "flex flex-col items-center justify-center",
|
|
10422
|
+
style: { gap: "var(--cmp-timepicker-selector-range-section-gap)" },
|
|
10423
|
+
children: [
|
|
10424
|
+
/* @__PURE__ */ jsxs(
|
|
10425
|
+
"div",
|
|
10426
|
+
{
|
|
10427
|
+
className: "flex flex-col items-center",
|
|
10428
|
+
style: { gap: "var(--cmp-timepicker-selector-range-heading-gap)" },
|
|
10429
|
+
children: [
|
|
10430
|
+
/* @__PURE__ */ jsx("div", { className: "whitespace-nowrap text-center text-[12px] font-bold leading-[20px] text-[var(--cmp-timepicker-selector-range-heading-color)]", children: title }),
|
|
10431
|
+
useMeridiem && /* @__PURE__ */ jsx("div", { className: "isolate flex", children: ["AM", "PM"].map((item, index) => {
|
|
10432
|
+
const selected = item === getMeridiem(side);
|
|
10433
|
+
return /* @__PURE__ */ jsx(
|
|
10434
|
+
"button",
|
|
10435
|
+
{
|
|
10436
|
+
type: "button",
|
|
10437
|
+
onClick: () => setMeridiem(side, item),
|
|
10438
|
+
className: cn(
|
|
10439
|
+
"box-border h-[var(--cmp-textinput-sm-height)] w-[61px] cursor-pointer border border-solid bg-white text-center text-[12px] font-medium leading-[20px]",
|
|
10440
|
+
index === 0 ? "rounded-l-[var(--cmp-select-sm-radius)] -mr-px" : "rounded-r-[var(--cmp-select-sm-radius)]",
|
|
10441
|
+
selected ? "z-[1] border-[var(--cmp-timepicker-border-focus)] text-[var(--cmp-timepicker-border-focus)]" : "border-[var(--cmp-timepicker-border-default)] text-[var(--cmp-field-hint-color)]"
|
|
10442
|
+
),
|
|
10443
|
+
children: item === "AM" ? "\uC624\uC804" : "\uC624\uD6C4"
|
|
10444
|
+
},
|
|
10445
|
+
item
|
|
10446
|
+
);
|
|
10447
|
+
}) })
|
|
10448
|
+
]
|
|
10449
|
+
}
|
|
10450
|
+
),
|
|
10451
|
+
/* @__PURE__ */ jsxs(
|
|
10452
|
+
"div",
|
|
10453
|
+
{
|
|
10454
|
+
className: "flex items-center justify-center",
|
|
10455
|
+
style: {
|
|
10456
|
+
gap: "var(--cmp-timepicker-selector-time-gap)",
|
|
10457
|
+
padding: "0 var(--cmp-timepicker-selector-section-paddingX)"
|
|
10458
|
+
},
|
|
10459
|
+
children: [
|
|
10460
|
+
renderColumn(side, "hour"),
|
|
10461
|
+
/* @__PURE__ */ jsx(
|
|
10462
|
+
"span",
|
|
10463
|
+
{
|
|
10464
|
+
className: "text-center",
|
|
10465
|
+
style: {
|
|
10466
|
+
width: "var(--cmp-timepicker-selector-colon-size)",
|
|
10467
|
+
color: "var(--cmp-field-hint-color)",
|
|
10468
|
+
fontSize: "var(--cmp-timepicker-selector-colon-size)",
|
|
10469
|
+
lineHeight: "var(--cmp-timepicker-selector-colon-size)"
|
|
10470
|
+
},
|
|
10471
|
+
children: ":"
|
|
10472
|
+
}
|
|
10473
|
+
),
|
|
10474
|
+
renderColumn(side, "minute")
|
|
10475
|
+
]
|
|
10476
|
+
}
|
|
10477
|
+
)
|
|
10478
|
+
]
|
|
10479
|
+
}
|
|
10480
|
+
);
|
|
10481
|
+
return /* @__PURE__ */ jsxs(
|
|
10482
|
+
"div",
|
|
10483
|
+
{
|
|
10484
|
+
className: "flex items-start justify-center overflow-hidden",
|
|
10485
|
+
style: {
|
|
10486
|
+
gap: "var(--cmp-timepicker-selector-range-panelGap)",
|
|
10487
|
+
padding: "var(--cmp-timepicker-selector-range-paddingXY)",
|
|
10488
|
+
background: "var(--cmp-timepicker-selector-bg)",
|
|
10489
|
+
borderRadius: "var(--cmp-timepicker-selector-radius)",
|
|
10490
|
+
boxShadow: "var(--shadow-spread-sm), var(--shadow-spread-md)"
|
|
10491
|
+
},
|
|
10492
|
+
children: [
|
|
10493
|
+
renderPanel("start", "\uC2DC\uC791 \uC2DC\uAC04"),
|
|
10494
|
+
/* @__PURE__ */ jsx("div", { className: "self-stretch w-px bg-[var(--sys-color-divider-default)]" }),
|
|
10495
|
+
renderPanel("end", "\uC885\uB8CC \uC2DC\uAC04")
|
|
10496
|
+
]
|
|
10497
|
+
}
|
|
10498
|
+
);
|
|
10499
|
+
}
|
|
10500
|
+
function STimeRangePicker({
|
|
10501
|
+
value,
|
|
10502
|
+
onValueChange,
|
|
10503
|
+
onOpenChange,
|
|
10504
|
+
type = "default",
|
|
10505
|
+
size = "sm",
|
|
10506
|
+
placeholder = "00:00 ~ 23:59",
|
|
10507
|
+
disabled = false,
|
|
10508
|
+
clearable = false,
|
|
10509
|
+
useMeridiem,
|
|
10510
|
+
minuteStep = 1,
|
|
10511
|
+
rangeOrder = "strict",
|
|
10512
|
+
width,
|
|
10513
|
+
name,
|
|
10514
|
+
rules,
|
|
10515
|
+
status,
|
|
10516
|
+
label,
|
|
10517
|
+
labelWidth,
|
|
10518
|
+
icon,
|
|
10519
|
+
iconColor,
|
|
10520
|
+
labelTooltip,
|
|
10521
|
+
labelTooltipProps,
|
|
10522
|
+
addonLabel,
|
|
10523
|
+
addonAlign,
|
|
10524
|
+
hint,
|
|
10525
|
+
error,
|
|
10526
|
+
errorMessage,
|
|
10527
|
+
className,
|
|
10528
|
+
style
|
|
10529
|
+
}) {
|
|
10530
|
+
const portalContainer = usePortalContainer();
|
|
10531
|
+
const [open, setOpen] = useState(false);
|
|
10532
|
+
const [focused, setFocused] = useState(false);
|
|
10533
|
+
const [ruleError, setRuleError] = useState("");
|
|
10534
|
+
const dims = TIMEPICKER_SIZE_CONFIG[size] ?? TIMEPICKER_SIZE_CONFIG.sm;
|
|
10535
|
+
const normalized = normalizeTimeRangeValue(value ?? null, rangeOrder);
|
|
10536
|
+
const effectiveUseMeridiem = useMeridiem ?? type === "midday";
|
|
10537
|
+
const displayText = formatTimeRangeDisplay(
|
|
10538
|
+
normalized,
|
|
10539
|
+
effectiveUseMeridiem ? "midday" : "default"
|
|
10540
|
+
);
|
|
10541
|
+
const hasValue = normalized != null && normalized[0] !== "" && normalized[1] !== "";
|
|
10542
|
+
useFormField({
|
|
10543
|
+
name,
|
|
10544
|
+
validate: () => {
|
|
10545
|
+
const msg = runRules(value, rules);
|
|
10546
|
+
setRuleError(msg);
|
|
10547
|
+
return msg === "";
|
|
10548
|
+
},
|
|
10549
|
+
resetValidation: () => setRuleError("")
|
|
10550
|
+
});
|
|
10551
|
+
const resolvedError = error || ruleError !== "";
|
|
10552
|
+
const resolvedStatus = status ?? (rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0);
|
|
10553
|
+
const commitOpen = (next) => {
|
|
10554
|
+
if (disabled) return;
|
|
10555
|
+
setOpen(next);
|
|
10556
|
+
onOpenChange?.(next);
|
|
10557
|
+
if (!next && rules && rules.length > 0) setRuleError(runRules(value, rules));
|
|
10558
|
+
};
|
|
10559
|
+
const commitValue = (next) => {
|
|
10560
|
+
onValueChange?.(next);
|
|
10561
|
+
if (rules && rules.length > 0) setRuleError(runRules(next, rules));
|
|
10562
|
+
};
|
|
10563
|
+
return /* @__PURE__ */ jsx(
|
|
10564
|
+
SField,
|
|
10565
|
+
{
|
|
10566
|
+
label,
|
|
10567
|
+
labelWidth,
|
|
10568
|
+
icon,
|
|
10569
|
+
iconColor,
|
|
10570
|
+
labelTooltip,
|
|
10571
|
+
labelTooltipProps,
|
|
10572
|
+
addonLabel,
|
|
10573
|
+
addonAlign,
|
|
10574
|
+
size,
|
|
10575
|
+
hint,
|
|
10576
|
+
error: resolvedError,
|
|
10577
|
+
status: resolvedStatus,
|
|
10578
|
+
focused: focused || open,
|
|
10579
|
+
errorMessage: ruleError !== "" ? ruleError : errorMessage,
|
|
10580
|
+
width,
|
|
10581
|
+
disabled,
|
|
10582
|
+
className,
|
|
10583
|
+
style: { minWidth: dims.fieldMinWidth, ...style },
|
|
10584
|
+
children: /* @__PURE__ */ jsxs(RPopover2.Root, { open, onOpenChange: commitOpen, children: [
|
|
10585
|
+
/* @__PURE__ */ jsx(RPopover2.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
10586
|
+
"button",
|
|
10587
|
+
{
|
|
10588
|
+
type: "button",
|
|
10589
|
+
name,
|
|
10590
|
+
disabled,
|
|
10591
|
+
onFocus: () => setFocused(true),
|
|
10592
|
+
onBlur: () => setFocused(false),
|
|
10593
|
+
className: "flex h-full w-full items-center overflow-hidden bg-transparent outline-none disabled:cursor-not-allowed",
|
|
10594
|
+
style: { padding: `0 ${dims.paddingX}`, gap: dims.gap, borderRadius: dims.radius },
|
|
10595
|
+
children: [
|
|
10596
|
+
/* @__PURE__ */ jsx(
|
|
10597
|
+
SIcon,
|
|
10598
|
+
{
|
|
10599
|
+
name: "clockOutline",
|
|
10600
|
+
size: dims.icon,
|
|
10601
|
+
color: disabled ? "var(--cmp-timepicker-icon-disabled)" : "var(--cmp-timepicker-icon-default)",
|
|
10602
|
+
className: "flex-shrink-0"
|
|
10603
|
+
}
|
|
10604
|
+
),
|
|
10605
|
+
/* @__PURE__ */ jsx(
|
|
10606
|
+
"span",
|
|
10607
|
+
{
|
|
10608
|
+
className: "flex-1 truncate text-center",
|
|
10609
|
+
style: {
|
|
10610
|
+
minWidth: dims.minWidth,
|
|
10611
|
+
fontSize: dims.fontSize,
|
|
10612
|
+
lineHeight: `${dims.lineHeight}px`,
|
|
10613
|
+
color: disabled ? "var(--cmp-timepicker-text-disabled)" : hasValue ? "var(--cmp-timepicker-text-default)" : "var(--cmp-field-hint-color)"
|
|
10614
|
+
},
|
|
10615
|
+
children: hasValue ? displayText : placeholder
|
|
10616
|
+
}
|
|
10617
|
+
),
|
|
10618
|
+
clearable && hasValue && !disabled && /* @__PURE__ */ jsx(
|
|
10619
|
+
SGhostButton,
|
|
10620
|
+
{
|
|
10621
|
+
icon: "close",
|
|
10622
|
+
size: "xs",
|
|
10623
|
+
ariaLabel: "\uC2DC\uAC04 \uBC94\uC704 \uC9C0\uC6B0\uAE30",
|
|
10624
|
+
onClick: (event) => {
|
|
10625
|
+
event.stopPropagation();
|
|
10626
|
+
commitValue(null);
|
|
10627
|
+
}
|
|
10628
|
+
}
|
|
10629
|
+
)
|
|
10630
|
+
]
|
|
10631
|
+
}
|
|
10632
|
+
) }),
|
|
10633
|
+
/* @__PURE__ */ jsx(RPopover2.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
|
|
10634
|
+
RPopover2.Content,
|
|
10635
|
+
{
|
|
10636
|
+
side: "bottom",
|
|
10637
|
+
align: "start",
|
|
10638
|
+
sideOffset: 4,
|
|
10639
|
+
className: cn("z-50", FLOATING_SLIDE_ANIM),
|
|
10640
|
+
children: /* @__PURE__ */ jsx(
|
|
10641
|
+
RangeTimeSelector,
|
|
10642
|
+
{
|
|
10643
|
+
value: normalized,
|
|
10644
|
+
useMeridiem: effectiveUseMeridiem,
|
|
10645
|
+
minuteStep,
|
|
10646
|
+
rangeOrder,
|
|
10647
|
+
onChange: commitValue
|
|
10648
|
+
}
|
|
10649
|
+
)
|
|
10650
|
+
}
|
|
10651
|
+
) })
|
|
10652
|
+
] })
|
|
10653
|
+
}
|
|
10654
|
+
);
|
|
10655
|
+
}
|
|
10656
|
+
|
|
10657
|
+
export { BADGE_COLORS, BUTTON_COLORS, BUTTON_SIZES, COLOR_KEYS, GNB_COLORS, GNB_COMMON, GNB_HEADER, GNB_MENU, GNB_MENU_WIDTH, ICONS, SActionModal, SBadge, SBarcodeInput, SButton, SCalendar, SCallout, SCard, SCheckbox, SChip, SChipInput, SCircleProgress, SConfirmModal, SDatePicker, SDateRangePicker, SDivider, SDropdownButton, SField, SFilePicker, SForm, SGhostButton, SGnb, SGuide, SIcon, SInput, SKeyValueTable, SLayout, SLayoutContext, SLinearProgress, SLoadingContainer, SLoadingModal, SLoadingViewport, SNumberInput, SPage, SPagination, SPopover, SPopup, SPortal, SRadio, SRadioButton, SRadioGroup, SSelect, SSwitch, STable, STabs, STag, STextLink, STextarea, STimePicker, STimeRangePicker, SToast, SToastContainer, SToggle, STooltip, TAG_COLORS, TAG_SHAPES, TAG_SIZES, TIMEPICKER_SIZES, TIMEPICKER_SIZE_CONFIG, buttonPreset, cn, findGnbAncestors, isColorKey, loading, resolveColor, useSLayout };
|
|
9810
10658
|
//# sourceMappingURL=index.js.map
|
|
9811
10659
|
//# sourceMappingURL=index.js.map
|