sellmate-design-system-react 0.5.0 → 0.6.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 +20 -0
- package/dist/components/SDateRangePicker/SDateRangePicker.cjs +180 -37
- package/dist/components/SDateRangePicker/SDateRangePicker.cjs.map +1 -1
- package/dist/components/SDateRangePicker/SDateRangePicker.d.ts +6 -1
- package/dist/components/SDateRangePicker/SDateRangePicker.js +180 -37
- package/dist/components/SDateRangePicker/SDateRangePicker.js.map +1 -1
- package/dist/components/SGnb/SGnb.cjs +124 -54
- package/dist/components/SGnb/SGnb.cjs.map +1 -1
- package/dist/components/SGnb/SGnb.d.ts +7 -1
- package/dist/components/SGnb/SGnb.js +125 -55
- package/dist/components/SGnb/SGnb.js.map +1 -1
- package/dist/components/SKeyValueTable/SKeyValueTable.cjs +180 -37
- package/dist/components/SKeyValueTable/SKeyValueTable.cjs.map +1 -1
- package/dist/components/SKeyValueTable/SKeyValueTable.js +180 -37
- package/dist/components/SKeyValueTable/SKeyValueTable.js.map +1 -1
- package/dist/components/SLayout/SLayout.cjs +21 -6
- package/dist/components/SLayout/SLayout.cjs.map +1 -1
- package/dist/components/SLayout/SLayout.d.ts +17 -2
- package/dist/components/SLayout/SLayout.js +21 -6
- package/dist/components/SLayout/SLayout.js.map +1 -1
- package/dist/components/SPage/SPage.cjs +21 -6
- package/dist/components/SPage/SPage.cjs.map +1 -1
- package/dist/components/SPage/SPage.js +21 -6
- package/dist/components/SPage/SPage.js.map +1 -1
- package/dist/index.cjs +303 -90
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +303 -90
- package/dist/index.js.map +1 -1
- package/dist/styles.css +61 -0
- package/package.json +3 -1
package/dist/index.cjs
CHANGED
|
@@ -5069,15 +5069,30 @@ var SLayout = react.forwardRef(function SLayout2({
|
|
|
5069
5069
|
},
|
|
5070
5070
|
[isControlled, onFoldedChange]
|
|
5071
5071
|
);
|
|
5072
|
+
const [gnbState, setGnbState] = react.useState({ forceFull: false, menuVisible: true });
|
|
5073
|
+
const reportGnbState = react.useCallback(
|
|
5074
|
+
(next) => setGnbState(
|
|
5075
|
+
(prev) => prev.forceFull === next.forceFull && prev.menuVisible === next.menuVisible ? prev : next
|
|
5076
|
+
),
|
|
5077
|
+
[]
|
|
5078
|
+
);
|
|
5079
|
+
const effectiveHeader = header === "full" || gnbState.forceFull ? "full" : "fix";
|
|
5072
5080
|
const ctx = react.useMemo(
|
|
5073
|
-
() => ({
|
|
5074
|
-
|
|
5081
|
+
() => ({
|
|
5082
|
+
type,
|
|
5083
|
+
header: effectiveHeader,
|
|
5084
|
+
useRail,
|
|
5085
|
+
folded: currentFolded,
|
|
5086
|
+
setFolded,
|
|
5087
|
+
reportGnbState
|
|
5088
|
+
}),
|
|
5089
|
+
[type, effectiveHeader, useRail, currentFolded, setFolded, reportGnbState]
|
|
5075
5090
|
);
|
|
5076
|
-
const isFullHeader =
|
|
5077
|
-
const gnbColumnWidth = useRail ? GNB_RAIL_WIDTH + GNB_MENU_WIDTH :
|
|
5091
|
+
const isFullHeader = effectiveHeader === "full";
|
|
5092
|
+
const gnbColumnWidth = (useRail ? GNB_RAIL_WIDTH : 0) + (gnbState.menuVisible ? GNB_MENU_WIDTH : 0);
|
|
5078
5093
|
const frameStyle = isFullHeader ? {
|
|
5079
5094
|
gridTemplateColumns: `${currentFolded ? 0 : gnbColumnWidth}px 1fr`,
|
|
5080
|
-
gridTemplateRows: `${GNB_HEADER[
|
|
5095
|
+
gridTemplateRows: `${GNB_HEADER[effectiveHeader].topHeight} 1fr`,
|
|
5081
5096
|
// 메뉴가 미끄러지는 동안 페이지 열도 같은 길이로 따라와야 한 덩어리로 읽힌다.
|
|
5082
5097
|
// (fix 는 SGnb 가 제 폭을 직접 전환하므로 프레임이 손댈 게 없다)
|
|
5083
5098
|
transition: `grid-template-columns ${GNB_FOLD_MS}ms ease-out`
|
|
@@ -5087,7 +5102,7 @@ var SLayout = react.forwardRef(function SLayout2({
|
|
|
5087
5102
|
{
|
|
5088
5103
|
ref,
|
|
5089
5104
|
"data-type": type,
|
|
5090
|
-
"data-header":
|
|
5105
|
+
"data-header": effectiveHeader,
|
|
5091
5106
|
className: cn(
|
|
5092
5107
|
"box-border h-full overflow-hidden",
|
|
5093
5108
|
isFullHeader ? "grid" : "flex flex-row",
|
|
@@ -5120,9 +5135,10 @@ var SGnb = react.forwardRef(function SGnb2({
|
|
|
5120
5135
|
}, ref) {
|
|
5121
5136
|
const layout = react.useContext(SLayoutContext);
|
|
5122
5137
|
const type = typeProp ?? layout?.type ?? "box";
|
|
5123
|
-
const header = headerProp ?? layout?.header ?? "fix";
|
|
5124
5138
|
const folded = foldedProp ?? layout?.folded ?? false;
|
|
5125
5139
|
const useRail = useRailProp ?? layout?.useRail ?? false;
|
|
5140
|
+
const railHasLeaf = useRail && items.some((item) => !item.children || item.children.length === 0);
|
|
5141
|
+
const header = railHasLeaf ? "full" : headerProp ?? layout?.header ?? "fix";
|
|
5126
5142
|
const H = GNB_HEADER[header];
|
|
5127
5143
|
const M = GNB_MENU[type];
|
|
5128
5144
|
const C = GNB_COLORS[color];
|
|
@@ -5310,7 +5326,11 @@ var SGnb = react.forwardRef(function SGnb2({
|
|
|
5310
5326
|
};
|
|
5311
5327
|
const railItems = useRail ? items : [];
|
|
5312
5328
|
const menuItems = useRail ? items.find((item) => item.value === activeRail)?.children ?? [] : items;
|
|
5313
|
-
const
|
|
5329
|
+
const showMenu = !useRail || menuItems.length > 0;
|
|
5330
|
+
const bodyWidth = (useRail ? GNB_RAIL_WIDTH : 0) + (showMenu ? GNB_MENU_WIDTH : 0);
|
|
5331
|
+
react.useEffect(() => {
|
|
5332
|
+
layout?.reportGnbState({ forceFull: railHasLeaf, menuVisible: showMenu });
|
|
5333
|
+
}, [layout, railHasLeaf, showMenu]);
|
|
5314
5334
|
const railFolded = folded && header === "fix";
|
|
5315
5335
|
const rootWidth = header === "full" ? "100%" : folded ? GNB_COMMON.foldWidth : bodyWidth;
|
|
5316
5336
|
const rootStyle = {
|
|
@@ -5320,6 +5340,13 @@ var SGnb = react.forwardRef(function SGnb2({
|
|
|
5320
5340
|
...style
|
|
5321
5341
|
};
|
|
5322
5342
|
const hideAfterSlide = (hidden) => `visibility 0s linear ${hidden ? `${GNB_FOLD_MS}ms` : "0s"}`;
|
|
5343
|
+
const foldInline = !!logo;
|
|
5344
|
+
const sideFoldStyle = {
|
|
5345
|
+
opacity: railFolded ? 0 : 1,
|
|
5346
|
+
position: railFolded ? "absolute" : "static",
|
|
5347
|
+
visibility: railFolded ? "hidden" : "visible",
|
|
5348
|
+
transition: `opacity ${GNB_FOLD_MS}ms ease-out, ${hideAfterSlide(railFolded)}`
|
|
5349
|
+
};
|
|
5323
5350
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5324
5351
|
"div",
|
|
5325
5352
|
{
|
|
@@ -5331,12 +5358,14 @@ var SGnb = react.forwardRef(function SGnb2({
|
|
|
5331
5358
|
"data-color": color,
|
|
5332
5359
|
...rest,
|
|
5333
5360
|
children: [
|
|
5334
|
-
/* @__PURE__ */ jsxRuntime.
|
|
5361
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5335
5362
|
"div",
|
|
5336
5363
|
{
|
|
5337
5364
|
className: "relative box-border flex shrink-0 items-center overflow-hidden",
|
|
5338
5365
|
style: {
|
|
5339
5366
|
height: H.topHeight,
|
|
5367
|
+
// 인라인 간격은 컨테이너 gap 대신 각 요소 margin 으로 준다 — 런처↔폴드(8px)와
|
|
5368
|
+
// 폴드↔로고(top-gap)를 다르게 두기 위함. 접히면 런처·로고가 흐름에서 빠져 margin 도 무의미해진다.
|
|
5340
5369
|
padding: `0 ${railFolded ? GNB_RAIL.padding : H.topPaddingX}`,
|
|
5341
5370
|
borderBottom: `1px solid ${C.topBorder}`,
|
|
5342
5371
|
backgroundColor: C.panelBg,
|
|
@@ -5345,49 +5374,90 @@ var SGnb = react.forwardRef(function SGnb2({
|
|
|
5345
5374
|
// 아이콘 버튼은 자체 ghostButton 토큰을 쓰므로, 이 색은 logo 슬롯 상속용
|
|
5346
5375
|
color: C.itemColorDefault
|
|
5347
5376
|
},
|
|
5348
|
-
children:
|
|
5349
|
-
(
|
|
5350
|
-
|
|
5351
|
-
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
|
|
5373
|
-
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5377
|
+
children: foldInline ? (
|
|
5378
|
+
// 런처(있을 때)·폴드·로고를 흐름에 나란히 둔다 → 폴드 버튼이 (런처와) 로고 사이에 선다.
|
|
5379
|
+
// 접히면 런처·로고가 페이드하며 흐름에서 빠지고(sideFoldStyle), 폴드 버튼만 남아 레일 가운데에 선다.
|
|
5380
|
+
/* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5381
|
+
onLauncherClick && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5382
|
+
SGhostButton,
|
|
5383
|
+
{
|
|
5384
|
+
icon: "launcher",
|
|
5385
|
+
size: "xs",
|
|
5386
|
+
intent: color === "dark" ? "inverse" : "default",
|
|
5387
|
+
ariaLabel: "app launcher",
|
|
5388
|
+
onClick: onLauncherClick,
|
|
5389
|
+
className: "shrink-0",
|
|
5390
|
+
style: { ...sideFoldStyle, marginRight: "8px" }
|
|
5391
|
+
}
|
|
5392
|
+
),
|
|
5393
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5394
|
+
SGhostButton,
|
|
5395
|
+
{
|
|
5396
|
+
icon: "sidebar",
|
|
5397
|
+
size: "xs",
|
|
5398
|
+
intent: color === "dark" ? "inverse" : "default",
|
|
5399
|
+
ariaLabel: "toggle navigation",
|
|
5400
|
+
ariaPressed: folded,
|
|
5401
|
+
onClick: handleFoldToggle,
|
|
5402
|
+
className: "shrink-0"
|
|
5403
|
+
}
|
|
5404
|
+
),
|
|
5405
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5406
|
+
"div",
|
|
5407
|
+
{
|
|
5408
|
+
className: "flex shrink-0 items-center",
|
|
5409
|
+
style: { height: H.logoHeight, marginLeft: H.topGap, ...sideFoldStyle },
|
|
5410
|
+
children: logo
|
|
5411
|
+
}
|
|
5412
|
+
)
|
|
5413
|
+
] })
|
|
5414
|
+
) : (
|
|
5415
|
+
// 런처·로고는 좌측 그룹(흐름에서 빼 폭 축소 중 폴드 버튼을 밀어내지 않는다),
|
|
5416
|
+
// 폴드 버튼은 우측 끝(ml-auto)이라 폭·패딩이 줄면 저절로 레일 가운데에 선다.
|
|
5417
|
+
/* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5418
|
+
(onLauncherClick || logo) && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5419
|
+
"div",
|
|
5420
|
+
{
|
|
5421
|
+
className: "absolute inset-y-0 flex items-center",
|
|
5422
|
+
style: {
|
|
5423
|
+
left: H.topPaddingX,
|
|
5424
|
+
gap: H.topGap,
|
|
5425
|
+
opacity: railFolded ? 0 : 1,
|
|
5426
|
+
transition: `opacity ${GNB_FOLD_MS}ms ease-out, ${hideAfterSlide(railFolded)}, transform ${GNB_FOLD_MS}ms ease-out`,
|
|
5427
|
+
// 메뉴와 같은 방향으로 빠지되, 좁은 레일 안에서 꼬리가 비치지 않게 페이드가 거리를 대신한다
|
|
5428
|
+
transform: railFolded ? `translateX(-${H.topPaddingX})` : "none",
|
|
5429
|
+
visibility: railFolded ? "hidden" : "visible"
|
|
5430
|
+
},
|
|
5431
|
+
children: [
|
|
5432
|
+
onLauncherClick && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5433
|
+
SGhostButton,
|
|
5434
|
+
{
|
|
5435
|
+
icon: "launcher",
|
|
5436
|
+
size: "xs",
|
|
5437
|
+
intent: color === "dark" ? "inverse" : "default",
|
|
5438
|
+
ariaLabel: "app launcher",
|
|
5439
|
+
onClick: onLauncherClick,
|
|
5440
|
+
className: "shrink-0"
|
|
5441
|
+
}
|
|
5442
|
+
),
|
|
5443
|
+
logo && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center", style: { height: H.logoHeight }, children: logo })
|
|
5444
|
+
]
|
|
5445
|
+
}
|
|
5446
|
+
),
|
|
5447
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5448
|
+
SGhostButton,
|
|
5449
|
+
{
|
|
5450
|
+
icon: "sidebar",
|
|
5451
|
+
size: "xs",
|
|
5452
|
+
intent: color === "dark" ? "inverse" : "default",
|
|
5453
|
+
ariaLabel: "toggle navigation",
|
|
5454
|
+
ariaPressed: folded,
|
|
5455
|
+
onClick: handleFoldToggle,
|
|
5456
|
+
className: "ml-auto shrink-0"
|
|
5457
|
+
}
|
|
5458
|
+
)
|
|
5459
|
+
] })
|
|
5460
|
+
)
|
|
5391
5461
|
}
|
|
5392
5462
|
),
|
|
5393
5463
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -5423,7 +5493,7 @@ var SGnb = react.forwardRef(function SGnb2({
|
|
|
5423
5493
|
children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "m-0 flex list-none flex-col p-0", style: { gap: GNB_RAIL.gap }, children: railItems.map(renderRailItem) })
|
|
5424
5494
|
}
|
|
5425
5495
|
),
|
|
5426
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5496
|
+
showMenu && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5427
5497
|
"nav",
|
|
5428
5498
|
{
|
|
5429
5499
|
"aria-label": ariaLabel,
|
|
@@ -8088,25 +8158,45 @@ function SDatePicker({
|
|
|
8088
8158
|
}
|
|
8089
8159
|
);
|
|
8090
8160
|
}
|
|
8161
|
+
function splitDateTime(v) {
|
|
8162
|
+
if (!v) return { date: null, hour: "00", minute: "00" };
|
|
8163
|
+
const [date = "", time = ""] = v.split(" ");
|
|
8164
|
+
const [hour = "00", minute = "00"] = time.split(":");
|
|
8165
|
+
return { date: date || null, hour, minute };
|
|
8166
|
+
}
|
|
8091
8167
|
function RangeCalendar({
|
|
8092
8168
|
value,
|
|
8093
8169
|
selectable,
|
|
8094
8170
|
maxRange,
|
|
8171
|
+
useTimePicker = false,
|
|
8095
8172
|
onSelect,
|
|
8096
8173
|
onPendingStartChange,
|
|
8097
8174
|
onViewChange
|
|
8098
8175
|
}) {
|
|
8099
8176
|
const today = todayStr();
|
|
8100
|
-
const
|
|
8177
|
+
const initial = splitDateTime(value?.[0]);
|
|
8178
|
+
const base = initial.date || today;
|
|
8101
8179
|
const [y, setY] = react.useState(Number(base.split("-")[0]));
|
|
8102
8180
|
const [m, setM] = react.useState(Number(base.split("-")[1]));
|
|
8103
|
-
const [start, setStart] = react.useState(
|
|
8104
|
-
const [end, setEnd] = react.useState(value?.[1]
|
|
8181
|
+
const [start, setStart] = react.useState(initial.date);
|
|
8182
|
+
const [end, setEnd] = react.useState(splitDateTime(value?.[1]).date);
|
|
8105
8183
|
const [hover, setHover] = react.useState(null);
|
|
8184
|
+
const [sH, setSH] = react.useState(initial.hour);
|
|
8185
|
+
const [sM, setSM] = react.useState(initial.minute);
|
|
8186
|
+
const [eH, setEH] = react.useState(splitDateTime(value?.[1]).hour);
|
|
8187
|
+
const [eM, setEM] = react.useState(splitDateTime(value?.[1]).minute);
|
|
8188
|
+
const lastEmitted = react.useRef("");
|
|
8106
8189
|
react.useEffect(() => {
|
|
8107
|
-
|
|
8108
|
-
|
|
8109
|
-
|
|
8190
|
+
if (useTimePicker && JSON.stringify(value) === lastEmitted.current) return;
|
|
8191
|
+
const s = splitDateTime(value?.[0]);
|
|
8192
|
+
const e = splitDateTime(value?.[1]);
|
|
8193
|
+
setStart(s.date);
|
|
8194
|
+
setEnd(e.date);
|
|
8195
|
+
setSH(s.hour);
|
|
8196
|
+
setSM(s.minute);
|
|
8197
|
+
setEH(e.hour);
|
|
8198
|
+
setEM(e.minute);
|
|
8199
|
+
}, [value, useTimePicker]);
|
|
8110
8200
|
const setBase = (ny, nm) => {
|
|
8111
8201
|
setY(ny);
|
|
8112
8202
|
setM(nm);
|
|
@@ -8150,18 +8240,53 @@ function RangeCalendar({
|
|
|
8150
8240
|
const hasRange = !!(rStart && rEnd && rStart !== rEnd);
|
|
8151
8241
|
const inRange = (d) => !!(rStart && rEnd && d > rStart && d < rEnd);
|
|
8152
8242
|
const RANGE_BG = "var(--cmp-datepicker-calendar-range-bg)";
|
|
8243
|
+
const pad = (v) => String(Number(v) || 0).padStart(2, "0");
|
|
8244
|
+
const emit2 = (dateStart, dateEnd, time) => {
|
|
8245
|
+
const t = time ?? { sH, sM, eH, eM };
|
|
8246
|
+
const range = useTimePicker ? [`${dateStart} ${pad(t.sH)}:${pad(t.sM)}`, `${dateEnd} ${pad(t.eH)}:${pad(t.eM)}`] : [dateStart, dateEnd];
|
|
8247
|
+
lastEmitted.current = JSON.stringify(range);
|
|
8248
|
+
onSelect(range);
|
|
8249
|
+
};
|
|
8153
8250
|
const click = (d) => {
|
|
8154
8251
|
if (isDisabled(d)) return;
|
|
8155
8252
|
if (!start || complete || d < start) {
|
|
8156
8253
|
setStart(d);
|
|
8157
8254
|
setEnd(null);
|
|
8158
8255
|
setHover(null);
|
|
8256
|
+
if (useTimePicker) {
|
|
8257
|
+
setSH("00");
|
|
8258
|
+
setSM("00");
|
|
8259
|
+
setEH("23");
|
|
8260
|
+
setEM("59");
|
|
8261
|
+
}
|
|
8159
8262
|
onPendingStartChange?.(d);
|
|
8160
8263
|
return;
|
|
8161
8264
|
}
|
|
8162
8265
|
setEnd(d);
|
|
8163
8266
|
onPendingStartChange?.(null);
|
|
8164
|
-
|
|
8267
|
+
emit2(start, d, useTimePicker ? { sH, sM, eH: "23", eM: "59" } : void 0);
|
|
8268
|
+
};
|
|
8269
|
+
const changeTime = (which, part, raw) => {
|
|
8270
|
+
const digits = raw.replace(/\D/g, "").slice(0, 2);
|
|
8271
|
+
const max = part === "h" ? 23 : 59;
|
|
8272
|
+
const next = digits !== "" && Number(digits) > max ? String(max) : digits;
|
|
8273
|
+
const nextTime = { sH, sM, eH, eM };
|
|
8274
|
+
if (which === "start") nextTime[part === "h" ? "sH" : "sM"] = next;
|
|
8275
|
+
else nextTime[part === "h" ? "eH" : "eM"] = next;
|
|
8276
|
+
setSH(nextTime.sH);
|
|
8277
|
+
setSM(nextTime.sM);
|
|
8278
|
+
setEH(nextTime.eH);
|
|
8279
|
+
setEM(nextTime.eM);
|
|
8280
|
+
if (start && end) emit2(start, end, nextTime);
|
|
8281
|
+
};
|
|
8282
|
+
const blurTime = (which, part) => {
|
|
8283
|
+
if (which === "start") {
|
|
8284
|
+
if (part === "h") setSH(pad(sH));
|
|
8285
|
+
else setSM(pad(sM));
|
|
8286
|
+
} else {
|
|
8287
|
+
if (part === "h") setEH(pad(eH));
|
|
8288
|
+
else setEM(pad(eM));
|
|
8289
|
+
}
|
|
8165
8290
|
};
|
|
8166
8291
|
const GRID_COLS = "grid grid-cols-[repeat(7,var(--cmp-datepicker-calendar-day-width))]";
|
|
8167
8292
|
const renderPanel = (gy, gm, isLeft) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-[var(--cmp-datepicker-calendar-gap)]", children: [
|
|
@@ -8236,35 +8361,120 @@ function RangeCalendar({
|
|
|
8236
8361
|
);
|
|
8237
8362
|
}) })
|
|
8238
8363
|
] });
|
|
8239
|
-
|
|
8240
|
-
|
|
8241
|
-
|
|
8242
|
-
|
|
8243
|
-
|
|
8244
|
-
|
|
8245
|
-
|
|
8246
|
-
|
|
8247
|
-
|
|
8248
|
-
|
|
8249
|
-
|
|
8250
|
-
|
|
8251
|
-
|
|
8252
|
-
|
|
8253
|
-
|
|
8254
|
-
|
|
8255
|
-
|
|
8256
|
-
|
|
8257
|
-
|
|
8258
|
-
|
|
8259
|
-
|
|
8260
|
-
|
|
8261
|
-
|
|
8262
|
-
|
|
8263
|
-
|
|
8364
|
+
const renderTimeSection = (which, date, suffix) => {
|
|
8365
|
+
const active = !!date;
|
|
8366
|
+
const [yy = "", mm = "", dd = ""] = date ? date.split("-") : [];
|
|
8367
|
+
const hour = which === "start" ? sH : eH;
|
|
8368
|
+
const minute = which === "start" ? sM : eM;
|
|
8369
|
+
const num = (n, strip) => active && n !== "" ? strip ? String(Number(n)) : n : "-";
|
|
8370
|
+
const INPUT_CLS = "h-[var(--cmp-datepicker-sm-height)] w-[40px] rounded-[var(--cmp-datepicker-sm-radius)] border border-solid border-[color:var(--cmp-datepicker-border-default)] bg-[var(--cmp-datepicker-bg-default)] text-center text-[12px] font-medium leading-[20px] text-[color:var(--cmp-datepicker-text-default)] outline-none placeholder:text-[color:var(--cmp-datepicker-text-disabled)] focus:border-[color:var(--cmp-datepicker-border-focus)] disabled:cursor-not-allowed";
|
|
8371
|
+
const LABEL = "text-[color:var(--cmp-datepicker-calendar-time-date-label)]";
|
|
8372
|
+
const UNIT = "text-[color:var(--cmp-datepicker-calendar-time-date-unit)]";
|
|
8373
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8374
|
+
"div",
|
|
8375
|
+
{
|
|
8376
|
+
className: cn(
|
|
8377
|
+
"flex flex-1 items-center justify-center gap-[var(--cmp-datepicker-calendar-time-section-gap)] rounded-[var(--cmp-datepicker-calendar-time-radius)] px-[var(--cmp-datepicker-calendar-time-paddingX)] py-[var(--cmp-datepicker-calendar-time-paddingY)] text-[12px] font-medium leading-[20px]",
|
|
8378
|
+
active ? "bg-[var(--cmp-datepicker-calendar-time-bg-selected)]" : "bg-[var(--cmp-datepicker-calendar-time-bg-default)]"
|
|
8379
|
+
),
|
|
8380
|
+
children: [
|
|
8381
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-[var(--cmp-datepicker-calendar-time-date-gap)]", children: [
|
|
8382
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: LABEL, children: num(yy, false) }),
|
|
8383
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: UNIT, children: "\uB144" }),
|
|
8384
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: LABEL, children: num(mm, true) }),
|
|
8385
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: UNIT, children: "\uC6D4" }),
|
|
8386
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: LABEL, children: num(dd, true) }),
|
|
8387
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: UNIT, children: "\uC77C" })
|
|
8388
|
+
] }),
|
|
8389
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-[var(--cmp-datepicker-calendar-time-unit-gap)]", children: [
|
|
8390
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8391
|
+
"input",
|
|
8392
|
+
{
|
|
8393
|
+
type: "text",
|
|
8394
|
+
inputMode: "numeric",
|
|
8395
|
+
maxLength: 2,
|
|
8396
|
+
"aria-label": `${suffix} \uC2DC`,
|
|
8397
|
+
disabled: !active,
|
|
8398
|
+
value: active ? hour : "",
|
|
8399
|
+
placeholder: "--",
|
|
8400
|
+
onChange: (e) => changeTime(which, "h", e.target.value),
|
|
8401
|
+
onBlur: () => blurTime(which, "h"),
|
|
8402
|
+
className: INPUT_CLS
|
|
8403
|
+
}
|
|
8404
|
+
),
|
|
8405
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: LABEL, children: ":" }),
|
|
8406
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8407
|
+
"input",
|
|
8408
|
+
{
|
|
8409
|
+
type: "text",
|
|
8410
|
+
inputMode: "numeric",
|
|
8411
|
+
maxLength: 2,
|
|
8412
|
+
"aria-label": `${suffix} \uBD84`,
|
|
8413
|
+
disabled: !active,
|
|
8414
|
+
value: active ? minute : "",
|
|
8415
|
+
placeholder: "--",
|
|
8416
|
+
onChange: (e) => changeTime(which, "m", e.target.value),
|
|
8417
|
+
onBlur: () => blurTime(which, "m"),
|
|
8418
|
+
className: INPUT_CLS
|
|
8419
|
+
}
|
|
8420
|
+
)
|
|
8421
|
+
] }),
|
|
8422
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: UNIT, children: suffix })
|
|
8423
|
+
]
|
|
8424
|
+
}
|
|
8425
|
+
);
|
|
8426
|
+
};
|
|
8427
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8428
|
+
"div",
|
|
8429
|
+
{
|
|
8430
|
+
className: cn(
|
|
8431
|
+
"inline-flex flex-col gap-[var(--cmp-datepicker-calendar-gap)] rounded-[var(--cmp-datepicker-calendar-radius)] bg-[var(--cmp-datepicker-calendar-bg)] p-[var(--cmp-datepicker-calendar-paddingXY)] shadow-[2px_2px_12px_2px_rgba(0,0,0,0.2)] select-none",
|
|
8432
|
+
useTimePicker ? "h-auto" : "h-[364px]"
|
|
8264
8433
|
),
|
|
8265
|
-
|
|
8266
|
-
|
|
8267
|
-
|
|
8434
|
+
children: [
|
|
8435
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex items-center justify-center", children: [
|
|
8436
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-[var(--cmp-datepicker-calendar-gap)] text-[14px] font-medium leading-[24px]", children: [
|
|
8437
|
+
/* @__PURE__ */ jsxRuntime.jsx(SGhostButton, { icon: "chevronLeft", size: "xxs", ariaLabel: "prevYear", onClick: goPrevYear }),
|
|
8438
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex min-w-[40px] items-center justify-center text-center", children: y }),
|
|
8439
|
+
/* @__PURE__ */ jsxRuntime.jsx(SGhostButton, { icon: "chevronRight", size: "xxs", ariaLabel: "nextYear", onClick: goNextYear })
|
|
8440
|
+
] }),
|
|
8441
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8442
|
+
"button",
|
|
8443
|
+
{
|
|
8444
|
+
type: "button",
|
|
8445
|
+
onClick: goToday,
|
|
8446
|
+
className: "absolute right-0 h-[24px] min-w-[37px] cursor-pointer bg-transparent text-center text-[12px] font-medium leading-[24px] text-[color:var(--cmp-datepicker-calendar-day-default-text)] hover:underline",
|
|
8447
|
+
children: "\uC624\uB298"
|
|
8448
|
+
}
|
|
8449
|
+
)
|
|
8450
|
+
] }),
|
|
8451
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-[var(--cmp-datepicker-calendar-range-panelGap)]", children: [
|
|
8452
|
+
renderPanel(y, m, true),
|
|
8453
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8454
|
+
"span",
|
|
8455
|
+
{
|
|
8456
|
+
className: "w-px shrink-0 self-stretch bg-[var(--cmp-datepicker-calendar-range-divider)]",
|
|
8457
|
+
"aria-hidden": true
|
|
8458
|
+
}
|
|
8459
|
+
),
|
|
8460
|
+
renderPanel(nextMonthYM.year, nextMonthYM.month, false)
|
|
8461
|
+
] }),
|
|
8462
|
+
useTimePicker && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
8463
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8464
|
+
"span",
|
|
8465
|
+
{
|
|
8466
|
+
className: "h-px w-full bg-[var(--cmp-datepicker-calendar-range-divider)]",
|
|
8467
|
+
"aria-hidden": true
|
|
8468
|
+
}
|
|
8469
|
+
),
|
|
8470
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-[var(--cmp-datepicker-calendar-time-gap)]", children: [
|
|
8471
|
+
renderTimeSection("start", start, "\uBD80\uD130"),
|
|
8472
|
+
renderTimeSection("end", end, "\uAE4C\uC9C0")
|
|
8473
|
+
] })
|
|
8474
|
+
] })
|
|
8475
|
+
]
|
|
8476
|
+
}
|
|
8477
|
+
);
|
|
8268
8478
|
}
|
|
8269
8479
|
function SDateRangePicker({
|
|
8270
8480
|
value,
|
|
@@ -8274,6 +8484,7 @@ function SDateRangePicker({
|
|
|
8274
8484
|
placeholder = "YYYY-MM-DD ~ YYYY-MM-DD",
|
|
8275
8485
|
selectable,
|
|
8276
8486
|
maxRange,
|
|
8487
|
+
useTimePicker = false,
|
|
8277
8488
|
disabled = false,
|
|
8278
8489
|
width,
|
|
8279
8490
|
name,
|
|
@@ -8317,8 +8528,9 @@ function SDateRangePicker({
|
|
|
8317
8528
|
setPendingStart(null);
|
|
8318
8529
|
onValueChange?.(r);
|
|
8319
8530
|
if (rules && rules.length > 0) setRuleError(runRules(r, rules));
|
|
8320
|
-
setOpen(false);
|
|
8531
|
+
if (!useTimePicker) setOpen(false);
|
|
8321
8532
|
};
|
|
8533
|
+
const resolvedPlaceholder = useTimePicker && placeholder === "YYYY-MM-DD ~ YYYY-MM-DD" ? "YYYY-MM-DD HH:mm ~ YYYY-MM-DD HH:mm" : placeholder;
|
|
8322
8534
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8323
8535
|
SField,
|
|
8324
8536
|
{
|
|
@@ -8385,7 +8597,7 @@ function SDateRangePicker({
|
|
|
8385
8597
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate text-right", children: startText }),
|
|
8386
8598
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-[4px]", children: "~" }),
|
|
8387
8599
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate text-left", children: endText })
|
|
8388
|
-
] }) :
|
|
8600
|
+
] }) : resolvedPlaceholder
|
|
8389
8601
|
}
|
|
8390
8602
|
)
|
|
8391
8603
|
]
|
|
@@ -8404,6 +8616,7 @@ function SDateRangePicker({
|
|
|
8404
8616
|
value: value ?? null,
|
|
8405
8617
|
selectable,
|
|
8406
8618
|
maxRange,
|
|
8619
|
+
useTimePicker,
|
|
8407
8620
|
onSelect: select,
|
|
8408
8621
|
onPendingStartChange: setPendingStart,
|
|
8409
8622
|
onViewChange
|