sellmate-design-system-react 9.0.0-beta.25 → 9.0.0-beta.27
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/components/SChipFilter/README.md +15 -10
- package/dist/components/SChipFilter/SChipFilter.d.ts +18 -9
- package/dist/components/SGhostButton/README.md +0 -2
- package/dist/components/SSearchInput/README.md +2 -0
- package/dist/components/SSelect/README.md +1 -1
- package/dist/components/SSelect/SSelect.d.ts +1 -1
- package/dist/components/STable/README.md +16 -0
- package/dist/components/STable/STable.d.ts +12 -0
- package/dist/components/STable/index.d.ts +1 -1
- package/dist/index.cjs +413 -227
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +413 -227
- package/dist/index.js.map +1 -1
- package/dist/lib/floating-height.d.ts +15 -0
- package/dist/llms-full.txt +32 -11
- package/dist/styles.css +4 -6
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -10444,6 +10444,14 @@ var SStepper = /* @__PURE__ */ react.forwardRef(function SStepper2({
|
|
|
10444
10444
|
}
|
|
10445
10445
|
);
|
|
10446
10446
|
});
|
|
10447
|
+
|
|
10448
|
+
// src/lib/floating-height.ts
|
|
10449
|
+
var POPOVER_AVAILABLE_HEIGHT = "var(--radix-popover-content-available-height)";
|
|
10450
|
+
function clampToAvailableHeight(value, availableHeight) {
|
|
10451
|
+
if (value == null || value === "") return availableHeight;
|
|
10452
|
+
const css = typeof value === "number" ? `${value}px` : value;
|
|
10453
|
+
return `min(${css}, ${availableHeight})`;
|
|
10454
|
+
}
|
|
10447
10455
|
function runRules(value, rules) {
|
|
10448
10456
|
if (!rules || rules.length === 0) return "";
|
|
10449
10457
|
for (const rule of rules) {
|
|
@@ -10841,7 +10849,7 @@ var SSelectImpl = /* @__PURE__ */ react.forwardRef(function SSelect({
|
|
|
10841
10849
|
error = false,
|
|
10842
10850
|
rules,
|
|
10843
10851
|
labelTooltipProps,
|
|
10844
|
-
dropdownHeight = "
|
|
10852
|
+
dropdownHeight = "640px",
|
|
10845
10853
|
dropdownWidth,
|
|
10846
10854
|
maxDropdownWidth = "640px",
|
|
10847
10855
|
label,
|
|
@@ -11202,6 +11210,7 @@ var SSelectImpl = /* @__PURE__ */ react.forwardRef(function SSelect({
|
|
|
11202
11210
|
placement: "bottom",
|
|
11203
11211
|
align: "start",
|
|
11204
11212
|
offset: 4,
|
|
11213
|
+
viewportPadding: 24,
|
|
11205
11214
|
fit: !dropdownWidth,
|
|
11206
11215
|
onOpenAutoFocus: (event) => {
|
|
11207
11216
|
if (!showSearch) {
|
|
@@ -11234,7 +11243,7 @@ var SSelectImpl = /* @__PURE__ */ react.forwardRef(function SSelect({
|
|
|
11234
11243
|
SCROLLBAR_TRACK_BG_CLASS,
|
|
11235
11244
|
SCROLLBAR_TRACK_BORDER_CLASS
|
|
11236
11245
|
),
|
|
11237
|
-
style: { maxHeight: dropdownHeight },
|
|
11246
|
+
style: { maxHeight: clampToAvailableHeight(dropdownHeight, POPOVER_AVAILABLE_HEIGHT) },
|
|
11238
11247
|
onMouseLeave: () => setFocusedIndex(-1),
|
|
11239
11248
|
children: [
|
|
11240
11249
|
showSearch && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -11506,6 +11515,7 @@ var colWidthFromDef = (c) => {
|
|
|
11506
11515
|
};
|
|
11507
11516
|
var STable = /* @__PURE__ */ react.forwardRef(function STable2({
|
|
11508
11517
|
columns = [],
|
|
11518
|
+
headerGroups,
|
|
11509
11519
|
rows = [],
|
|
11510
11520
|
rowKey = "id",
|
|
11511
11521
|
selectable = false,
|
|
@@ -11553,6 +11563,49 @@ var STable = /* @__PURE__ */ react.forwardRef(function STable2({
|
|
|
11553
11563
|
onDenseChange?.(next);
|
|
11554
11564
|
};
|
|
11555
11565
|
const visibleCols = react.useMemo(() => columns.filter((c) => c.visible !== false), [columns]);
|
|
11566
|
+
const headerGroupInfo = react.useMemo(() => {
|
|
11567
|
+
if (!headerGroups || headerGroups.length === 0) return null;
|
|
11568
|
+
const indexByName = new Map(visibleCols.map((col, index) => [col.name, index]));
|
|
11569
|
+
const covered = /* @__PURE__ */ new Set();
|
|
11570
|
+
let previousLast = -1;
|
|
11571
|
+
const cells = headerGroups.map((group) => {
|
|
11572
|
+
if (group.columnNames.length === 0) {
|
|
11573
|
+
throw new Error("[STable] headerGroups\uC758 columnNames\uB294 \uBE44\uC5B4 \uC788\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
11574
|
+
}
|
|
11575
|
+
const indexes = group.columnNames.map((name) => {
|
|
11576
|
+
const index = indexByName.get(name);
|
|
11577
|
+
if (index == null) {
|
|
11578
|
+
throw new Error(`[STable] headerGroups\uC5D0 \uC874\uC7AC\uD558\uC9C0 \uC54A\uB294 \uCEEC\uB7FC\uC774 \uC9C0\uC815\uB418\uC5C8\uC2B5\uB2C8\uB2E4: ${name}`);
|
|
11579
|
+
}
|
|
11580
|
+
if (covered.has(name)) {
|
|
11581
|
+
throw new Error(`[STable] headerGroups\uC5D0\uC11C \uCEEC\uB7FC\uC774 \uC911\uBCF5 \uC9C0\uC815\uB418\uC5C8\uC2B5\uB2C8\uB2E4: ${name}`);
|
|
11582
|
+
}
|
|
11583
|
+
covered.add(name);
|
|
11584
|
+
return index;
|
|
11585
|
+
});
|
|
11586
|
+
const first = indexes[0];
|
|
11587
|
+
const last = indexes[indexes.length - 1];
|
|
11588
|
+
if (last - first + 1 !== indexes.length || indexes.some((index, i) => index !== first + i)) {
|
|
11589
|
+
throw new Error(
|
|
11590
|
+
"[STable] headerGroups\uC758 columnNames\uB294 \uC778\uC811\uD55C \uCEEC\uB7FC \uC21C\uC11C\uB85C \uC9C0\uC815\uD574\uC57C \uD569\uB2C8\uB2E4."
|
|
11591
|
+
);
|
|
11592
|
+
}
|
|
11593
|
+
if (first <= previousLast) {
|
|
11594
|
+
throw new Error("[STable] headerGroups\uB294 \uCEEC\uB7FC \uC21C\uC11C\uB300\uB85C \uC9C0\uC815\uD574\uC57C \uD569\uB2C8\uB2E4.");
|
|
11595
|
+
}
|
|
11596
|
+
previousLast = last;
|
|
11597
|
+
return { ...group, firstIndex: first, colSpan: indexes.length };
|
|
11598
|
+
});
|
|
11599
|
+
if (covered.size !== visibleCols.length) {
|
|
11600
|
+
throw new Error("[STable] headerGroups\uC758 columnNames\uAC00 \uBAA8\uB4E0 visible \uCEEC\uB7FC\uC744 \uD3EC\uD568\uD574\uC57C \uD569\uB2C8\uB2E4.");
|
|
11601
|
+
}
|
|
11602
|
+
return {
|
|
11603
|
+
cells,
|
|
11604
|
+
rowSpanNames: new Set(
|
|
11605
|
+
cells.filter((cell) => cell.rowSpan === 2).flatMap((cell) => cell.columnNames)
|
|
11606
|
+
)
|
|
11607
|
+
};
|
|
11608
|
+
}, [headerGroups, visibleCols]);
|
|
11556
11609
|
const stickyLeft = stickyColumn?.left ?? 0;
|
|
11557
11610
|
const stickyRight = stickyColumn?.right ?? 0;
|
|
11558
11611
|
const effectiveRowHeight = rowHeight ?? (innerDense ? DENSE_ROW_HEIGHT : DEFAULT_ROW_HEIGHT);
|
|
@@ -11815,6 +11868,35 @@ var STable = /* @__PURE__ */ react.forwardRef(function STable2({
|
|
|
11815
11868
|
isRightEdge && scrolledRight && "shadow-[-5px_0_8px_0_rgba(34,34,34,0.1)]"
|
|
11816
11869
|
);
|
|
11817
11870
|
};
|
|
11871
|
+
const headerResizeHitArea = (i, key) => {
|
|
11872
|
+
const col = visibleCols[i];
|
|
11873
|
+
if (!headerGroupInfo || !resizable || !col || col.autoWidth || i >= visibleCols.length - 1) {
|
|
11874
|
+
return null;
|
|
11875
|
+
}
|
|
11876
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
11877
|
+
"span",
|
|
11878
|
+
{
|
|
11879
|
+
onMouseDown: (e) => startResize(i, e),
|
|
11880
|
+
className: "absolute inset-y-0 right-0 z-[5] w-[9px] cursor-col-resize",
|
|
11881
|
+
"aria-hidden": true
|
|
11882
|
+
},
|
|
11883
|
+
key
|
|
11884
|
+
);
|
|
11885
|
+
};
|
|
11886
|
+
const headerResizer = (i, key) => {
|
|
11887
|
+
const col = visibleCols[i];
|
|
11888
|
+
if (!resizable || !col || col.autoWidth || i >= visibleCols.length - 1) return null;
|
|
11889
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
11890
|
+
"span",
|
|
11891
|
+
{
|
|
11892
|
+
onMouseDown: (e) => startResize(i, e),
|
|
11893
|
+
className: "absolute right-0 top-1/2 z-[5] flex h-[16px] w-[9px] -translate-y-1/2 cursor-col-resize items-center justify-end",
|
|
11894
|
+
"aria-hidden": true,
|
|
11895
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-full w-[4px] border-x border-solid border-[color:var(--cmp-table-header-resizingBar-color)]" })
|
|
11896
|
+
},
|
|
11897
|
+
key
|
|
11898
|
+
);
|
|
11899
|
+
};
|
|
11818
11900
|
const bodyScrollClass = cn(
|
|
11819
11901
|
"min-h-0 flex-1 overflow-auto border-t border-solid border-[color:var(--cmp-table-border-color)]",
|
|
11820
11902
|
SCROLLBAR_CLASS,
|
|
@@ -11879,145 +11961,179 @@ var STable = /* @__PURE__ */ react.forwardRef(function STable2({
|
|
|
11879
11961
|
style: { fontSize: 12 },
|
|
11880
11962
|
children: [
|
|
11881
11963
|
colgroup,
|
|
11882
|
-
/* @__PURE__ */ jsxRuntime.
|
|
11883
|
-
|
|
11884
|
-
|
|
11885
|
-
|
|
11886
|
-
|
|
11887
|
-
|
|
11888
|
-
|
|
11889
|
-
|
|
11890
|
-
|
|
11891
|
-
|
|
11892
|
-
|
|
11893
|
-
|
|
11894
|
-
|
|
11895
|
-
|
|
11964
|
+
/* @__PURE__ */ jsxRuntime.jsxs("thead", { className: cn(isNoData && "opacity-40"), children: [
|
|
11965
|
+
headerGroupInfo && /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "h-[var(--cmp-table-header-height)] bg-[var(--cmp-table-header-bg)]", children: [
|
|
11966
|
+
selectable && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11967
|
+
"th",
|
|
11968
|
+
{
|
|
11969
|
+
rowSpan: 2,
|
|
11970
|
+
className: cn(
|
|
11971
|
+
"sticky left-0 z-[7] bg-[var(--cmp-table-header-bg)] text-center align-middle",
|
|
11972
|
+
stickyLeft === 0 && scrolledLeft && "shadow-[5px_0_8px_0_rgba(34,34,34,0.1)]"
|
|
11973
|
+
),
|
|
11974
|
+
style: {
|
|
11975
|
+
width: SELECTABLE_COLUMN_WIDTH,
|
|
11976
|
+
minWidth: SELECTABLE_COLUMN_WIDTH,
|
|
11977
|
+
maxWidth: SELECTABLE_COLUMN_WIDTH
|
|
11978
|
+
},
|
|
11979
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(SCheckbox, { value: headerCheck, onValueChange: toggleAll }) })
|
|
11980
|
+
}
|
|
11981
|
+
),
|
|
11982
|
+
headerGroupInfo.cells.map((group) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11983
|
+
"th",
|
|
11984
|
+
{
|
|
11985
|
+
colSpan: group.colSpan,
|
|
11986
|
+
rowSpan: group.rowSpan,
|
|
11987
|
+
className: cn(
|
|
11988
|
+
"relative border-b border-r border-solid border-[color:var(--cmp-table-border-color)] bg-[var(--cmp-table-header-bg)] px-[16px] text-[12px] font-medium leading-[20px] text-[color:var(--sys-color-fg-primary)]",
|
|
11989
|
+
group.firstIndex + group.colSpan === visibleCols.length && "border-r-0",
|
|
11990
|
+
group.rowSpan === 2 && "border-b-0",
|
|
11991
|
+
group.className
|
|
11992
|
+
),
|
|
11993
|
+
style: { textAlign: group.align ?? "left", ...group.style },
|
|
11994
|
+
children: [
|
|
11995
|
+
group.render ? group.render() : group.label,
|
|
11996
|
+
group.rowSpan === 2 && group.colSpan === 1 ? headerResizeHitArea(
|
|
11997
|
+
group.firstIndex,
|
|
11998
|
+
`group-resizer-${group.columnNames[0]}`
|
|
11999
|
+
) : null
|
|
12000
|
+
]
|
|
11896
12001
|
},
|
|
11897
|
-
|
|
11898
|
-
|
|
11899
|
-
|
|
11900
|
-
|
|
11901
|
-
|
|
11902
|
-
"aria-hidden": true,
|
|
11903
|
-
className: "pointer-events-none absolute right-0 top-1/2 h-[16px] w-px -translate-y-1/2 bg-[var(--cmp-table-header-resizingBar-color)]"
|
|
11904
|
-
}
|
|
11905
|
-
)
|
|
11906
|
-
]
|
|
11907
|
-
}
|
|
11908
|
-
),
|
|
11909
|
-
visibleCols.map((col, i) => {
|
|
11910
|
-
const isSortable = !!col.sortable && !col.renderHeader;
|
|
11911
|
-
const sortDir = isSortable && sort?.name === col.name ? sort.dir : void 0;
|
|
11912
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12002
|
+
group.columnNames.join("|")
|
|
12003
|
+
))
|
|
12004
|
+
] }),
|
|
12005
|
+
/* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "h-[var(--cmp-table-header-height)] bg-[var(--cmp-table-header-bg)]", children: [
|
|
12006
|
+
selectable && !headerGroupInfo && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11913
12007
|
"th",
|
|
11914
12008
|
{
|
|
11915
12009
|
className: cn(
|
|
11916
|
-
//
|
|
11917
|
-
//
|
|
11918
|
-
|
|
11919
|
-
|
|
11920
|
-
// 세로 가운데도 어긋난다. 글자 줄높이는 아래 th__content 가 다시 준다.
|
|
11921
|
-
"relative bg-[var(--cmp-table-header-bg)] px-[16px] text-[12px] font-medium leading-[0] text-[color:var(--sys-color-fg-primary)]",
|
|
11922
|
-
stickyInfo(i).isSticky && "z-[6]",
|
|
11923
|
-
stickyShadowClass(i),
|
|
11924
|
-
col.thClass
|
|
12010
|
+
// 원본 .th--selected: 48px 고정폭, 항상 left sticky, 체크박스 중앙정렬
|
|
12011
|
+
// 하단 border는 헤더 래퍼가 연속으로 그리므로 셀에는 두지 않는다.
|
|
12012
|
+
"sticky left-0 z-[7] bg-[var(--cmp-table-header-bg)] text-center align-middle",
|
|
12013
|
+
stickyLeft === 0 && scrolledLeft && "shadow-[5px_0_8px_0_rgba(34,34,34,0.1)]"
|
|
11925
12014
|
),
|
|
11926
|
-
style: {
|
|
11927
|
-
|
|
12015
|
+
style: {
|
|
12016
|
+
width: SELECTABLE_COLUMN_WIDTH,
|
|
12017
|
+
minWidth: SELECTABLE_COLUMN_WIDTH,
|
|
12018
|
+
maxWidth: SELECTABLE_COLUMN_WIDTH
|
|
12019
|
+
},
|
|
11928
12020
|
children: [
|
|
12021
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(SCheckbox, { value: headerCheck, onValueChange: toggleAll }) }),
|
|
11929
12022
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11930
12023
|
"span",
|
|
11931
12024
|
{
|
|
11932
|
-
className: cn(
|
|
11933
|
-
// 원본 th__content: align에 따라 justify-content 적용 (th도 정렬 반영)
|
|
11934
|
-
// th 가 leading-[0] 이므로 글자 줄높이는 여기서 준다 (truncate 가
|
|
11935
|
-
// overflow-hidden 이라 줄높이가 0이면 라벨이 잘려 사라진다).
|
|
11936
|
-
"inline-flex w-full min-w-0 items-center gap-[4px] leading-[20px]",
|
|
11937
|
-
col.align === "center" && "justify-center",
|
|
11938
|
-
col.align === "right" && "justify-end"
|
|
11939
|
-
),
|
|
11940
|
-
children: col.renderHeader ? col.renderHeader(col, i) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
11941
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: col.label }),
|
|
11942
|
-
col.helpText && col.helpText.length > 0 && // 라벨이 좁아져 truncate 되더라도 아이콘까지 함께 줄어들면 안 되므로
|
|
11943
|
-
// shrink-0 래퍼로 감싼다 (STooltip 의 className 은 본문 쪽으로 간다).
|
|
11944
|
-
// 아이콘·크기·색은 SKeyValueTable 헤더 도움말과 동일하게 맞춘다.
|
|
11945
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
11946
|
-
STooltip2,
|
|
11947
|
-
{
|
|
11948
|
-
trigger: "hover",
|
|
11949
|
-
icon: "helpOutline",
|
|
11950
|
-
iconSize: 12,
|
|
11951
|
-
color: "var(--sys-color-fg-success)",
|
|
11952
|
-
placement: "top",
|
|
11953
|
-
message: col.helpText
|
|
11954
|
-
}
|
|
11955
|
-
) }),
|
|
11956
|
-
col.editable && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11957
|
-
SIcon,
|
|
11958
|
-
{
|
|
11959
|
-
name: "pageEdit",
|
|
11960
|
-
size: 12,
|
|
11961
|
-
color: "var(--sys-color-link-accent)",
|
|
11962
|
-
label: "\uC218\uC815 \uAC00\uB2A5",
|
|
11963
|
-
className: "shrink-0"
|
|
11964
|
-
}
|
|
11965
|
-
),
|
|
11966
|
-
col.navigable && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11967
|
-
SIcon,
|
|
11968
|
-
{
|
|
11969
|
-
name: "pageMove",
|
|
11970
|
-
size: 12,
|
|
11971
|
-
color: "var(--sys-color-link-accent)",
|
|
11972
|
-
label: "\uB2E4\uB978 \uD654\uBA74\uC73C\uB85C \uC774\uB3D9",
|
|
11973
|
-
className: "shrink-0"
|
|
11974
|
-
}
|
|
11975
|
-
),
|
|
11976
|
-
col.required && // 라벨이 truncate 돼도 필수 표시는 남아야 하므로 shrink-0.
|
|
11977
|
-
// 아이콘·크기·색은 SKeyValueTable 헤더 필수 표시와 동일하게 맞춘다.
|
|
11978
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11979
|
-
SIcon,
|
|
11980
|
-
{
|
|
11981
|
-
name: "asterisk",
|
|
11982
|
-
size: 12,
|
|
11983
|
-
color: "var(--sys-color-fg-accent)",
|
|
11984
|
-
className: "shrink-0"
|
|
11985
|
-
}
|
|
11986
|
-
),
|
|
11987
|
-
isSortable && // 미정렬은 updown 을 default(회색)로 — 정렬할 수 있다는 것 자체가
|
|
11988
|
-
// 헤더에 보여야 한다. 정렬 중이면 action 색으로 올려 활성임을 알린다.
|
|
11989
|
-
// 라벨이 truncate 돼도 버튼은 남도록 shrink-0.
|
|
11990
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
11991
|
-
SGhostButton,
|
|
11992
|
-
{
|
|
11993
|
-
size: "xxs",
|
|
11994
|
-
intent: sortDir ? "action" : "default",
|
|
11995
|
-
icon: sortDir === "asc" ? "arrowUp" : sortDir === "desc" ? "arrowDown" : "updown",
|
|
11996
|
-
ariaLabel: `${col.label} \uC815\uB82C`,
|
|
11997
|
-
onClick: () => toggleSort(col)
|
|
11998
|
-
}
|
|
11999
|
-
) })
|
|
12000
|
-
] })
|
|
12001
|
-
}
|
|
12002
|
-
),
|
|
12003
|
-
resizable && !col.autoWidth && i < visibleCols.length - 1 && // 원본 th__resizer: 셀 우측 경계 안쪽 4px 그립(좌우 1px #CCCCCC 라인, 세로 16px).
|
|
12004
|
-
// 셀 밖으로 넘치면 다음 셀에 가려져 클릭이 안 먹으므로 translate 없이 셀 내부에 배치.
|
|
12005
|
-
// 겉보기 그립은 4px(원본과 동일), 클릭 영역은 9px로 넓혀 사용성 확보.
|
|
12006
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12007
|
-
"span",
|
|
12008
|
-
{
|
|
12009
|
-
onMouseDown: (e) => startResize(i, e),
|
|
12010
|
-
className: "absolute right-0 top-1/2 z-[5] flex h-[16px] w-[9px] -translate-y-1/2 cursor-col-resize items-center justify-end",
|
|
12011
12025
|
"aria-hidden": true,
|
|
12012
|
-
|
|
12026
|
+
className: "pointer-events-none absolute right-0 top-1/2 h-[16px] w-px -translate-y-1/2 bg-[var(--cmp-table-header-resizingBar-color)]"
|
|
12013
12027
|
}
|
|
12014
12028
|
)
|
|
12015
12029
|
]
|
|
12016
|
-
}
|
|
12017
|
-
|
|
12018
|
-
)
|
|
12019
|
-
|
|
12020
|
-
|
|
12030
|
+
}
|
|
12031
|
+
),
|
|
12032
|
+
visibleCols.map((col, i) => {
|
|
12033
|
+
if (headerGroupInfo?.rowSpanNames.has(col.name)) return null;
|
|
12034
|
+
const isSortable = !!col.sortable && !col.renderHeader;
|
|
12035
|
+
const sortDir = isSortable && sort?.name === col.name ? sort.dir : void 0;
|
|
12036
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12037
|
+
"th",
|
|
12038
|
+
{
|
|
12039
|
+
className: cn(
|
|
12040
|
+
// 하단 border는 헤더 래퍼가 연속으로 그린다 (거터 영역까지 이어짐).
|
|
12041
|
+
// leading-[0]: th 의 스트럿(line-height 만큼의 빈 인라인 박스)을 없앤다.
|
|
12042
|
+
// 내용이 inline-flex 라 스트럿이 남아 있으면 라벨보다 큰 컨트롤(정렬 버튼 등)이
|
|
12043
|
+
// 들어올 때 줄 상자가 베이스라인 기준으로 늘어나 헤더 높이를 넘기고
|
|
12044
|
+
// 세로 가운데도 어긋난다. 글자 줄높이는 아래 th__content 가 다시 준다.
|
|
12045
|
+
headerGroupInfo && "border-r border-solid border-[color:var(--cmp-table-border-color)]",
|
|
12046
|
+
headerGroupInfo && i === visibleCols.length - 1 && "border-r-0",
|
|
12047
|
+
"relative bg-[var(--cmp-table-header-bg)] px-[16px] text-[12px] font-medium leading-[0] text-[color:var(--sys-color-fg-primary)]",
|
|
12048
|
+
stickyInfo(i).isSticky && "z-[6]",
|
|
12049
|
+
stickyShadowClass(i),
|
|
12050
|
+
col.thClass
|
|
12051
|
+
),
|
|
12052
|
+
style: { textAlign: col.align ?? "left", ...cellStyle(i), ...col.thStyle },
|
|
12053
|
+
"aria-sort": isSortable ? sortDir === "asc" ? "ascending" : sortDir === "desc" ? "descending" : "none" : void 0,
|
|
12054
|
+
children: [
|
|
12055
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12056
|
+
"span",
|
|
12057
|
+
{
|
|
12058
|
+
className: cn(
|
|
12059
|
+
// 원본 th__content: align에 따라 justify-content 적용 (th도 정렬 반영)
|
|
12060
|
+
// th 가 leading-[0] 이므로 글자 줄높이는 여기서 준다 (truncate 가
|
|
12061
|
+
// overflow-hidden 이라 줄높이가 0이면 라벨이 잘려 사라진다).
|
|
12062
|
+
"inline-flex w-full min-w-0 items-center gap-[4px] leading-[20px]",
|
|
12063
|
+
col.align === "center" && "justify-center",
|
|
12064
|
+
col.align === "right" && "justify-end"
|
|
12065
|
+
),
|
|
12066
|
+
children: col.renderHeader ? col.renderHeader(col, i) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
12067
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: col.label }),
|
|
12068
|
+
col.helpText && col.helpText.length > 0 && // 라벨이 좁아져 truncate 되더라도 아이콘까지 함께 줄어들면 안 되므로
|
|
12069
|
+
// shrink-0 래퍼로 감싼다 (STooltip 의 className 은 본문 쪽으로 간다).
|
|
12070
|
+
// 아이콘·크기·색은 SKeyValueTable 헤더 도움말과 동일하게 맞춘다.
|
|
12071
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12072
|
+
STooltip2,
|
|
12073
|
+
{
|
|
12074
|
+
trigger: "hover",
|
|
12075
|
+
icon: "helpOutline",
|
|
12076
|
+
iconSize: 12,
|
|
12077
|
+
color: "var(--sys-color-fg-success)",
|
|
12078
|
+
placement: "top",
|
|
12079
|
+
message: col.helpText
|
|
12080
|
+
}
|
|
12081
|
+
) }),
|
|
12082
|
+
col.editable && /* @__PURE__ */ jsxRuntime.jsx(
|
|
12083
|
+
SIcon,
|
|
12084
|
+
{
|
|
12085
|
+
name: "pageEdit",
|
|
12086
|
+
size: 12,
|
|
12087
|
+
color: "var(--sys-color-link-accent)",
|
|
12088
|
+
label: "\uC218\uC815 \uAC00\uB2A5",
|
|
12089
|
+
className: "shrink-0"
|
|
12090
|
+
}
|
|
12091
|
+
),
|
|
12092
|
+
col.navigable && /* @__PURE__ */ jsxRuntime.jsx(
|
|
12093
|
+
SIcon,
|
|
12094
|
+
{
|
|
12095
|
+
name: "pageMove",
|
|
12096
|
+
size: 12,
|
|
12097
|
+
color: "var(--sys-color-link-accent)",
|
|
12098
|
+
label: "\uB2E4\uB978 \uD654\uBA74\uC73C\uB85C \uC774\uB3D9",
|
|
12099
|
+
className: "shrink-0"
|
|
12100
|
+
}
|
|
12101
|
+
),
|
|
12102
|
+
col.required && // 라벨이 truncate 돼도 필수 표시는 남아야 하므로 shrink-0.
|
|
12103
|
+
// 아이콘·크기·색은 SKeyValueTable 헤더 필수 표시와 동일하게 맞춘다.
|
|
12104
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12105
|
+
SIcon,
|
|
12106
|
+
{
|
|
12107
|
+
name: "asterisk",
|
|
12108
|
+
size: 12,
|
|
12109
|
+
color: "var(--sys-color-fg-accent)",
|
|
12110
|
+
className: "shrink-0"
|
|
12111
|
+
}
|
|
12112
|
+
),
|
|
12113
|
+
isSortable && // 미정렬은 updown 을 default(회색)로 — 정렬할 수 있다는 것 자체가
|
|
12114
|
+
// 헤더에 보여야 한다. 정렬 중이면 action 색으로 올려 활성임을 알린다.
|
|
12115
|
+
// 라벨이 truncate 돼도 버튼은 남도록 shrink-0.
|
|
12116
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12117
|
+
SGhostButton,
|
|
12118
|
+
{
|
|
12119
|
+
size: "xxs",
|
|
12120
|
+
intent: sortDir ? "action" : "default",
|
|
12121
|
+
icon: sortDir === "asc" ? "arrowUp" : sortDir === "desc" ? "arrowDown" : "updown",
|
|
12122
|
+
ariaLabel: `${col.label} \uC815\uB82C`,
|
|
12123
|
+
onClick: () => toggleSort(col)
|
|
12124
|
+
}
|
|
12125
|
+
) })
|
|
12126
|
+
] })
|
|
12127
|
+
}
|
|
12128
|
+
),
|
|
12129
|
+
headerGroupInfo ? headerResizeHitArea(i, `resizer-${col.name}`) : headerResizer(i, `resizer-${col.name}`)
|
|
12130
|
+
]
|
|
12131
|
+
},
|
|
12132
|
+
col.name
|
|
12133
|
+
);
|
|
12134
|
+
})
|
|
12135
|
+
] })
|
|
12136
|
+
] })
|
|
12021
12137
|
]
|
|
12022
12138
|
}
|
|
12023
12139
|
)
|
|
@@ -17280,6 +17396,8 @@ var SEditor = /* @__PURE__ */ react.forwardRef(function SEditor2({
|
|
|
17280
17396
|
});
|
|
17281
17397
|
var CHIPFILTER_LISTBOX_WIDTH = 240;
|
|
17282
17398
|
var CHIPFILTER_DATE_PRESET_LISTBOX_WIDTH = 246;
|
|
17399
|
+
var EDITOR_LISTBOX_MAX_HEIGHT = "min(640px, var(--radix-popover-content-available-height))";
|
|
17400
|
+
var EDITOR_POPOVER_VIEWPORT_PADDING = 24;
|
|
17283
17401
|
var CHIPFILTER = {
|
|
17284
17402
|
barBg: "var(--cmp-chipFilter-bar-bg)",
|
|
17285
17403
|
barBorder: "var(--cmp-chipFilter-bar-border)",
|
|
@@ -17319,6 +17437,7 @@ var CHIPFILTER = {
|
|
|
17319
17437
|
itemTextDefault: "var(--cmp-chipFilter-item-text-default)",
|
|
17320
17438
|
itemTextSelected: "var(--cmp-chipFilter-item-text-selected)"
|
|
17321
17439
|
};
|
|
17440
|
+
var DEFAULT_CUSTOM_MAX_RANGE = 90;
|
|
17322
17441
|
var DEFAULT_PERIOD_PRESETS = [
|
|
17323
17442
|
{ value: "day", label: "\uC77C\uBCC4" },
|
|
17324
17443
|
{ value: "month", label: "\uC6D4\uBCC4" },
|
|
@@ -17327,6 +17446,20 @@ var DEFAULT_PERIOD_PRESETS = [
|
|
|
17327
17446
|
{ value: "year", label: "\uC5F0\uB3C4\uBCC4" },
|
|
17328
17447
|
{ value: "custom", label: "\uC0AC\uC6A9\uC790 \uC9C0\uC815", custom: true }
|
|
17329
17448
|
];
|
|
17449
|
+
var DEFAULT_DATE_RANGE_PRESETS = [
|
|
17450
|
+
{ value: "today", label: "\uC624\uB298", resolve: () => todayIso() },
|
|
17451
|
+
{
|
|
17452
|
+
value: "last7",
|
|
17453
|
+
label: "\uC9C0\uB09C 7\uC77C",
|
|
17454
|
+
resolve: () => [addDaysIso(todayIso(), -7), todayIso()]
|
|
17455
|
+
},
|
|
17456
|
+
{
|
|
17457
|
+
value: "last30",
|
|
17458
|
+
label: "\uC9C0\uB09C 30\uC77C",
|
|
17459
|
+
resolve: () => [addDaysIso(todayIso(), -30), todayIso()]
|
|
17460
|
+
},
|
|
17461
|
+
{ value: "custom", label: "\uC0AC\uC6A9\uC790 \uC9C0\uC815", custom: true }
|
|
17462
|
+
];
|
|
17330
17463
|
var isKeywordValue = (value) => typeof value === "object" && value != null && !Array.isArray(value) && "keywords" in value;
|
|
17331
17464
|
var isPeriodValue = (value) => typeof value === "object" && value != null && !Array.isArray(value) && "unit" in value;
|
|
17332
17465
|
var keywordEntries = (value) => {
|
|
@@ -17351,23 +17484,39 @@ var todayIso = () => {
|
|
|
17351
17484
|
const pad = (n) => String(n).padStart(2, "0");
|
|
17352
17485
|
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
|
|
17353
17486
|
};
|
|
17487
|
+
var addDaysIso = (iso, n) => {
|
|
17488
|
+
const d = /* @__PURE__ */ new Date(`${iso}T00:00:00`);
|
|
17489
|
+
d.setDate(d.getDate() + n);
|
|
17490
|
+
const pad = (v) => String(v).padStart(2, "0");
|
|
17491
|
+
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
|
|
17492
|
+
};
|
|
17354
17493
|
var isInlineDateField = (field) => field.type === "datepicker-range" && field.radioButton === true && (field.presets?.length ?? 0) > 0;
|
|
17355
17494
|
var getFieldPresets = (field) => {
|
|
17356
17495
|
if (field.type === "datepicker-statistics") return field.presets ?? DEFAULT_PERIOD_PRESETS;
|
|
17357
|
-
return field.presets ??
|
|
17496
|
+
return field.presets ?? DEFAULT_DATE_RANGE_PRESETS;
|
|
17497
|
+
};
|
|
17498
|
+
var getEffectiveMaxRange = (field) => {
|
|
17499
|
+
if (field.maxRange !== void 0) return field.maxRange;
|
|
17500
|
+
const hasCustomPreset = getFieldPresets(field).some((preset) => preset.custom);
|
|
17501
|
+
return hasCustomPreset ? DEFAULT_CUSTOM_MAX_RANGE : void 0;
|
|
17358
17502
|
};
|
|
17359
|
-
var
|
|
17503
|
+
var getPresetLabel = (preset, maxRange) => {
|
|
17504
|
+
if (!preset.custom || !maxRange || preset.label.includes("\uCD5C\uB300")) return preset.label;
|
|
17505
|
+
return `${preset.label} (\uCD5C\uB300 ${maxRange}\uC77C\uC529)`;
|
|
17506
|
+
};
|
|
17507
|
+
var getDefaultPeriodInputValue = (unit, maxRange) => {
|
|
17360
17508
|
const today = todayIso();
|
|
17361
17509
|
if (unit === "day") return today;
|
|
17362
17510
|
if (unit === "month") return today.slice(0, 7);
|
|
17363
17511
|
if (unit === "quarter") return 1;
|
|
17364
17512
|
if (unit === "half") return "first";
|
|
17365
17513
|
if (unit === "year") return today.slice(0, 4);
|
|
17366
|
-
|
|
17514
|
+
const days = maxRange && maxRange > 0 ? maxRange : DEFAULT_CUSTOM_MAX_RANGE;
|
|
17515
|
+
return [addDaysIso(today, -days), today];
|
|
17367
17516
|
};
|
|
17368
|
-
var createPeriodValue = (unit) => ({
|
|
17517
|
+
var createPeriodValue = (unit, maxRange) => ({
|
|
17369
17518
|
unit,
|
|
17370
|
-
value: getDefaultPeriodInputValue(unit)
|
|
17519
|
+
value: getDefaultPeriodInputValue(unit, maxRange)
|
|
17371
17520
|
});
|
|
17372
17521
|
var resolveFieldDefault = (field) => {
|
|
17373
17522
|
if (field.defaultValue !== void 0 && isFixedField(field)) return field.defaultValue;
|
|
@@ -17380,7 +17529,8 @@ var resolveFieldDefault = (field) => {
|
|
|
17380
17529
|
if (field.type === "datepicker-day") return todayIso();
|
|
17381
17530
|
if (field.type === "select") return field.options?.[0]?.value;
|
|
17382
17531
|
if (field.type === "datepicker-statistics") {
|
|
17383
|
-
const
|
|
17532
|
+
const presets = getFieldPresets(field).filter((preset) => !preset.custom);
|
|
17533
|
+
const unit = presets.some((preset) => preset.value === "day") ? "day" : presets[0]?.value;
|
|
17384
17534
|
return unit ? createPeriodValue(unit) : void 0;
|
|
17385
17535
|
}
|
|
17386
17536
|
return void 0;
|
|
@@ -17510,8 +17660,7 @@ var SChipFilter = /* @__PURE__ */ react.forwardRef(function SChipFilter2({
|
|
|
17510
17660
|
onActiveKeysChange,
|
|
17511
17661
|
onReset,
|
|
17512
17662
|
onAddFilter,
|
|
17513
|
-
label
|
|
17514
|
-
showLabel = false,
|
|
17663
|
+
label,
|
|
17515
17664
|
showReset = true,
|
|
17516
17665
|
disabled = false,
|
|
17517
17666
|
className,
|
|
@@ -17528,6 +17677,7 @@ var SChipFilter = /* @__PURE__ */ react.forwardRef(function SChipFilter2({
|
|
|
17528
17677
|
const pendingOpenKeyRef = react.useRef(null);
|
|
17529
17678
|
const triggerRefs = react.useRef(/* @__PURE__ */ new Map());
|
|
17530
17679
|
const initializedDefaultsRef = react.useRef(/* @__PURE__ */ new Set());
|
|
17680
|
+
const misuseWarningSignatureRef = react.useRef(null);
|
|
17531
17681
|
const prevOpenKeyRef = react.useRef(null);
|
|
17532
17682
|
const valuesRef = react.useRef(values);
|
|
17533
17683
|
valuesRef.current = values;
|
|
@@ -17543,14 +17693,19 @@ var SChipFilter = /* @__PURE__ */ react.forwardRef(function SChipFilter2({
|
|
|
17543
17693
|
(current) => groups.every((group) => isGroupSatisfied(group, current)),
|
|
17544
17694
|
[groups]
|
|
17545
17695
|
);
|
|
17696
|
+
const isRequiredSatisfied = react.useCallback(
|
|
17697
|
+
(current) => fields.every((field) => !field.required || !isEmptyValue(current[field.key])),
|
|
17698
|
+
[fields]
|
|
17699
|
+
);
|
|
17546
17700
|
const runSearch = react.useCallback(
|
|
17547
17701
|
(next) => {
|
|
17548
17702
|
if (valuesMapEqual(lastSearchedValuesRef.current, next)) return;
|
|
17549
17703
|
if (!isGroupsValid(next)) return;
|
|
17704
|
+
if (!isRequiredSatisfied(next)) return;
|
|
17550
17705
|
lastSearchedValuesRef.current = next;
|
|
17551
17706
|
onSearch?.(next);
|
|
17552
17707
|
},
|
|
17553
|
-
[isGroupsValid, onSearch]
|
|
17708
|
+
[isGroupsValid, isRequiredSatisfied, onSearch]
|
|
17554
17709
|
);
|
|
17555
17710
|
react.useEffect(() => {
|
|
17556
17711
|
const prevKey = prevOpenKeyRef.current;
|
|
@@ -17585,14 +17740,24 @@ var SChipFilter = /* @__PURE__ */ react.forwardRef(function SChipFilter2({
|
|
|
17585
17740
|
});
|
|
17586
17741
|
if (changed) onValueChange?.({ ...values, ...patch });
|
|
17587
17742
|
}, [fields, values, onValueChange]);
|
|
17588
|
-
|
|
17589
|
-
|
|
17590
|
-
|
|
17743
|
+
react.useEffect(() => {
|
|
17744
|
+
if (typeof console === "undefined") return;
|
|
17745
|
+
const misusedKeys = fields.filter((f) => f.defaultValue !== void 0 && !isFixedField(f)).map((f) => f.key);
|
|
17746
|
+
const requiredWithoutDefaultKeys = fields.filter((f) => f.required === true && resolveFieldDefault(f) === void 0).map((f) => f.key);
|
|
17747
|
+
const signature = JSON.stringify([misusedKeys, requiredWithoutDefaultKeys]);
|
|
17748
|
+
if (signature === misuseWarningSignatureRef.current) return;
|
|
17749
|
+
misuseWarningSignatureRef.current = signature;
|
|
17750
|
+
if (misusedKeys.length > 0) {
|
|
17591
17751
|
console.warn(
|
|
17592
|
-
`[SChipFilter] defaultValue \uB294 fixed\xB7required \uD544\uD130\uC5D0\uC11C\uB9CC \uC4F8 \uC218 \uC788\uC2B5\uB2C8\uB2E4. \uBB34\uC2DC\uD569\uB2C8\uB2E4. (${
|
|
17752
|
+
`[SChipFilter] defaultValue \uB294 fixed\xB7required \uD544\uD130\uC5D0\uC11C\uB9CC \uC4F8 \uC218 \uC788\uC2B5\uB2C8\uB2E4. \uBB34\uC2DC\uD569\uB2C8\uB2E4. (${misusedKeys.join(", ")})`
|
|
17593
17753
|
);
|
|
17594
17754
|
}
|
|
17595
|
-
|
|
17755
|
+
if (requiredWithoutDefaultKeys.length > 0) {
|
|
17756
|
+
console.warn(
|
|
17757
|
+
`[SChipFilter] required \uD544\uD130\uC5D0 defaultValue \uAC00 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 \uC774 \uD0C0\uC785\uC740 \uB0B4\uC7A5 \uAE30\uBCF8\uAC12\uC774 \uC5C6\uC5B4 "\uAC80\uC0C9 \uCD08\uAE30\uD654" \uC2DC \uAC12\uC774 \uBE44\uC6CC\uC9C0\uACE0 \uAC80\uC0C9\uB3C4 \uB9C9\uD799\uB2C8\uB2E4. defaultValue \uB97C \uC9C0\uC815\uD558\uC138\uC694. (${requiredWithoutDefaultKeys.join(", ")})`
|
|
17758
|
+
);
|
|
17759
|
+
}
|
|
17760
|
+
}, [fields]);
|
|
17596
17761
|
const fixedKeys = fields.filter(isFixedField).map((field) => field.key);
|
|
17597
17762
|
const resolvedActiveKeys = Array.from(
|
|
17598
17763
|
/* @__PURE__ */ new Set([...activeKeys ?? internalActiveKeys, ...fixedKeys])
|
|
@@ -17660,7 +17825,10 @@ var SChipFilter = /* @__PURE__ */ react.forwardRef(function SChipFilter2({
|
|
|
17660
17825
|
},
|
|
17661
17826
|
[fields]
|
|
17662
17827
|
);
|
|
17663
|
-
const validate = react.useCallback(
|
|
17828
|
+
const validate = react.useCallback(
|
|
17829
|
+
() => invalidGroups.size === 0 && isRequiredSatisfied(values),
|
|
17830
|
+
[invalidGroups, isRequiredSatisfied, values]
|
|
17831
|
+
);
|
|
17664
17832
|
react.useImperativeHandle(ref, () => ({ open, reset, validate }), [open, reset, validate]);
|
|
17665
17833
|
const addField = (key) => {
|
|
17666
17834
|
const next = [...resolvedActiveKeys, key];
|
|
@@ -17697,7 +17865,7 @@ var SChipFilter = /* @__PURE__ */ react.forwardRef(function SChipFilter2({
|
|
|
17697
17865
|
),
|
|
17698
17866
|
style: { ...rootStyle, borderColor: "var(--chipfilter-bar-border)" },
|
|
17699
17867
|
children: [
|
|
17700
|
-
|
|
17868
|
+
label && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
17701
17869
|
/* @__PURE__ */ jsxRuntime.jsx(STag, { className: "shrink-0", shape: "square", size: "sm", color: "darkblue", label }),
|
|
17702
17870
|
/* @__PURE__ */ jsxRuntime.jsx(Divider, { top: true })
|
|
17703
17871
|
] }),
|
|
@@ -17897,6 +18065,7 @@ var SChipFilter = /* @__PURE__ */ react.forwardRef(function SChipFilter2({
|
|
|
17897
18065
|
side: "bottom",
|
|
17898
18066
|
align: "start",
|
|
17899
18067
|
sideOffset: 4,
|
|
18068
|
+
collisionPadding: EDITOR_POPOVER_VIEWPORT_PADDING,
|
|
17900
18069
|
onOpenAutoFocus: (event) => event.preventDefault(),
|
|
17901
18070
|
className: cn("z-50", FLOATING_SLIDE_ANIM),
|
|
17902
18071
|
style: editorPopoverStyle,
|
|
@@ -18062,6 +18231,7 @@ function EditorPanel({
|
|
|
18062
18231
|
onClose
|
|
18063
18232
|
}) {
|
|
18064
18233
|
const wrapsInPaddedTop = field.type === "datepicker-day" || field.type === "datepicker-range" || field.type === "datepicker-statistics";
|
|
18234
|
+
const isScrollableListField = field.type === "select" || field.type === "select-multi" || field.type === "keyword";
|
|
18065
18235
|
const isMulti = field.type === "select-multi";
|
|
18066
18236
|
const selectableValues = isMulti ? (field.options ?? []).filter((option) => !option.disabled).map((option) => option.value) : [];
|
|
18067
18237
|
const selectedValues = isMulti ? toArrayValue(value) : [];
|
|
@@ -18071,7 +18241,7 @@ function EditorPanel({
|
|
|
18071
18241
|
allSelected ? selectedValues.filter((v) => !selectableValues.includes(v)) : [...selectedValues, ...selectableValues.filter((v) => !selectedValues.includes(v))]
|
|
18072
18242
|
);
|
|
18073
18243
|
};
|
|
18074
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(ListBox, { children: [
|
|
18244
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(ListBox, { maxHeight: isScrollableListField ? EDITOR_LISTBOX_MAX_HEIGHT : void 0, children: [
|
|
18075
18245
|
wrapsInPaddedTop ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-[var(--cmp-chipFilter-listbox-top-gap)] px-[var(--cmp-chipFilter-listbox-top-paddingX)] py-[var(--cmp-chipFilter-listbox-top-paddingY)]", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
18076
18246
|
FilterEditor,
|
|
18077
18247
|
{
|
|
@@ -18094,7 +18264,7 @@ function EditorPanel({
|
|
|
18094
18264
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
18095
18265
|
"div",
|
|
18096
18266
|
{
|
|
18097
|
-
className: "flex items-center justify-end gap-[var(--cmp-chipFilter-listbox-bottom-gap)] border-t border-solid px-[var(--cmp-chipFilter-listbox-bottom-paddingX)] py-[var(--cmp-chipFilter-listbox-bottom-paddingY)]",
|
|
18267
|
+
className: "flex shrink-0 items-center justify-end gap-[var(--cmp-chipFilter-listbox-bottom-gap)] border-t border-solid px-[var(--cmp-chipFilter-listbox-bottom-paddingX)] py-[var(--cmp-chipFilter-listbox-bottom-paddingY)]",
|
|
18098
18268
|
style: { borderColor: CHIPFILTER.listboxBorder },
|
|
18099
18269
|
children: [
|
|
18100
18270
|
isMulti && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
@@ -18209,6 +18379,7 @@ function DatePresetEditor({
|
|
|
18209
18379
|
onValueChange
|
|
18210
18380
|
}) {
|
|
18211
18381
|
const presets = getFieldPresets(field);
|
|
18382
|
+
const maxRange = getEffectiveMaxRange(field);
|
|
18212
18383
|
const [selectedId, setSelectedId] = react.useState(() => matchPresetId(presets, value));
|
|
18213
18384
|
const syncedInitialValueRef = react.useRef(!isEmptyValue(value));
|
|
18214
18385
|
react.useEffect(() => {
|
|
@@ -18219,7 +18390,13 @@ function DatePresetEditor({
|
|
|
18219
18390
|
const selectedPreset = presets.find((preset) => preset.value === selectedId);
|
|
18220
18391
|
const selectPreset = (preset) => {
|
|
18221
18392
|
setSelectedId(preset.value);
|
|
18222
|
-
if (!preset.custom)
|
|
18393
|
+
if (!preset.custom) {
|
|
18394
|
+
onValueChange(preset.resolve ? preset.resolve() : preset.value);
|
|
18395
|
+
return;
|
|
18396
|
+
}
|
|
18397
|
+
const today = todayIso();
|
|
18398
|
+
const days = maxRange && maxRange > 0 ? maxRange : DEFAULT_CUSTOM_MAX_RANGE;
|
|
18399
|
+
onValueChange([addDaysIso(today, -days), today]);
|
|
18223
18400
|
};
|
|
18224
18401
|
if (presets.length === 0) {
|
|
18225
18402
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -18228,7 +18405,7 @@ function DatePresetEditor({
|
|
|
18228
18405
|
value: Array.isArray(value) && value.length === 2 ? value : null,
|
|
18229
18406
|
onValueChange,
|
|
18230
18407
|
selectable: field.selectable,
|
|
18231
|
-
maxRange
|
|
18408
|
+
maxRange,
|
|
18232
18409
|
disabled,
|
|
18233
18410
|
width: "100%"
|
|
18234
18411
|
}
|
|
@@ -18240,7 +18417,7 @@ function DatePresetEditor({
|
|
|
18240
18417
|
{
|
|
18241
18418
|
val: preset.value,
|
|
18242
18419
|
value: selectedId,
|
|
18243
|
-
label: preset
|
|
18420
|
+
label: getPresetLabel(preset, maxRange),
|
|
18244
18421
|
disabled,
|
|
18245
18422
|
onValueChange: () => selectPreset(preset)
|
|
18246
18423
|
},
|
|
@@ -18252,7 +18429,7 @@ function DatePresetEditor({
|
|
|
18252
18429
|
value: Array.isArray(value) && value.length === 2 ? value : null,
|
|
18253
18430
|
onValueChange,
|
|
18254
18431
|
selectable: field.selectable,
|
|
18255
|
-
maxRange
|
|
18432
|
+
maxRange,
|
|
18256
18433
|
disabled
|
|
18257
18434
|
}
|
|
18258
18435
|
)
|
|
@@ -18265,9 +18442,10 @@ function PeriodPresetEditor({
|
|
|
18265
18442
|
onValueChange
|
|
18266
18443
|
}) {
|
|
18267
18444
|
const presets = getFieldPresets(field);
|
|
18445
|
+
const maxRange = getEffectiveMaxRange(field);
|
|
18268
18446
|
const firstUnit = presets.find((preset) => !preset.custom)?.value ?? "day";
|
|
18269
18447
|
const [selectedId, setSelectedId] = react.useState(() => matchPresetId(presets, value) ?? firstUnit);
|
|
18270
|
-
const periodValue = isPeriodValue(value) ? value : createPeriodValue(selectedId ?? firstUnit);
|
|
18448
|
+
const periodValue = isPeriodValue(value) ? value : createPeriodValue(selectedId ?? firstUnit, maxRange);
|
|
18271
18449
|
const selectedUnit = selectedId ?? periodValue.unit;
|
|
18272
18450
|
react.useEffect(() => {
|
|
18273
18451
|
if (isEmptyValue(value)) return;
|
|
@@ -18276,7 +18454,7 @@ function PeriodPresetEditor({
|
|
|
18276
18454
|
const selectPreset = (preset) => {
|
|
18277
18455
|
const nextUnit = preset.value;
|
|
18278
18456
|
setSelectedId(nextUnit);
|
|
18279
|
-
onValueChange(createPeriodValue(nextUnit));
|
|
18457
|
+
onValueChange(createPeriodValue(nextUnit, maxRange));
|
|
18280
18458
|
};
|
|
18281
18459
|
const updateInputValue = (nextValue) => {
|
|
18282
18460
|
onValueChange({ unit: selectedUnit, value: nextValue });
|
|
@@ -18359,7 +18537,7 @@ function PeriodPresetEditor({
|
|
|
18359
18537
|
value: Array.isArray(periodValue.value) && periodValue.value.length === 2 ? periodValue.value : null,
|
|
18360
18538
|
onValueChange: updateInputValue,
|
|
18361
18539
|
selectable: field.selectable,
|
|
18362
|
-
maxRange
|
|
18540
|
+
maxRange,
|
|
18363
18541
|
disabled,
|
|
18364
18542
|
width: "100%"
|
|
18365
18543
|
}
|
|
@@ -18371,7 +18549,7 @@ function PeriodPresetEditor({
|
|
|
18371
18549
|
{
|
|
18372
18550
|
val: preset.value,
|
|
18373
18551
|
value: selectedId,
|
|
18374
|
-
label: preset
|
|
18552
|
+
label: getPresetLabel(preset, maxRange),
|
|
18375
18553
|
disabled,
|
|
18376
18554
|
onValueChange: () => selectPreset(preset)
|
|
18377
18555
|
},
|
|
@@ -18407,6 +18585,10 @@ function InlineDatePresetFilter({
|
|
|
18407
18585
|
setSelectedId(preset.value);
|
|
18408
18586
|
onValueChange(preset.resolve ? preset.resolve() : null);
|
|
18409
18587
|
};
|
|
18588
|
+
const badgeBorder = disabled ? CHIPFILTER.chipDisabledBorder : warning ? CHIPFILTER.chipWarningBorder : CHIPFILTER.chipAppliedBorder;
|
|
18589
|
+
const badgeBackground = disabled ? CHIPFILTER.chipDisabledBg : CHIPFILTER.chipAppliedBg;
|
|
18590
|
+
const badgeLabelColor = disabled ? CHIPFILTER.chipDisabledText : CHIPFILTER.chipAppliedLabel;
|
|
18591
|
+
const badgeValueColor = disabled ? CHIPFILTER.chipDisabledText : CHIPFILTER.chipAppliedValue;
|
|
18410
18592
|
const badge = applied && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
18411
18593
|
"span",
|
|
18412
18594
|
{
|
|
@@ -18414,17 +18596,17 @@ function InlineDatePresetFilter({
|
|
|
18414
18596
|
style: {
|
|
18415
18597
|
minHeight: CHIPFILTER.chipHeight,
|
|
18416
18598
|
borderRadius: CHIPFILTER.chipRadius,
|
|
18417
|
-
borderColor:
|
|
18418
|
-
background:
|
|
18419
|
-
color:
|
|
18420
|
-
cursor: rangeValue ? "pointer" : void 0
|
|
18599
|
+
borderColor: badgeBorder,
|
|
18600
|
+
background: badgeBackground,
|
|
18601
|
+
color: badgeLabelColor,
|
|
18602
|
+
cursor: rangeValue && !disabled ? "pointer" : void 0
|
|
18421
18603
|
},
|
|
18422
18604
|
children: [
|
|
18423
18605
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-bold", children: [
|
|
18424
18606
|
field.label,
|
|
18425
18607
|
":"
|
|
18426
18608
|
] }),
|
|
18427
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-bold", style: { color:
|
|
18609
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-bold", style: { color: badgeValueColor }, children: displayValue(field, value) }),
|
|
18428
18610
|
!disabled && showClear && /* @__PURE__ */ jsxRuntime.jsx(
|
|
18429
18611
|
"span",
|
|
18430
18612
|
{
|
|
@@ -18579,7 +18761,7 @@ function KeywordEditor({
|
|
|
18579
18761
|
}
|
|
18580
18762
|
};
|
|
18581
18763
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
18582
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-[var(--cmp-chipFilter-listbox-top-gap)] px-[var(--cmp-chipFilter-listbox-top-paddingX)] py-[var(--cmp-chipFilter-listbox-top-paddingY)]", children: [
|
|
18764
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 flex-col gap-[var(--cmp-chipFilter-listbox-top-gap)] px-[var(--cmp-chipFilter-listbox-top-paddingX)] py-[var(--cmp-chipFilter-listbox-top-paddingY)]", children: [
|
|
18583
18765
|
field.matchModes && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
18584
18766
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
18585
18767
|
"span",
|
|
@@ -18621,7 +18803,7 @@ function KeywordEditor({
|
|
|
18621
18803
|
entries3.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
18622
18804
|
"div",
|
|
18623
18805
|
{
|
|
18624
|
-
className: "
|
|
18806
|
+
className: "min-h-0 flex-1 overflow-auto border-t border-solid py-[var(--cmp-chipFilter-listbox-list-paddingY)]",
|
|
18625
18807
|
style: { borderColor: CHIPFILTER.listboxBorder },
|
|
18626
18808
|
children: entries3.map((entry) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
18627
18809
|
KeywordEntryRow,
|
|
@@ -18679,6 +18861,7 @@ function OptionList({
|
|
|
18679
18861
|
const selected = multiple ? toArrayValue(value) : [];
|
|
18680
18862
|
const singleValue = !multiple && (typeof value === "string" || typeof value === "number") ? value : null;
|
|
18681
18863
|
const [search, setSearch] = react.useState("");
|
|
18864
|
+
const searchInputRef = react.useRef(null);
|
|
18682
18865
|
const options = field.options ?? [];
|
|
18683
18866
|
const showSearch = options.length >= OPTION_SEARCH_THRESHOLD;
|
|
18684
18867
|
const filteredOptions = react.useMemo(() => {
|
|
@@ -18686,74 +18869,70 @@ function OptionList({
|
|
|
18686
18869
|
const query = search.trim().toLowerCase();
|
|
18687
18870
|
return options.filter((option) => option.label.toLowerCase().includes(query));
|
|
18688
18871
|
}, [options, search, showSearch]);
|
|
18872
|
+
react.useEffect(() => {
|
|
18873
|
+
if (!showSearch || disabled) return;
|
|
18874
|
+
searchInputRef.current?.focus();
|
|
18875
|
+
}, [showSearch, disabled]);
|
|
18689
18876
|
if (options.length === 0) return /* @__PURE__ */ jsxRuntime.jsx(EmptyItem, { children: "\uD45C\uC2DC\uD560 \uD56D\uBAA9\uC774 \uC5C6\uC2B5\uB2C8\uB2E4." });
|
|
18690
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
18691
|
-
|
|
18692
|
-
|
|
18693
|
-
|
|
18694
|
-
"
|
|
18695
|
-
|
|
18696
|
-
|
|
18697
|
-
|
|
18698
|
-
children: [
|
|
18699
|
-
showSearch && /* @__PURE__ */ jsxRuntime.jsx(
|
|
18700
|
-
"div",
|
|
18877
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-0 flex-1 flex-col", children: [
|
|
18878
|
+
showSearch && /* @__PURE__ */ jsxRuntime.jsx(
|
|
18879
|
+
"div",
|
|
18880
|
+
{
|
|
18881
|
+
className: "shrink-0 border-b border-solid px-[8px] pb-[4px] pt-[var(--cmp-chipFilter-listbox-list-paddingY)]",
|
|
18882
|
+
style: { borderColor: CHIPFILTER.listboxBorder },
|
|
18883
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
18884
|
+
SSearchInput,
|
|
18701
18885
|
{
|
|
18702
|
-
|
|
18703
|
-
|
|
18704
|
-
|
|
18705
|
-
|
|
18706
|
-
|
|
18707
|
-
|
|
18708
|
-
|
|
18709
|
-
|
|
18710
|
-
disabled,
|
|
18711
|
-
placeholder: "\uAC80\uC0C9",
|
|
18712
|
-
onChange: (event) => setSearch(event.target.value),
|
|
18713
|
-
className: "min-w-0 flex-1 border-none bg-transparent text-[12px] leading-[20px] text-[color:var(--sys-color-field-text-default)] outline-none placeholder:text-[color:var(--sys-color-field-text-placeholder)] disabled:cursor-not-allowed"
|
|
18714
|
-
}
|
|
18715
|
-
),
|
|
18716
|
-
search !== "" && !disabled && /* @__PURE__ */ jsxRuntime.jsx(
|
|
18717
|
-
SGhostButton,
|
|
18718
|
-
{
|
|
18719
|
-
icon: "close",
|
|
18720
|
-
size: "xxs",
|
|
18721
|
-
ariaLabel: "\uAC80\uC0C9\uC5B4 \uC9C0\uC6B0\uAE30",
|
|
18722
|
-
className: "flex-shrink-0",
|
|
18723
|
-
onClick: () => setSearch("")
|
|
18724
|
-
}
|
|
18725
|
-
)
|
|
18726
|
-
] })
|
|
18886
|
+
ref: searchInputRef,
|
|
18887
|
+
size: "sm",
|
|
18888
|
+
value: search,
|
|
18889
|
+
onValueChange: setSearch,
|
|
18890
|
+
disabled,
|
|
18891
|
+
placeholder: "\uAC80\uC0C9",
|
|
18892
|
+
clearable: true,
|
|
18893
|
+
width: "100%"
|
|
18727
18894
|
}
|
|
18895
|
+
)
|
|
18896
|
+
}
|
|
18897
|
+
),
|
|
18898
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
18899
|
+
"div",
|
|
18900
|
+
{
|
|
18901
|
+
className: cn(
|
|
18902
|
+
"min-h-0 flex-1 overflow-auto",
|
|
18903
|
+
!showSearch && "pt-[var(--cmp-chipFilter-listbox-list-paddingY)]",
|
|
18904
|
+
"pb-[var(--cmp-chipFilter-listbox-list-paddingY)]"
|
|
18728
18905
|
),
|
|
18729
|
-
|
|
18730
|
-
|
|
18731
|
-
|
|
18732
|
-
|
|
18733
|
-
|
|
18734
|
-
|
|
18735
|
-
|
|
18736
|
-
|
|
18737
|
-
|
|
18738
|
-
|
|
18739
|
-
|
|
18740
|
-
|
|
18741
|
-
|
|
18742
|
-
|
|
18743
|
-
|
|
18744
|
-
|
|
18906
|
+
children: [
|
|
18907
|
+
showSearch && filteredOptions.length === 0 && /* @__PURE__ */ jsxRuntime.jsx(EmptyItem, { children: "\uAC80\uC0C9 \uACB0\uACFC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4." }),
|
|
18908
|
+
filteredOptions.map((option) => {
|
|
18909
|
+
const checked = multiple ? selected.includes(option.value) : singleValue === option.value;
|
|
18910
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
18911
|
+
MenuItem,
|
|
18912
|
+
{
|
|
18913
|
+
selected: checked,
|
|
18914
|
+
disabled: disabled || option.disabled,
|
|
18915
|
+
multi: multiple,
|
|
18916
|
+
onClick: () => {
|
|
18917
|
+
if (multiple) {
|
|
18918
|
+
const next = checked ? selected.filter((v) => v !== option.value) : [...selected, option.value];
|
|
18919
|
+
onValueChange(next);
|
|
18920
|
+
} else {
|
|
18921
|
+
onValueChange(option.value);
|
|
18922
|
+
}
|
|
18923
|
+
},
|
|
18924
|
+
children: [
|
|
18925
|
+
multiple && /* @__PURE__ */ jsxRuntime.jsx(OptionCheckbox, { checked }),
|
|
18926
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate", children: option.label })
|
|
18927
|
+
]
|
|
18745
18928
|
},
|
|
18746
|
-
|
|
18747
|
-
|
|
18748
|
-
|
|
18749
|
-
|
|
18750
|
-
|
|
18751
|
-
|
|
18752
|
-
|
|
18753
|
-
})
|
|
18754
|
-
]
|
|
18755
|
-
}
|
|
18756
|
-
);
|
|
18929
|
+
String(option.value)
|
|
18930
|
+
);
|
|
18931
|
+
})
|
|
18932
|
+
]
|
|
18933
|
+
}
|
|
18934
|
+
)
|
|
18935
|
+
] });
|
|
18757
18936
|
}
|
|
18758
18937
|
function OptionCheckbox({ checked }) {
|
|
18759
18938
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -18767,15 +18946,22 @@ function OptionCheckbox({ checked }) {
|
|
|
18767
18946
|
}
|
|
18768
18947
|
);
|
|
18769
18948
|
}
|
|
18770
|
-
function ListBox({
|
|
18949
|
+
function ListBox({
|
|
18950
|
+
children,
|
|
18951
|
+
maxHeight
|
|
18952
|
+
}) {
|
|
18771
18953
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
18772
18954
|
"div",
|
|
18773
18955
|
{
|
|
18774
|
-
className:
|
|
18956
|
+
className: cn(
|
|
18957
|
+
"overflow-hidden border border-solid shadow-[var(--shadow-overlay)]",
|
|
18958
|
+
maxHeight && "flex flex-col"
|
|
18959
|
+
),
|
|
18775
18960
|
style: {
|
|
18776
18961
|
borderRadius: CHIPFILTER.listboxRadius,
|
|
18777
18962
|
background: CHIPFILTER.listboxBg,
|
|
18778
|
-
borderColor: CHIPFILTER.listboxBorder
|
|
18963
|
+
borderColor: CHIPFILTER.listboxBorder,
|
|
18964
|
+
maxHeight
|
|
18779
18965
|
},
|
|
18780
18966
|
children
|
|
18781
18967
|
}
|