sellmate-design-system-react 9.0.0-beta.104 → 9.0.0-beta.107
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/AGENTS.md +26 -0
- package/dist/components/SGnb/SGnb.d.ts +3 -0
- package/dist/components/SGnb/gnb.config.d.ts +24 -0
- package/dist/components/SSelect/README.md +17 -0
- package/dist/components/SSelect/SSelect.d.ts +1 -1
- package/dist/components/SSelect/select.config.d.ts +12 -0
- package/dist/components/STable/STable.d.ts +14 -0
- package/dist/components/STag/README.md +2 -0
- package/dist/index.cjs +666 -385
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +666 -385
- package/dist/index.js.map +1 -1
- package/dist/lib/grid-key-nav.d.ts +10 -0
- package/dist/lib/story-docs.d.ts +35 -0
- package/dist/llms-full.txt +43 -0
- package/dist/llms.txt +26 -0
- package/dist/styles.css +9 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -3107,43 +3107,52 @@ var Icon_helpFill = (p) => {
|
|
|
3107
3107
|
}
|
|
3108
3108
|
);
|
|
3109
3109
|
};
|
|
3110
|
+
var HELP_OUTLINE_VARIANTS = {
|
|
3111
|
+
16: {
|
|
3112
|
+
stroke: 1.25,
|
|
3113
|
+
ring: "M14.6666 8.00004C14.6666 4.31814 11.6819 1.33337 7.99998 1.33337C4.31808 1.33337 1.33331 4.31814 1.33331 8.00004C1.33331 11.6819 4.31808 14.6667 7.99998 14.6667C11.6819 14.6667 14.6666 11.6819 14.6666 8.00004Z",
|
|
3114
|
+
mark: "M5.99988 6.06806C5.99988 5.462 6.39988 4.24988 7.99988 4.24988C9.59988 4.24988 9.99988 5.462 9.99988 6.06806C9.99988 6.58025 9.71419 7.52529 8.65996 7.80576C8.30414 7.90042 7.99988 8.18472 7.99988 8.55291V9.24988",
|
|
3115
|
+
dot: "M7.99986 10.4999C8.36805 10.4999 8.66652 10.7984 8.66652 11.1665C8.66652 11.5347 8.36805 11.8332 7.99986 11.8332C7.63167 11.8332 7.33319 11.5347 7.33319 11.1665C7.33319 10.7984 7.63167 10.4999 7.99986 10.4999Z"
|
|
3116
|
+
},
|
|
3117
|
+
20: {
|
|
3118
|
+
stroke: 1.25,
|
|
3119
|
+
ring: "M18.3334 9.99996C18.3334 5.39759 14.6024 1.66663 10 1.66663C5.39765 1.66663 1.66669 5.39759 1.66669 9.99996C1.66669 14.6023 5.39765 18.3333 10 18.3333C14.6024 18.3333 18.3334 14.6023 18.3334 9.99996Z",
|
|
3120
|
+
mark: "M7.49988 7.58498C7.49988 6.82741 7.99988 5.31226 9.99988 5.31226C11.9999 5.31226 12.4999 6.82741 12.4999 7.58498C12.4999 8.22522 12.1428 9.40652 10.825 9.75711C10.3802 9.87543 9.99988 10.2308 9.99988 10.691V11.5623",
|
|
3121
|
+
dot: "M9.99984 13.1248C10.4601 13.1248 10.8332 13.4979 10.8332 13.9581C10.8332 14.4183 10.4601 14.7914 9.99984 14.7914C9.5396 14.7914 9.1665 14.4183 9.1665 13.9581C9.1665 13.4979 9.5396 13.1248 9.99984 13.1248Z"
|
|
3122
|
+
},
|
|
3123
|
+
24: {
|
|
3124
|
+
stroke: 1.5,
|
|
3125
|
+
ring: "M22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22C17.5228 22 22 17.5228 22 12Z",
|
|
3126
|
+
mark: "M8.99982 9.10203C8.99982 8.19294 9.59982 6.37476 11.9998 6.37476C14.3998 6.37476 14.9998 8.19294 14.9998 9.10203C14.9998 9.87031 14.5713 11.2879 12.9899 11.7086C12.4562 11.8506 11.9998 12.277 11.9998 12.8293V13.8748",
|
|
3127
|
+
dot: "M11.9998 15.7498C12.5521 15.7498 12.9998 16.1975 12.9998 16.7498C12.9998 17.302 12.5521 17.7498 11.9998 17.7498C11.4475 17.7498 10.9998 17.302 10.9998 16.7498C10.9998 16.1975 11.4475 15.7498 11.9998 15.7498Z"
|
|
3128
|
+
}
|
|
3129
|
+
};
|
|
3130
|
+
var helpOutlineGrid = (size) => {
|
|
3131
|
+
const px = typeof size === "number" ? size : /^\d+(\.\d+)?(px)?$/.test(size) ? parseFloat(size) : void 0;
|
|
3132
|
+
if (px === void 0) return 24;
|
|
3133
|
+
if (px <= 16) return 16;
|
|
3134
|
+
if (px <= 20) return 20;
|
|
3135
|
+
return 24;
|
|
3136
|
+
};
|
|
3110
3137
|
var Icon_helpOutline = (p) => {
|
|
3111
3138
|
const { size = 24, strokeWidth, ...rest } = p;
|
|
3112
|
-
const
|
|
3139
|
+
const grid = helpOutlineGrid(size);
|
|
3140
|
+
const v = HELP_OUTLINE_VARIANTS[grid];
|
|
3141
|
+
const native = Number(size) === grid || size === `${grid}px`;
|
|
3142
|
+
const stroke = native ? { stroke: "currentColor", strokeWidth: v.stroke } : { ...strokeProps(strokeWidth), strokeWidth: strokeWidth ?? v.stroke };
|
|
3113
3143
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3114
3144
|
"svg",
|
|
3115
3145
|
{
|
|
3116
3146
|
width: size,
|
|
3117
3147
|
height: size,
|
|
3118
|
-
viewBox:
|
|
3148
|
+
viewBox: `0 0 ${grid} ${grid}`,
|
|
3119
3149
|
fill: "none",
|
|
3120
3150
|
xmlns: "http://www.w3.org/2000/svg",
|
|
3121
3151
|
...rest,
|
|
3122
3152
|
children: [
|
|
3123
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
d: "M22.1998 11.9998C22.1998 6.3665 17.6331 1.7998 11.9998 1.7998C6.3665 1.7998 1.7998 6.3665 1.7998 11.9998C1.7998 17.6331 6.3665 22.1998 11.9998 22.1998C17.6331 22.1998 22.1998 17.6331 22.1998 11.9998Z",
|
|
3127
|
-
strokeLinecap: "round",
|
|
3128
|
-
...stroke
|
|
3129
|
-
}
|
|
3130
|
-
),
|
|
3131
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3132
|
-
"path",
|
|
3133
|
-
{
|
|
3134
|
-
d: "M8.99982 9.10203C8.99982 8.19294 9.59982 6.37476 11.9998 6.37476C14.3998 6.37476 14.9998 8.19294 14.9998 9.10203C14.9998 9.87031 14.5713 11.2879 12.9899 11.7086C12.4562 11.8506 11.9998 12.277 11.9998 12.8293V13.8748",
|
|
3135
|
-
strokeLinecap: "round",
|
|
3136
|
-
strokeLinejoin: "round",
|
|
3137
|
-
...stroke
|
|
3138
|
-
}
|
|
3139
|
-
),
|
|
3140
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3141
|
-
"path",
|
|
3142
|
-
{
|
|
3143
|
-
d: "M11.9998 15.7498C12.5521 15.7498 12.9998 16.1975 12.9998 16.7498C12.9998 17.302 12.5521 17.7498 11.9998 17.7498C11.4475 17.7498 10.9998 17.302 10.9998 16.7498C10.9998 16.1975 11.4475 15.7498 11.9998 15.7498Z",
|
|
3144
|
-
fill: "currentColor"
|
|
3145
|
-
}
|
|
3146
|
-
)
|
|
3153
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: v.ring, strokeLinecap: "round", ...stroke }),
|
|
3154
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: v.mark, strokeLinecap: "round", strokeLinejoin: "round", ...stroke }),
|
|
3155
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: v.dot, fill: "currentColor" })
|
|
3147
3156
|
]
|
|
3148
3157
|
}
|
|
3149
3158
|
);
|
|
@@ -5652,7 +5661,11 @@ var STag = /* @__PURE__ */ react.forwardRef(function STag2({
|
|
|
5652
5661
|
// 레이블에 line-height 가 필요 없다. 오히려 line-height 를 주면 브라우저가
|
|
5653
5662
|
// 폰트 ascent/descent 를 정수 px 로 반올림한 뒤 남는 half-leading 을 내림 처리해
|
|
5654
5663
|
// 베이스라인이 최대 1px 위로 밀린다(xs 에서 특히 눈에 띈다).
|
|
5655
|
-
|
|
5664
|
+
// truncate: 폭이 모자라면(`width` 지정, 부모의 max-w 등) 글자에 말줄임이 걸린다. text-overflow 는
|
|
5665
|
+
// inline-flex 에서 듣지 않아 block 으로 둔다 — flex 아이템이라 폭·정렬은 그대로다.
|
|
5666
|
+
// overflow:hidden 이 line-height:1 의 줄 상자 밖으로 나온 글자(디센더)를 자르지 않도록
|
|
5667
|
+
// py 로 잘리는 영역만 넓히고 -my 로 레이아웃 높이는 되돌린다.
|
|
5668
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "-my-[2px] block min-w-0 truncate py-[2px] leading-none", children: label }),
|
|
5656
5669
|
icon && !iconLeft && iconNode
|
|
5657
5670
|
]
|
|
5658
5671
|
}
|
|
@@ -13825,6 +13838,11 @@ var GNB_RAIL = {
|
|
|
13825
13838
|
var GNB_RAIL_WIDTH = 68;
|
|
13826
13839
|
var GNB_FOLD_MS = 200;
|
|
13827
13840
|
var GNB_EXPAND_MS = 200;
|
|
13841
|
+
var GNB_PEEK_ENTER_DELAY_MS = 120;
|
|
13842
|
+
var GNB_PEEK_LEAVE_DELAY_MS = 250;
|
|
13843
|
+
var GNB_PEEK_EDGE_WIDTH = 12;
|
|
13844
|
+
var GNB_PEEK_Z_INDEX = 40;
|
|
13845
|
+
var GNB_PEEK_SHADOW = "0px 0px 64px 0px rgba(34,34,34,0.12), 0px 0px 24px 0px rgba(34,34,34,0.08)";
|
|
13828
13846
|
var GNB_MENU_WIDTH = 214;
|
|
13829
13847
|
var GNB_MENU_MIN_WIDTH = 200;
|
|
13830
13848
|
var GNB_MENU_MAX_WIDTH = 240;
|
|
@@ -13921,6 +13939,10 @@ var SGnb = /* @__PURE__ */ react.forwardRef(function SGnb2({
|
|
|
13921
13939
|
ariaLabel = "global navigation",
|
|
13922
13940
|
className,
|
|
13923
13941
|
style,
|
|
13942
|
+
onPointerEnter: onPointerEnterProp,
|
|
13943
|
+
onPointerLeave: onPointerLeaveProp,
|
|
13944
|
+
onFocus: onFocusProp,
|
|
13945
|
+
onBlur: onBlurProp,
|
|
13924
13946
|
...rest
|
|
13925
13947
|
}, ref) {
|
|
13926
13948
|
const layout = react.useContext(SLayoutContext);
|
|
@@ -14277,7 +14299,80 @@ var SGnb = /* @__PURE__ */ react.forwardRef(function SGnb2({
|
|
|
14277
14299
|
event.preventDefault();
|
|
14278
14300
|
commitMenuWidth(next);
|
|
14279
14301
|
};
|
|
14280
|
-
const
|
|
14302
|
+
const [peeking, setPeeking] = react.useState(false);
|
|
14303
|
+
const peekingRef = react.useRef(false);
|
|
14304
|
+
const peekHoverRef = react.useRef(false);
|
|
14305
|
+
const peekFocusRef = react.useRef(false);
|
|
14306
|
+
const peekTimerRef = react.useRef(null);
|
|
14307
|
+
const clearPeekTimer = () => {
|
|
14308
|
+
if (peekTimerRef.current === null) return;
|
|
14309
|
+
clearTimeout(peekTimerRef.current);
|
|
14310
|
+
peekTimerRef.current = null;
|
|
14311
|
+
};
|
|
14312
|
+
const commitPeek = (next) => {
|
|
14313
|
+
peekingRef.current = next;
|
|
14314
|
+
if (next) peekFocusRef.current = false;
|
|
14315
|
+
setPeeking(next);
|
|
14316
|
+
};
|
|
14317
|
+
const schedulePeek = () => {
|
|
14318
|
+
clearPeekTimer();
|
|
14319
|
+
const want = peekHoverRef.current || peekingRef.current && peekFocusRef.current;
|
|
14320
|
+
if (want === peekingRef.current) return;
|
|
14321
|
+
peekTimerRef.current = setTimeout(
|
|
14322
|
+
() => {
|
|
14323
|
+
peekTimerRef.current = null;
|
|
14324
|
+
commitPeek(want);
|
|
14325
|
+
},
|
|
14326
|
+
want ? GNB_PEEK_ENTER_DELAY_MS : GNB_PEEK_LEAVE_DELAY_MS
|
|
14327
|
+
);
|
|
14328
|
+
};
|
|
14329
|
+
react.useEffect(() => {
|
|
14330
|
+
if (folded) return;
|
|
14331
|
+
clearPeekTimer();
|
|
14332
|
+
peekHoverRef.current = false;
|
|
14333
|
+
peekFocusRef.current = false;
|
|
14334
|
+
commitPeek(false);
|
|
14335
|
+
}, [folded]);
|
|
14336
|
+
react.useEffect(() => clearPeekTimer, []);
|
|
14337
|
+
const handlePeekEdgeEnter = (event) => {
|
|
14338
|
+
if (!folded || event.pointerType === "touch") return;
|
|
14339
|
+
peekHoverRef.current = true;
|
|
14340
|
+
schedulePeek();
|
|
14341
|
+
};
|
|
14342
|
+
const handlePeekEnter = (event) => {
|
|
14343
|
+
if (!peekingRef.current) return;
|
|
14344
|
+
handlePeekEdgeEnter(event);
|
|
14345
|
+
};
|
|
14346
|
+
const handlePeekLeave = () => {
|
|
14347
|
+
peekHoverRef.current = false;
|
|
14348
|
+
schedulePeek();
|
|
14349
|
+
};
|
|
14350
|
+
const handlePeekFocus = (event) => {
|
|
14351
|
+
peekFocusRef.current = event.target.matches(":focus-visible");
|
|
14352
|
+
schedulePeek();
|
|
14353
|
+
};
|
|
14354
|
+
const handlePeekBlur = (event) => {
|
|
14355
|
+
if (event.currentTarget.contains(event.relatedTarget)) return;
|
|
14356
|
+
peekFocusRef.current = false;
|
|
14357
|
+
schedulePeek();
|
|
14358
|
+
};
|
|
14359
|
+
const [peekClosing, setPeekClosing] = react.useState(false);
|
|
14360
|
+
const wasPeekingRef = react.useRef(false);
|
|
14361
|
+
react.useEffect(() => {
|
|
14362
|
+
if (peeking) {
|
|
14363
|
+
wasPeekingRef.current = true;
|
|
14364
|
+
setPeekClosing(false);
|
|
14365
|
+
return void 0;
|
|
14366
|
+
}
|
|
14367
|
+
if (!wasPeekingRef.current) return void 0;
|
|
14368
|
+
wasPeekingRef.current = false;
|
|
14369
|
+
setPeekClosing(true);
|
|
14370
|
+
const timer = setTimeout(() => setPeekClosing(false), GNB_FOLD_MS);
|
|
14371
|
+
return () => clearTimeout(timer);
|
|
14372
|
+
}, [peeking]);
|
|
14373
|
+
const peekOverlay = folded && peeking;
|
|
14374
|
+
const visuallyFolded = folded && !peeking;
|
|
14375
|
+
const railFolded = visuallyFolded && header === "fix";
|
|
14281
14376
|
react.useEffect(() => {
|
|
14282
14377
|
if (!railFolded || !launcherOpen) return;
|
|
14283
14378
|
setLauncherOpen(false);
|
|
@@ -14324,14 +14419,50 @@ var SGnb = /* @__PURE__ */ react.forwardRef(function SGnb2({
|
|
|
14324
14419
|
{ width: "100%", ...style }
|
|
14325
14420
|
) : {
|
|
14326
14421
|
// fix 를 닫으면 48px 레일로 좁혀진다.
|
|
14327
|
-
width:
|
|
14422
|
+
width: visuallyFolded ? GNB_COMMON.foldWidth : bodyWidth,
|
|
14423
|
+
// 호버 오버레이: 폭은 펼치되 음수 margin 으로 레이아웃 자리는 레일 폭 그대로 둔다 — 페이지가 밀리지 않는다.
|
|
14424
|
+
// 폭과 margin 이 같은 길이·곡선으로 움직여 둘의 합(=페이지가 보는 자리)은 전환 내내 변하지 않는다.
|
|
14425
|
+
marginRight: peekOverlay ? `calc(${GNB_COMMON.foldWidth} - ${bodyWidth}px)` : "0px",
|
|
14426
|
+
// 페이지 위에 뜬다(접히는 전환이 끝날 때까지). 그 밖에는 주지 않는다 — 주면 펼친 GNB 에도 stacking context 가 새로 생긴다.
|
|
14427
|
+
// (폴드 버튼으로 펴서 folded 가 풀리면 접히는 중이 아니다 — 펼친 GNB 에는 주지 않는다)
|
|
14428
|
+
zIndex: peekOverlay || peekClosing && folded ? GNB_PEEK_Z_INDEX : void 0,
|
|
14429
|
+
boxShadow: peekOverlay ? GNB_PEEK_SHADOW : "none",
|
|
14328
14430
|
// 폭을 끄는 중에는 전환을 끈다 — 접힘용 전환이 걸려 있으면 컬럼이 손보다 늦게 따라온다.
|
|
14329
|
-
transition: resizing ? "none" : `width ${GNB_FOLD_MS}ms ease-out`,
|
|
14431
|
+
transition: resizing ? "none" : `width ${GNB_FOLD_MS}ms ease-out, margin-right ${GNB_FOLD_MS}ms ease-out, box-shadow ${GNB_FOLD_MS}ms ease-out`,
|
|
14330
14432
|
backgroundColor: C.panelBg,
|
|
14331
14433
|
borderRight: rightBorder,
|
|
14332
14434
|
...style
|
|
14333
14435
|
};
|
|
14334
14436
|
const hideAfterSlide = (hidden) => `visibility 0s linear ${hidden ? `${GNB_FOLD_MS}ms` : "0s"}`;
|
|
14437
|
+
const peekEdge = visuallyFolded ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
14438
|
+
"div",
|
|
14439
|
+
{
|
|
14440
|
+
"aria-hidden": true,
|
|
14441
|
+
"data-gnb-peek-edge": "",
|
|
14442
|
+
className: "absolute inset-y-0 left-0 z-[2]",
|
|
14443
|
+
style: { width: GNB_PEEK_EDGE_WIDTH },
|
|
14444
|
+
onPointerEnter: handlePeekEdgeEnter,
|
|
14445
|
+
onPointerLeave: handlePeekLeave
|
|
14446
|
+
}
|
|
14447
|
+
) : null;
|
|
14448
|
+
const rootPeekProps = {
|
|
14449
|
+
onPointerEnter: (event) => {
|
|
14450
|
+
onPointerEnterProp?.(event);
|
|
14451
|
+
if (!isFull) handlePeekEnter(event);
|
|
14452
|
+
},
|
|
14453
|
+
onPointerLeave: (event) => {
|
|
14454
|
+
onPointerLeaveProp?.(event);
|
|
14455
|
+
if (!isFull) handlePeekLeave();
|
|
14456
|
+
},
|
|
14457
|
+
onFocus: (event) => {
|
|
14458
|
+
onFocusProp?.(event);
|
|
14459
|
+
if (!isFull) handlePeekFocus(event);
|
|
14460
|
+
},
|
|
14461
|
+
onBlur: (event) => {
|
|
14462
|
+
onBlurProp?.(event);
|
|
14463
|
+
if (!isFull) handlePeekBlur(event);
|
|
14464
|
+
}
|
|
14465
|
+
};
|
|
14335
14466
|
const sideFoldStyle = railFolded ? {
|
|
14336
14467
|
opacity: 0,
|
|
14337
14468
|
position: "absolute",
|
|
@@ -14481,7 +14612,9 @@ var SGnb = /* @__PURE__ */ react.forwardRef(function SGnb2({
|
|
|
14481
14612
|
"data-header": header,
|
|
14482
14613
|
"data-color": color,
|
|
14483
14614
|
...rest,
|
|
14615
|
+
...rootPeekProps,
|
|
14484
14616
|
children: [
|
|
14617
|
+
!isFull && peekEdge,
|
|
14485
14618
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14486
14619
|
"div",
|
|
14487
14620
|
{
|
|
@@ -14516,19 +14649,33 @@ var SGnb = /* @__PURE__ */ react.forwardRef(function SGnb2({
|
|
|
14516
14649
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
14517
14650
|
"div",
|
|
14518
14651
|
{
|
|
14519
|
-
className: cn(
|
|
14520
|
-
|
|
14652
|
+
className: cn(
|
|
14653
|
+
"relative",
|
|
14654
|
+
(!isFull || !folded) && "overflow-hidden",
|
|
14655
|
+
!isFullFrame && "min-h-0 flex-1"
|
|
14656
|
+
),
|
|
14657
|
+
style: {
|
|
14658
|
+
...isFullFrame ? { gridArea: "nav" } : null,
|
|
14659
|
+
// 접힌 동안 띠와 펼쳐진 본문이 페이지 위에 서도록 이 칸을 올린다
|
|
14660
|
+
...isFull && folded ? { zIndex: GNB_PEEK_Z_INDEX } : null
|
|
14661
|
+
},
|
|
14521
14662
|
children: [
|
|
14663
|
+
isFull && peekEdge,
|
|
14522
14664
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
14523
14665
|
"div",
|
|
14524
14666
|
{
|
|
14525
14667
|
className: "flex h-full flex-row",
|
|
14526
14668
|
style: {
|
|
14527
14669
|
width: bodyWidth,
|
|
14528
|
-
transform:
|
|
14529
|
-
visibility:
|
|
14530
|
-
|
|
14670
|
+
transform: visuallyFolded ? "translateX(-100%)" : "none",
|
|
14671
|
+
visibility: visuallyFolded ? "hidden" : "visible",
|
|
14672
|
+
boxShadow: peekOverlay ? GNB_PEEK_SHADOW : "none",
|
|
14673
|
+
transition: `transform ${GNB_FOLD_MS}ms ease-out, box-shadow ${GNB_FOLD_MS}ms ease-out, ${hideAfterSlide(visuallyFolded)}`
|
|
14531
14674
|
},
|
|
14675
|
+
onPointerEnter: isFull ? handlePeekEnter : void 0,
|
|
14676
|
+
onPointerLeave: isFull ? handlePeekLeave : void 0,
|
|
14677
|
+
onFocus: isFull ? handlePeekFocus : void 0,
|
|
14678
|
+
onBlur: isFull ? handlePeekBlur : void 0,
|
|
14532
14679
|
children: [
|
|
14533
14680
|
showRail && // 레일 컬럼 — 스크롤되는 아이템 목록(nav)을 가운데 두고 위아래에 고정 슬롯(top/footer)을 붙인다.
|
|
14534
14681
|
// 두 슬롯은 내비게이션이 아니므로 nav(landmark) 밖에 두고, 컬럼 폭·구분선·배경은 이 래퍼가
|
|
@@ -17321,6 +17468,48 @@ function indexAtOffset(metrics, y) {
|
|
|
17321
17468
|
return lo;
|
|
17322
17469
|
}
|
|
17323
17470
|
|
|
17471
|
+
// src/lib/grid-key-nav.ts
|
|
17472
|
+
var GRID_NAV_ATTR = "data-grid-nav";
|
|
17473
|
+
var TEXT_INPUT = [
|
|
17474
|
+
"input:not([type])",
|
|
17475
|
+
...["text", "number", "search", "tel", "url", "email", "password"].map((t) => `input[type="${t}"]`)
|
|
17476
|
+
];
|
|
17477
|
+
var FOCUSABLE_INPUT = TEXT_INPUT.map(
|
|
17478
|
+
(s) => `${s}:not(:disabled):not([readonly]):not([aria-disabled="true"])`
|
|
17479
|
+
).join(",");
|
|
17480
|
+
function isTextInput(el) {
|
|
17481
|
+
return el.matches(TEXT_INPUT.join(","));
|
|
17482
|
+
}
|
|
17483
|
+
function focusInput(cell) {
|
|
17484
|
+
const input = cell.querySelector(FOCUSABLE_INPUT);
|
|
17485
|
+
if (!input) return false;
|
|
17486
|
+
if (input.closest('[inert],[aria-disabled="true"]')) return false;
|
|
17487
|
+
input.focus();
|
|
17488
|
+
if (input.ownerDocument.activeElement !== input) return false;
|
|
17489
|
+
input.select();
|
|
17490
|
+
return true;
|
|
17491
|
+
}
|
|
17492
|
+
function handleGridKeyNav(e) {
|
|
17493
|
+
if (e.key !== "Enter" || e.defaultPrevented) return;
|
|
17494
|
+
if (e.nativeEvent.isComposing || e.keyCode === 229 || e.ctrlKey || e.altKey || e.metaKey) return;
|
|
17495
|
+
const target = e.target;
|
|
17496
|
+
if (!isTextInput(target)) return;
|
|
17497
|
+
if (target.getAttribute("aria-expanded") === "true") return;
|
|
17498
|
+
const root = e.currentTarget;
|
|
17499
|
+
const cell = target.closest(`[${GRID_NAV_ATTR}]`);
|
|
17500
|
+
if (!cell || !root.contains(cell)) return;
|
|
17501
|
+
const column = cell.getAttribute(GRID_NAV_ATTR) ?? "";
|
|
17502
|
+
e.preventDefault();
|
|
17503
|
+
const table = cell.closest("table");
|
|
17504
|
+
const cells = [...root.querySelectorAll(`[${GRID_NAV_ATTR}]`)].filter(
|
|
17505
|
+
(c) => c.getAttribute(GRID_NAV_ATTR) === column && c.closest("table") === table
|
|
17506
|
+
);
|
|
17507
|
+
const step = e.shiftKey ? -1 : 1;
|
|
17508
|
+
for (let i = cells.indexOf(cell) + step; i >= 0 && i < cells.length; i += step) {
|
|
17509
|
+
if (focusInput(cells[i])) return;
|
|
17510
|
+
}
|
|
17511
|
+
}
|
|
17512
|
+
|
|
17324
17513
|
// src/lib/depth-filter.ts
|
|
17325
17514
|
function filterDepthRows(rows, matches) {
|
|
17326
17515
|
const selfMatch = rows.map(matches);
|
|
@@ -17488,6 +17677,7 @@ function flattenOptions(options, depth = 1, inheritDisabled = true) {
|
|
|
17488
17677
|
out.push({
|
|
17489
17678
|
value: String(o.value),
|
|
17490
17679
|
label: o.label,
|
|
17680
|
+
tag: o.tag,
|
|
17491
17681
|
disabled: !!o.disabled || allChildrenDisabled,
|
|
17492
17682
|
depth,
|
|
17493
17683
|
isGroup: true,
|
|
@@ -17498,6 +17688,7 @@ function flattenOptions(options, depth = 1, inheritDisabled = true) {
|
|
|
17498
17688
|
out.push({
|
|
17499
17689
|
value: String(o.value),
|
|
17500
17690
|
label: o.label,
|
|
17691
|
+
tag: o.tag,
|
|
17501
17692
|
disabled: !!o.disabled,
|
|
17502
17693
|
depth,
|
|
17503
17694
|
isGroup: false,
|
|
@@ -17702,9 +17893,15 @@ var SSelectImpl = /* @__PURE__ */ react.forwardRef(function SSelect({
|
|
|
17702
17893
|
const effectiveDisabled = disabled || allOptionsDisabled;
|
|
17703
17894
|
const searchVisible = showSearch && (partialOptions || selectable.length >= SEARCH_THRESHOLD);
|
|
17704
17895
|
const labelByValue = react.useMemo(() => new Map(flat.map((o) => [o.value, o.label])), [flat]);
|
|
17896
|
+
const tagByValue = react.useMemo(() => new Map(flat.map((o) => [o.value, o.tag])), [flat]);
|
|
17705
17897
|
const rawByValue = react.useMemo(() => new Map(flat.map((o) => [o.value, o.raw])), [flat]);
|
|
17706
17898
|
const optionByValue = react.useMemo(
|
|
17707
|
-
() => new Map(
|
|
17899
|
+
() => new Map(
|
|
17900
|
+
flat.map((o) => [
|
|
17901
|
+
o.value,
|
|
17902
|
+
{ value: o.raw, label: o.label, ...o.tag && { tag: o.tag } }
|
|
17903
|
+
])
|
|
17904
|
+
),
|
|
17708
17905
|
[flat]
|
|
17709
17906
|
);
|
|
17710
17907
|
const selected = react.useMemo(() => {
|
|
@@ -17717,7 +17914,11 @@ var SSelectImpl = /* @__PURE__ */ react.forwardRef(function SSelect({
|
|
|
17717
17914
|
if (value == null) return map;
|
|
17718
17915
|
for (const v of Array.isArray(value) ? value : [value]) {
|
|
17719
17916
|
if (v != null && typeof v === "object") {
|
|
17720
|
-
map.set(String(v.value), {
|
|
17917
|
+
map.set(String(v.value), {
|
|
17918
|
+
value: v.value,
|
|
17919
|
+
label: v.label,
|
|
17920
|
+
...v.tag && { tag: v.tag }
|
|
17921
|
+
});
|
|
17721
17922
|
}
|
|
17722
17923
|
}
|
|
17723
17924
|
return map;
|
|
@@ -18058,6 +18259,7 @@ var SSelectImpl = /* @__PURE__ */ react.forwardRef(function SSelect({
|
|
|
18058
18259
|
});
|
|
18059
18260
|
}
|
|
18060
18261
|
}
|
|
18262
|
+
const tagSize = size === "md" ? "sm" : "xs";
|
|
18061
18263
|
const isPlaceholder = selected.length === 0;
|
|
18062
18264
|
const showTriggerSpinner = loading2 && !effectiveDisabled;
|
|
18063
18265
|
const showClear = clearable && !effectiveDisabled && !isPlaceholder;
|
|
@@ -18402,7 +18604,15 @@ var SSelectImpl = /* @__PURE__ */ react.forwardRef(function SSelect({
|
|
|
18402
18604
|
))
|
|
18403
18605
|
}
|
|
18404
18606
|
)
|
|
18405
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
18607
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
18608
|
+
TriggerLabel,
|
|
18609
|
+
{
|
|
18610
|
+
label: triggerText,
|
|
18611
|
+
tag: multi ? void 0 : tagByValue.get(selected[0]) ?? valueOptions.get(selected[0])?.tag,
|
|
18612
|
+
tagSize,
|
|
18613
|
+
tagDisabled: effectiveDisabled
|
|
18614
|
+
}
|
|
18615
|
+
),
|
|
18406
18616
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex shrink-0 items-center gap-[8px]", children: [
|
|
18407
18617
|
showClear && /* @__PURE__ */ jsxRuntime.jsx(TriggerRemoveButton, { ariaLabel: t.clear, onRemove: handleClear }),
|
|
18408
18618
|
showTriggerSpinner ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "inline-flex shrink-0", "data-select-trigger-spinner": true, children: /* @__PURE__ */ jsxRuntime.jsx(SCircleProgress, { indeterminate: true, type: "neutral", size: 12 }) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -18495,6 +18705,7 @@ var SSelectImpl = /* @__PURE__ */ react.forwardRef(function SSelect({
|
|
|
18495
18705
|
hasItems ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
18496
18706
|
ItemList,
|
|
18497
18707
|
{
|
|
18708
|
+
tagSize,
|
|
18498
18709
|
listboxId,
|
|
18499
18710
|
activeOptionId,
|
|
18500
18711
|
items: visibleItems,
|
|
@@ -18552,6 +18763,7 @@ var SSelectImpl = /* @__PURE__ */ react.forwardRef(function SSelect({
|
|
|
18552
18763
|
});
|
|
18553
18764
|
var SSelect2 = /* @__PURE__ */ withDisplayName(SSelectImpl, "SSelect");
|
|
18554
18765
|
function ItemList({
|
|
18766
|
+
tagSize,
|
|
18555
18767
|
listboxId,
|
|
18556
18768
|
activeOptionId,
|
|
18557
18769
|
items,
|
|
@@ -18734,6 +18946,9 @@ function ItemList({
|
|
|
18734
18946
|
OptionLabel,
|
|
18735
18947
|
{
|
|
18736
18948
|
label: o.label,
|
|
18949
|
+
tag: o.tag,
|
|
18950
|
+
tagSize,
|
|
18951
|
+
tagDisabled: rowDisabled,
|
|
18737
18952
|
className: treeLabelClass("sm", {
|
|
18738
18953
|
// 고른 줄은 굵게 — multi_tree 는 일부만 고른 그룹도 굵다 (STree 와 같다)
|
|
18739
18954
|
emphasized: checkState !== false,
|
|
@@ -18868,7 +19083,16 @@ function ItemList({
|
|
|
18868
19083
|
focused: focusedValue === o.value
|
|
18869
19084
|
}
|
|
18870
19085
|
),
|
|
18871
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19086
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19087
|
+
OptionLabel,
|
|
19088
|
+
{
|
|
19089
|
+
label: o.label,
|
|
19090
|
+
tag: o.tag,
|
|
19091
|
+
tagSize,
|
|
19092
|
+
tagDisabled: o.disabled,
|
|
19093
|
+
className: "flex-1 truncate"
|
|
19094
|
+
}
|
|
19095
|
+
)
|
|
18872
19096
|
]
|
|
18873
19097
|
},
|
|
18874
19098
|
rowKey
|
|
@@ -18900,11 +19124,52 @@ function TreeRowsMotion({ opening, children }) {
|
|
|
18900
19124
|
react.useEffect(() => () => animationRef.current?.cancel(), []);
|
|
18901
19125
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: "overflow-hidden", "aria-hidden": opening ? void 0 : true, children });
|
|
18902
19126
|
}
|
|
18903
|
-
function OptionLabel({
|
|
19127
|
+
function OptionLabel({
|
|
19128
|
+
label,
|
|
19129
|
+
tag,
|
|
19130
|
+
tagSize,
|
|
19131
|
+
tagDisabled,
|
|
19132
|
+
className
|
|
19133
|
+
}) {
|
|
19134
|
+
if (tag) {
|
|
19135
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
19136
|
+
"span",
|
|
19137
|
+
{
|
|
19138
|
+
className: cn(
|
|
19139
|
+
className,
|
|
19140
|
+
"min-w-0 overflow-hidden",
|
|
19141
|
+
tagDisabled && "opacity-(--opacity-050)"
|
|
19142
|
+
),
|
|
19143
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
19144
|
+
STag,
|
|
19145
|
+
{
|
|
19146
|
+
...tag,
|
|
19147
|
+
size: tagSize,
|
|
19148
|
+
label: isHtmlLabel(label) ? extractText(label) : label,
|
|
19149
|
+
className: cn("max-w-full min-w-0", tag.className)
|
|
19150
|
+
}
|
|
19151
|
+
)
|
|
19152
|
+
}
|
|
19153
|
+
);
|
|
19154
|
+
}
|
|
18904
19155
|
return isHtmlLabel(label) ? /* @__PURE__ */ jsxRuntime.jsx("span", { className, dangerouslySetInnerHTML: { __html: sanitizeInlineHtml(label) } }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className, children: label });
|
|
18905
19156
|
}
|
|
18906
|
-
function TriggerLabel({
|
|
18907
|
-
|
|
19157
|
+
function TriggerLabel({
|
|
19158
|
+
label,
|
|
19159
|
+
tag,
|
|
19160
|
+
tagSize,
|
|
19161
|
+
tagDisabled
|
|
19162
|
+
}) {
|
|
19163
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
19164
|
+
OptionLabel,
|
|
19165
|
+
{
|
|
19166
|
+
label,
|
|
19167
|
+
tag,
|
|
19168
|
+
tagSize,
|
|
19169
|
+
tagDisabled,
|
|
19170
|
+
className: "truncate"
|
|
19171
|
+
}
|
|
19172
|
+
);
|
|
18908
19173
|
}
|
|
18909
19174
|
function TriggerRemoveButton({ ariaLabel, onRemove }) {
|
|
18910
19175
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -19911,365 +20176,381 @@ var STableImpl = /* @__PURE__ */ react.forwardRef(function STable({
|
|
|
19911
20176
|
]
|
|
19912
20177
|
}
|
|
19913
20178
|
);
|
|
19914
|
-
|
|
19915
|
-
|
|
19916
|
-
|
|
19917
|
-
|
|
19918
|
-
|
|
19919
|
-
"
|
|
19920
|
-
|
|
19921
|
-
|
|
19922
|
-
|
|
19923
|
-
|
|
19924
|
-
|
|
19925
|
-
|
|
19926
|
-
|
|
19927
|
-
|
|
19928
|
-
|
|
19929
|
-
|
|
19930
|
-
|
|
19931
|
-
|
|
19932
|
-
|
|
19933
|
-
|
|
19934
|
-
|
|
19935
|
-
|
|
19936
|
-
|
|
19937
|
-
|
|
19938
|
-
|
|
19939
|
-
|
|
19940
|
-
|
|
19941
|
-
|
|
19942
|
-
|
|
19943
|
-
|
|
19944
|
-
|
|
19945
|
-
|
|
19946
|
-
|
|
19947
|
-
|
|
19948
|
-
|
|
19949
|
-
|
|
19950
|
-
|
|
19951
|
-
|
|
19952
|
-
|
|
19953
|
-
|
|
19954
|
-
|
|
19955
|
-
|
|
19956
|
-
|
|
19957
|
-
|
|
19958
|
-
|
|
19959
|
-
|
|
19960
|
-
|
|
19961
|
-
|
|
19962
|
-
|
|
19963
|
-
|
|
19964
|
-
|
|
19965
|
-
|
|
19966
|
-
|
|
19967
|
-
|
|
19968
|
-
|
|
19969
|
-
|
|
19970
|
-
|
|
19971
|
-
|
|
19972
|
-
|
|
19973
|
-
|
|
19974
|
-
|
|
19975
|
-
|
|
19976
|
-
|
|
19977
|
-
|
|
19978
|
-
|
|
19979
|
-
|
|
19980
|
-
|
|
19981
|
-
|
|
19982
|
-
|
|
19983
|
-
|
|
19984
|
-
|
|
19985
|
-
|
|
19986
|
-
|
|
19987
|
-
|
|
19988
|
-
|
|
19989
|
-
|
|
19990
|
-
|
|
19991
|
-
|
|
19992
|
-
|
|
19993
|
-
|
|
19994
|
-
|
|
19995
|
-
|
|
19996
|
-
|
|
19997
|
-
|
|
19998
|
-
|
|
19999
|
-
|
|
20000
|
-
|
|
20001
|
-
|
|
20002
|
-
|
|
20003
|
-
|
|
20004
|
-
|
|
20005
|
-
|
|
20006
|
-
|
|
20007
|
-
|
|
20008
|
-
|
|
20009
|
-
|
|
20010
|
-
|
|
20011
|
-
(
|
|
20012
|
-
|
|
20013
|
-
|
|
20014
|
-
|
|
20015
|
-
|
|
20016
|
-
|
|
20017
|
-
|
|
20018
|
-
|
|
20019
|
-
|
|
20020
|
-
|
|
20021
|
-
|
|
20022
|
-
|
|
20179
|
+
const gridNavOn = columns.some((col) => col.gridNav);
|
|
20180
|
+
return (
|
|
20181
|
+
// 키 이벤트를 모아 받을 뿐 이 요소 자체는 상호작용 요소가 아니다 — role 을 바꾸지 않는다
|
|
20182
|
+
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
|
|
20183
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
20184
|
+
"div",
|
|
20185
|
+
{
|
|
20186
|
+
className: cn("flex flex-col", className),
|
|
20187
|
+
style: { width, ...style },
|
|
20188
|
+
"data-table-id": resolvedTableId,
|
|
20189
|
+
onKeyDown: gridNavOn ? handleGridKeyNav : void 0,
|
|
20190
|
+
children: [
|
|
20191
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
20192
|
+
"div",
|
|
20193
|
+
{
|
|
20194
|
+
className: cn(
|
|
20195
|
+
// isolate: no-data/loading 오버레이(z-30·31)를 테이블 안에서 끝낸다. relative + z-auto
|
|
20196
|
+
// 만으로는 스태킹 컨텍스트가 생기지 않아, 모달 안에 들어가면 30·31이 모달 Content
|
|
20197
|
+
// 레벨까지 올라가 같은 컨텍스트의 floating portal 밴드(z-2)를 덮는다.
|
|
20198
|
+
// 자손은 이미 overflow-hidden으로 클리핑되므로 테이블 내부 순서는 달라지지 않는다.
|
|
20199
|
+
"bg-white relative isolate flex flex-col overflow-hidden",
|
|
20200
|
+
bordered && "border border-solid border-[color:var(--cmp-table-border-color)]",
|
|
20201
|
+
// height가 없으면 루트가 받은 높이를 끝까지 채운다. 호스트가 className으로
|
|
20202
|
+
// `flex-1 min-h-0` 등을 줘 루트 높이가 확정된 경우, 행이 적어도 테두리 박스가
|
|
20203
|
+
// 남은 영역을 그대로 차지한다. basis는 auto로 둬 높이가 확정되지 않은
|
|
20204
|
+
// 기본 사용(내용만큼 커지는 케이스)에서는 동작이 바뀌지 않는다.
|
|
20205
|
+
!height && "min-h-0 grow",
|
|
20206
|
+
radiusClass,
|
|
20207
|
+
// 원본 sd-table__scroll-container--loading/--no-data: 로딩·데이터 없음 시 인터랙션 차단
|
|
20208
|
+
(loading2 || rowCount === 0) && "pointer-events-none"
|
|
20209
|
+
),
|
|
20210
|
+
style: {
|
|
20211
|
+
height,
|
|
20212
|
+
minHeight: isNoData ? "calc(var(--cmp-table-header-height) + 60px)" : void 0
|
|
20213
|
+
},
|
|
20214
|
+
children: [
|
|
20215
|
+
showNoDataSlot ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
20216
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-none overflow-hidden", children: headerTable }),
|
|
20217
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(bodyScrollClass, "pointer-events-auto bg-white"), children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full min-h-[60px] w-full items-center justify-center", children: emptySlot }) })
|
|
20218
|
+
] }) : (
|
|
20219
|
+
/**
|
|
20220
|
+
* 헤더와 body 가 한 스크롤 컨테이너에 있다 — 헤더는 위에 붙어(sticky) 세로로는 서 있고
|
|
20221
|
+
* 가로로는 body 와 같은 스크롤로 움직인다. 헤더를 따로 두고 scroll 이벤트에서
|
|
20222
|
+
* scrollLeft 를 맞추면, 브라우저가 body 스크롤을 먼저 그리고 이벤트를 나중에 돌려
|
|
20223
|
+
* 헤더가 한 프레임 이상 늦게 따라온다.
|
|
20224
|
+
*
|
|
20225
|
+
* 행 좌표는 body 표 기준 그대로다 — `scrollTop` 이 y 이면 y 에 있는 행이 헤더 바로
|
|
20226
|
+
* 아래에 선다. 보이는 높이만 헤더 높이만큼 줄어든다(`headerHeight`).
|
|
20227
|
+
*/
|
|
20228
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
20229
|
+
"div",
|
|
20230
|
+
{
|
|
20231
|
+
ref: scrollRef,
|
|
20232
|
+
onScroll: handleScrollEvent,
|
|
20233
|
+
className: cn(
|
|
20234
|
+
bodyScrollClass,
|
|
20235
|
+
// 원본 sd-table__scroll-container--loading/--no-data: 로딩·데이터 없음 시 스크롤 차단
|
|
20236
|
+
(loading2 || rowCount === 0) && "overflow-hidden"
|
|
20237
|
+
),
|
|
20238
|
+
style: { scrollPaddingTop: headerHeight },
|
|
20239
|
+
children: [
|
|
20240
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: headerRef, className: "sticky top-0 z-[8]", children: headerTable }),
|
|
20241
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
20242
|
+
"table",
|
|
20243
|
+
{
|
|
20244
|
+
className: "w-full table-fixed border-separate border-spacing-0 text-left",
|
|
20245
|
+
style: { fontSize: 12 },
|
|
20246
|
+
children: [
|
|
20247
|
+
colgroup,
|
|
20248
|
+
/* @__PURE__ */ jsxRuntime.jsxs("tbody", { children: [
|
|
20249
|
+
virtualScroll && topSpacer > 0 && /* @__PURE__ */ jsxRuntime.jsx("tr", { "aria-hidden": true, style: { height: topSpacer }, children: /* @__PURE__ */ jsxRuntime.jsx("td", { colSpan: totalColSpan, className: "p-0" }) }),
|
|
20250
|
+
rowCount === 0 ? null : bodyRows.map((row, ri) => {
|
|
20251
|
+
const rowIndex = rowOffset + ri;
|
|
20252
|
+
const isSel = isViewSelected(row);
|
|
20253
|
+
const dragSel = dragSelectOn && isSel;
|
|
20254
|
+
const dragTop = dragSel && !isViewSelected(rows[rowIndex - 1]);
|
|
20255
|
+
const dragBottom = dragSel && !isViewSelected(rows[rowIndex + 1]);
|
|
20256
|
+
const rowLocked = (selectable || dragSelectable) && !canSelectRow(row);
|
|
20257
|
+
const rowBg = "bg-white";
|
|
20258
|
+
const rowHover = hoverable && !rowLocked;
|
|
20259
|
+
const expansionShown = expansionOn && shownExpansionSet.has(row[rowKey]);
|
|
20260
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(react.Fragment, { children: [
|
|
20261
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
20262
|
+
"tr",
|
|
20263
|
+
{
|
|
20264
|
+
"data-row-index": rowIndex,
|
|
20265
|
+
onClick: onRowClick ? (event) => {
|
|
20266
|
+
const target = event.target;
|
|
20267
|
+
if (target.closest(ROW_INTERACTIVE_SELECTOR)) return;
|
|
20268
|
+
onRowClick(row);
|
|
20269
|
+
} : void 0,
|
|
20270
|
+
onDoubleClick: onRowDoubleClick ? (event) => {
|
|
20271
|
+
const target = event.target;
|
|
20272
|
+
if (target.closest(ROW_INTERACTIVE_SELECTOR)) return;
|
|
20273
|
+
onRowDoubleClick(row);
|
|
20274
|
+
} : void 0,
|
|
20275
|
+
onMouseDown: dragSelectOn ? (event) => startDragSelect(rowIndex, event) : void 0,
|
|
20276
|
+
onMouseEnter: dragSelectOn ? () => extendDragSelect(rowIndex) : void 0,
|
|
20277
|
+
onContextMenu: contextMenuOn ? (event) => openContextMenu(row, event) : void 0,
|
|
20278
|
+
className: cn(
|
|
20279
|
+
"group/table-row",
|
|
20280
|
+
rowHover && "hover:bg-[var(--color-grey-05)]",
|
|
20281
|
+
(onRowClick || onRowDoubleClick) && "cursor-pointer",
|
|
20282
|
+
dragSelectOn && "select-none",
|
|
20283
|
+
rowClassName?.(row)
|
|
20284
|
+
),
|
|
20285
|
+
style: { height: virtualScroll ? effectiveRowHeight : rowH },
|
|
20286
|
+
children: [
|
|
20287
|
+
selectable && /* @__PURE__ */ jsxRuntime.jsx(
|
|
20288
|
+
"td",
|
|
20289
|
+
{
|
|
20290
|
+
className: cn(
|
|
20291
|
+
// 원본 .td--selected: 48px 고정폭, 항상 left sticky, 체크박스 중앙정렬
|
|
20292
|
+
"sticky left-0 z-[2] border-b border-solid border-[color:var(--cmp-table-border-color)] align-middle",
|
|
20293
|
+
rowBg,
|
|
20294
|
+
rowHover && "group-hover/table-row:bg-[var(--color-grey-05)]",
|
|
20295
|
+
stickyLeft === 0 && scrolledLeft && "shadow-[5px_0_8px_0_rgba(34,34,34,0.1)]"
|
|
20296
|
+
),
|
|
20297
|
+
style: {
|
|
20298
|
+
width: SELECTABLE_COLUMN_WIDTH,
|
|
20299
|
+
minWidth: SELECTABLE_COLUMN_WIDTH,
|
|
20300
|
+
maxWidth: SELECTABLE_COLUMN_WIDTH,
|
|
20301
|
+
// 선택 열도 행의 일부다 — 여기만 희지 않으면 회색 줄이 끊긴다
|
|
20302
|
+
background: rowLocked ? LOCKED_BG : void 0
|
|
20303
|
+
},
|
|
20304
|
+
onClick: (e) => e.stopPropagation(),
|
|
20305
|
+
onDoubleClick: (e) => e.stopPropagation(),
|
|
20306
|
+
onClickCapture: (e) => {
|
|
20307
|
+
shiftPressedRef.current = e.shiftKey;
|
|
20308
|
+
if (e.shiftKey) window.getSelection()?.removeAllRanges();
|
|
20309
|
+
},
|
|
20310
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex select-none items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
20311
|
+
SCheckbox,
|
|
20312
|
+
{
|
|
20313
|
+
value: isSel || !isRowIndeterminate?.(row) ? isSel : null,
|
|
20314
|
+
disabled: !canSelectRow(row),
|
|
20315
|
+
onValueChange: () => toggleRow(row, rowOffset + ri),
|
|
20316
|
+
ariaLabel: rowSelectLabel?.(row) ?? t.selectRow
|
|
20317
|
+
}
|
|
20318
|
+
) })
|
|
20319
|
+
}
|
|
20320
|
+
),
|
|
20321
|
+
visibleCols.map((col, i) => {
|
|
20322
|
+
const tdClassName = cn(
|
|
20323
|
+
// 원본 .td: 컬럼 폭에 맞춰 내용 말줄임(overflow hidden + ellipsis) + 행 구분선(border-b)
|
|
20324
|
+
// 셀 배경은 흰색으로 채워 뒤 배경이 비치지 않게 하고, hover 시 행 배경(grey_05)을 따른다.
|
|
20325
|
+
"overflow-hidden text-ellipsis whitespace-nowrap border-b border-solid border-[color:var(--cmp-table-border-color)] text-[12px] leading-[20px] text-[color:var(--sys-color-fg-primary)]",
|
|
20023
20326
|
rowBg,
|
|
20024
20327
|
rowHover && "group-hover/table-row:bg-[var(--color-grey-05)]",
|
|
20025
|
-
|
|
20026
|
-
)
|
|
20027
|
-
|
|
20028
|
-
|
|
20029
|
-
|
|
20030
|
-
|
|
20031
|
-
|
|
20032
|
-
|
|
20033
|
-
|
|
20034
|
-
|
|
20035
|
-
|
|
20036
|
-
|
|
20037
|
-
|
|
20038
|
-
|
|
20039
|
-
|
|
20040
|
-
|
|
20041
|
-
|
|
20042
|
-
|
|
20043
|
-
|
|
20044
|
-
|
|
20045
|
-
|
|
20046
|
-
|
|
20047
|
-
|
|
20048
|
-
|
|
20049
|
-
|
|
20050
|
-
|
|
20051
|
-
|
|
20052
|
-
|
|
20053
|
-
|
|
20054
|
-
|
|
20055
|
-
|
|
20056
|
-
|
|
20057
|
-
|
|
20058
|
-
|
|
20059
|
-
|
|
20060
|
-
|
|
20061
|
-
|
|
20062
|
-
|
|
20063
|
-
|
|
20064
|
-
i ===
|
|
20065
|
-
|
|
20066
|
-
|
|
20067
|
-
|
|
20068
|
-
|
|
20069
|
-
|
|
20070
|
-
|
|
20071
|
-
|
|
20072
|
-
|
|
20073
|
-
|
|
20074
|
-
|
|
20075
|
-
|
|
20076
|
-
|
|
20077
|
-
|
|
20078
|
-
|
|
20079
|
-
|
|
20080
|
-
|
|
20081
|
-
|
|
20082
|
-
if (col.renderCell) {
|
|
20083
|
-
const cell = col.renderCell({
|
|
20084
|
-
row,
|
|
20085
|
-
value: cellValue(col, row),
|
|
20086
|
-
column: col,
|
|
20087
|
-
colIndex: i,
|
|
20088
|
-
rowIndex: ri,
|
|
20089
|
-
isSelected: isSel,
|
|
20090
|
-
className: tdClassName,
|
|
20091
|
-
style: tdStyle
|
|
20092
|
-
});
|
|
20093
|
-
if (cell == null || cell === false) return null;
|
|
20094
|
-
return /* @__PURE__ */ jsxRuntime.jsx(react.Fragment, { children: cell }, col.name);
|
|
20095
|
-
}
|
|
20096
|
-
const content = col.render ? col.render(row, cellValue(col, row)) : cellValue(col, row);
|
|
20097
|
-
if (i === expansionColIndex) {
|
|
20328
|
+
typeof col.tdClass === "function" ? col.tdClass(row) : col.tdClass
|
|
20329
|
+
);
|
|
20330
|
+
const tdPadX = cellPadXOf(col);
|
|
20331
|
+
const dragEdges = dragSel ? [
|
|
20332
|
+
dragTop && `inset 0 ${DRAG_EDGE_W} 0 0 ${DRAG_EDGE_C}`,
|
|
20333
|
+
dragBottom && `inset 0 ${DRAG_EDGE_NEG_W} 0 0 ${DRAG_EDGE_C}`,
|
|
20334
|
+
i === 0 && `inset ${DRAG_EDGE_W} 0 0 0 ${DRAG_EDGE_C}`,
|
|
20335
|
+
i === visibleCols.length - 1 && `inset ${DRAG_EDGE_NEG_W} 0 0 0 ${DRAG_EDGE_C}`
|
|
20336
|
+
].filter(Boolean) : [];
|
|
20337
|
+
const shadows = [...dragEdges, stickyShadowValue(i)].filter(Boolean);
|
|
20338
|
+
const tdStyle = {
|
|
20339
|
+
paddingLeft: tdPadX,
|
|
20340
|
+
paddingRight: tdPadX,
|
|
20341
|
+
paddingTop: cellPadY,
|
|
20342
|
+
paddingBottom: cellPadY,
|
|
20343
|
+
textAlign: col.align ?? "left",
|
|
20344
|
+
// 인라인이라 hover 배경보다 세다 — 고른 행은 hover 로 흐려지지 않는다.
|
|
20345
|
+
background: dragSel ? DRAG_BG : rowLocked ? LOCKED_BG : void 0,
|
|
20346
|
+
// 클래스의 기본 글자색을 덮는다. 셀이 자기 색을 정한 내용(SIcon 의
|
|
20347
|
+
// color, STag 등)까지는 닿지 않는다 — 그건 소비 앱 몫이다.
|
|
20348
|
+
color: rowLocked ? LOCKED_CONTENT : void 0,
|
|
20349
|
+
boxShadow: shadows.length > 0 ? shadows.join(", ") : void 0,
|
|
20350
|
+
...cellStyle(i)
|
|
20351
|
+
};
|
|
20352
|
+
if (col.renderCell) {
|
|
20353
|
+
const cell = col.renderCell({
|
|
20354
|
+
row,
|
|
20355
|
+
value: cellValue(col, row),
|
|
20356
|
+
column: col,
|
|
20357
|
+
colIndex: i,
|
|
20358
|
+
rowIndex: ri,
|
|
20359
|
+
isSelected: isSel,
|
|
20360
|
+
className: tdClassName,
|
|
20361
|
+
style: tdStyle
|
|
20362
|
+
});
|
|
20363
|
+
if (cell == null || cell === false) return null;
|
|
20364
|
+
return /* @__PURE__ */ jsxRuntime.jsx(react.Fragment, { children: cell }, col.name);
|
|
20365
|
+
}
|
|
20366
|
+
const content = col.render ? col.render(row, cellValue(col, row)) : cellValue(col, row);
|
|
20367
|
+
if (i === expansionColIndex) {
|
|
20368
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
20369
|
+
"td",
|
|
20370
|
+
{
|
|
20371
|
+
className: cn(tdClassName, "cursor-pointer"),
|
|
20372
|
+
style: tdStyle,
|
|
20373
|
+
"data-grid-nav": col.gridNav ? col.name : void 0,
|
|
20374
|
+
onClick: (event) => {
|
|
20375
|
+
if (isOwnControl(event.target, event.currentTarget)) return;
|
|
20376
|
+
event.stopPropagation();
|
|
20377
|
+
toggleExpanded(row);
|
|
20378
|
+
},
|
|
20379
|
+
onDoubleClick: (event) => event.stopPropagation(),
|
|
20380
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ExpansionToggleCell, { expanded: isRowExpanded(row), children: content })
|
|
20381
|
+
},
|
|
20382
|
+
col.name
|
|
20383
|
+
);
|
|
20384
|
+
}
|
|
20098
20385
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
20099
20386
|
"td",
|
|
20100
20387
|
{
|
|
20101
|
-
className:
|
|
20388
|
+
className: tdClassName,
|
|
20102
20389
|
style: tdStyle,
|
|
20103
|
-
|
|
20104
|
-
|
|
20105
|
-
event.stopPropagation();
|
|
20106
|
-
toggleExpanded(row);
|
|
20107
|
-
},
|
|
20108
|
-
onDoubleClick: (event) => event.stopPropagation(),
|
|
20109
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(ExpansionToggleCell, { expanded: isRowExpanded(row), children: content })
|
|
20390
|
+
"data-grid-nav": col.gridNav ? col.name : void 0,
|
|
20391
|
+
children: content
|
|
20110
20392
|
},
|
|
20111
20393
|
col.name
|
|
20112
20394
|
);
|
|
20395
|
+
})
|
|
20396
|
+
]
|
|
20397
|
+
}
|
|
20398
|
+
),
|
|
20399
|
+
expansionShown && // 상세 영역 — 행이 아니므로 data-row-index 를 달지 않는다 (행 수·선택·실측 대상 밖)
|
|
20400
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
20401
|
+
"tr",
|
|
20402
|
+
{
|
|
20403
|
+
"data-expansion-row": "",
|
|
20404
|
+
"data-expansion-key": String(row[rowKey]),
|
|
20405
|
+
className: expandedSet.has(row[rowKey]) ? void 0 : "pointer-events-none",
|
|
20406
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
20407
|
+
"td",
|
|
20408
|
+
{
|
|
20409
|
+
colSpan: totalColSpan,
|
|
20410
|
+
className: "whitespace-normal border-b border-solid border-[color:var(--cmp-table-border-color)] bg-white p-0 text-[12px] leading-[20px] text-[color:var(--sys-color-fg-primary)]",
|
|
20411
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
20412
|
+
"div",
|
|
20413
|
+
{
|
|
20414
|
+
className: "sticky left-0 box-border min-w-0",
|
|
20415
|
+
style: {
|
|
20416
|
+
// 가로 스크롤이 있어도 보이는 폭에 머문다. 재기 전(0)에는 표 폭을 따른다
|
|
20417
|
+
width: viewportWidth > 0 ? viewportWidth : void 0,
|
|
20418
|
+
paddingLeft: "var(--cmp-table-body-paddingX-wide)",
|
|
20419
|
+
paddingRight: "var(--cmp-table-body-paddingX-wide)",
|
|
20420
|
+
paddingTop: cellPadY,
|
|
20421
|
+
paddingBottom: cellPadY
|
|
20422
|
+
},
|
|
20423
|
+
children: renderExpansion?.(row)
|
|
20424
|
+
}
|
|
20425
|
+
)
|
|
20113
20426
|
}
|
|
20114
|
-
|
|
20115
|
-
|
|
20116
|
-
|
|
20117
|
-
|
|
20118
|
-
|
|
20119
|
-
|
|
20120
|
-
|
|
20121
|
-
|
|
20122
|
-
|
|
20123
|
-
|
|
20124
|
-
|
|
20125
|
-
|
|
20126
|
-
|
|
20127
|
-
"td",
|
|
20128
|
-
{
|
|
20129
|
-
colSpan: totalColSpan,
|
|
20130
|
-
className: "whitespace-normal border-b border-solid border-[color:var(--cmp-table-border-color)] bg-white p-0 text-[12px] leading-[20px] text-[color:var(--sys-color-fg-primary)]",
|
|
20131
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
20132
|
-
"div",
|
|
20133
|
-
{
|
|
20134
|
-
className: "sticky left-0 box-border min-w-0",
|
|
20135
|
-
style: {
|
|
20136
|
-
// 가로 스크롤이 있어도 보이는 폭에 머문다. 재기 전(0)에는 표 폭을 따른다
|
|
20137
|
-
width: viewportWidth > 0 ? viewportWidth : void 0,
|
|
20138
|
-
paddingLeft: "var(--cmp-table-body-paddingX-wide)",
|
|
20139
|
-
paddingRight: "var(--cmp-table-body-paddingX-wide)",
|
|
20140
|
-
paddingTop: cellPadY,
|
|
20141
|
-
paddingBottom: cellPadY
|
|
20142
|
-
},
|
|
20143
|
-
children: renderExpansion?.(row)
|
|
20144
|
-
}
|
|
20145
|
-
)
|
|
20146
|
-
}
|
|
20147
|
-
)
|
|
20148
|
-
}
|
|
20149
|
-
)
|
|
20150
|
-
] }, row[rowKey] ?? ri);
|
|
20151
|
-
}),
|
|
20152
|
-
virtualScroll && bottomSpacer > 0 && /* @__PURE__ */ jsxRuntime.jsx("tr", { "aria-hidden": true, style: { height: bottomSpacer }, children: /* @__PURE__ */ jsxRuntime.jsx("td", { colSpan: totalColSpan, className: "p-0" }) })
|
|
20153
|
-
] })
|
|
20154
|
-
]
|
|
20155
|
-
}
|
|
20156
|
-
)
|
|
20157
|
-
]
|
|
20158
|
-
}
|
|
20159
|
-
)
|
|
20160
|
-
),
|
|
20161
|
-
isNoData && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
20162
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
20163
|
-
"div",
|
|
20164
|
-
{
|
|
20165
|
-
"aria-hidden": true,
|
|
20166
|
-
className: "pointer-events-none absolute left-0 right-0 top-0 z-[31] h-[var(--cmp-table-header-height)] bg-white/60"
|
|
20167
|
-
}
|
|
20168
|
-
),
|
|
20169
|
-
!showNoDataSlot && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-none absolute bottom-0 left-0 right-0 top-[var(--cmp-table-header-height)] z-[30] flex items-center justify-center bg-white/60 text-[12px] text-[color:var(--color-grey-65)]", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-[60px] w-full items-center justify-center", children: emptyLabel }) })
|
|
20170
|
-
] }),
|
|
20171
|
-
loading2 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 z-30 flex items-center justify-center bg-white/60", children: /* @__PURE__ */ jsxRuntime.jsx(SCircleProgress, { indeterminate: true }) })
|
|
20172
|
-
]
|
|
20173
|
-
}
|
|
20174
|
-
),
|
|
20175
|
-
(showPagination || showRowsPerPageSelect) && // 원본 sd-table__pagination: 테이블 하단에 이어붙는 회색 바(높이 48px, margin-top:-1px로 테두리 겹침).
|
|
20176
|
-
// SPagination은 전체 폭 기준 중앙, rows-per-page SSelect는 우측에 absolute 배치해 중앙 정렬을 유지한다.
|
|
20177
|
-
// 루트 높이가 확정된 경우(테이블이 남은 영역을 채우는 배치) 페이지네이션 바가
|
|
20178
|
-
// 눌리지 않도록 shrink-0으로 48px를 보장한다.
|
|
20179
|
-
// 페이지네이션이 없어도 rows-per-page 셀렉트가 있으면 이 바를 그린다 — 셀렉트와
|
|
20180
|
-
// 밀도 토글이 사는 곳이 여기다. dense 만으로는 그리지 않는다(빈 바가 남는다).
|
|
20181
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
20182
|
-
"div",
|
|
20183
|
-
{
|
|
20184
|
-
className: cn(
|
|
20185
|
-
"relative flex h-[48px] shrink-0 items-center justify-center rounded-[var(--cmp-table-radius)] bg-[var(--color-grey-05)]",
|
|
20186
|
-
// 테두리를 끄면 겹칠 대상이 없어진다 — -mt-px 를 남기면 1px 어긋남만 생긴다.
|
|
20187
|
-
bordered && "-mt-px border border-solid border-[color:var(--cmp-table-border-color)]"
|
|
20188
|
-
),
|
|
20189
|
-
children: [
|
|
20190
|
-
showPagination && /* @__PURE__ */ jsxRuntime.jsx(SPagination, { currentPage: displayPage, lastPage, onPageChange: changePage }),
|
|
20191
|
-
showRowsPerPageSelect && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute right-[10px] top-1/2 flex -translate-y-1/2 items-center gap-[12px]", children: [
|
|
20192
|
-
dense && /* @__PURE__ */ jsxRuntime.jsx(
|
|
20193
|
-
STextLink,
|
|
20194
|
-
{
|
|
20195
|
-
size: "sm",
|
|
20196
|
-
icon: innerDense ? "row" : "rowDense",
|
|
20197
|
-
iconRotate: 90,
|
|
20198
|
-
iconColor: "var(--sys-color-fg-quaternary)",
|
|
20199
|
-
label: innerDense ? t.denseOff : t.denseOn,
|
|
20200
|
-
onClick: () => changeDense(!innerDense)
|
|
20201
|
-
}
|
|
20427
|
+
)
|
|
20428
|
+
}
|
|
20429
|
+
)
|
|
20430
|
+
] }, row[rowKey] ?? ri);
|
|
20431
|
+
}),
|
|
20432
|
+
virtualScroll && bottomSpacer > 0 && /* @__PURE__ */ jsxRuntime.jsx("tr", { "aria-hidden": true, style: { height: bottomSpacer }, children: /* @__PURE__ */ jsxRuntime.jsx("td", { colSpan: totalColSpan, className: "p-0" }) })
|
|
20433
|
+
] })
|
|
20434
|
+
]
|
|
20435
|
+
}
|
|
20436
|
+
)
|
|
20437
|
+
]
|
|
20438
|
+
}
|
|
20439
|
+
)
|
|
20202
20440
|
),
|
|
20203
|
-
|
|
20204
|
-
|
|
20205
|
-
|
|
20206
|
-
|
|
20207
|
-
|
|
20208
|
-
|
|
20209
|
-
|
|
20210
|
-
|
|
20211
|
-
|
|
20212
|
-
|
|
20213
|
-
)
|
|
20214
|
-
]
|
|
20215
|
-
|
|
20216
|
-
|
|
20217
|
-
|
|
20218
|
-
|
|
20441
|
+
isNoData && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
20442
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
20443
|
+
"div",
|
|
20444
|
+
{
|
|
20445
|
+
"aria-hidden": true,
|
|
20446
|
+
className: "pointer-events-none absolute left-0 right-0 top-0 z-[31] h-[var(--cmp-table-header-height)] bg-white/60"
|
|
20447
|
+
}
|
|
20448
|
+
),
|
|
20449
|
+
!showNoDataSlot && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-none absolute bottom-0 left-0 right-0 top-[var(--cmp-table-header-height)] z-[30] flex items-center justify-center bg-white/60 text-[12px] text-[color:var(--color-grey-65)]", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-[60px] w-full items-center justify-center", children: emptyLabel }) })
|
|
20450
|
+
] }),
|
|
20451
|
+
loading2 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 z-30 flex items-center justify-center bg-white/60", children: /* @__PURE__ */ jsxRuntime.jsx(SCircleProgress, { indeterminate: true }) })
|
|
20452
|
+
]
|
|
20453
|
+
}
|
|
20454
|
+
),
|
|
20455
|
+
(showPagination || showRowsPerPageSelect) && // 원본 sd-table__pagination: 테이블 하단에 이어붙는 회색 바(높이 48px, margin-top:-1px로 테두리 겹침).
|
|
20456
|
+
// SPagination은 전체 폭 기준 중앙, rows-per-page SSelect는 우측에 absolute 배치해 중앙 정렬을 유지한다.
|
|
20457
|
+
// 루트 높이가 확정된 경우(테이블이 남은 영역을 채우는 배치) 페이지네이션 바가
|
|
20458
|
+
// 눌리지 않도록 shrink-0으로 48px를 보장한다.
|
|
20459
|
+
// 페이지네이션이 없어도 rows-per-page 셀렉트가 있으면 이 바를 그린다 — 셀렉트와
|
|
20460
|
+
// 밀도 토글이 사는 곳이 여기다. dense 만으로는 그리지 않는다(빈 바가 남는다).
|
|
20219
20461
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
20220
|
-
|
|
20462
|
+
"div",
|
|
20221
20463
|
{
|
|
20222
|
-
|
|
20223
|
-
|
|
20224
|
-
|
|
20225
|
-
|
|
20226
|
-
|
|
20464
|
+
className: cn(
|
|
20465
|
+
"relative flex h-[48px] shrink-0 items-center justify-center rounded-[var(--cmp-table-radius)] bg-[var(--color-grey-05)]",
|
|
20466
|
+
// 테두리를 끄면 겹칠 대상이 없어진다 — -mt-px 를 남기면 1px 어긋남만 생긴다.
|
|
20467
|
+
bordered && "-mt-px border border-solid border-[color:var(--cmp-table-border-color)]"
|
|
20468
|
+
),
|
|
20227
20469
|
children: [
|
|
20228
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
20229
|
-
|
|
20230
|
-
|
|
20231
|
-
|
|
20232
|
-
|
|
20233
|
-
|
|
20234
|
-
|
|
20235
|
-
|
|
20236
|
-
|
|
20237
|
-
|
|
20238
|
-
|
|
20239
|
-
|
|
20240
|
-
|
|
20241
|
-
|
|
20242
|
-
|
|
20243
|
-
|
|
20244
|
-
|
|
20245
|
-
|
|
20246
|
-
|
|
20247
|
-
|
|
20248
|
-
|
|
20249
|
-
|
|
20250
|
-
|
|
20251
|
-
|
|
20252
|
-
|
|
20253
|
-
disabled: item4.disabled,
|
|
20254
|
-
onSelect: () => onContextMenuItemClick?.(item4.value, contextMenu?.rows ?? []),
|
|
20255
|
-
className: CONTEXT_MENU_ITEM_CLASS,
|
|
20256
|
-
children: [
|
|
20257
|
-
item4.icon && /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: item4.icon, size: 12 }),
|
|
20258
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 break-words", children: item4.label })
|
|
20259
|
-
]
|
|
20260
|
-
},
|
|
20261
|
-
item4.value
|
|
20262
|
-
))
|
|
20263
|
-
}
|
|
20264
|
-
)
|
|
20470
|
+
showPagination && /* @__PURE__ */ jsxRuntime.jsx(SPagination, { currentPage: displayPage, lastPage, onPageChange: changePage }),
|
|
20471
|
+
showRowsPerPageSelect && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute right-[10px] top-1/2 flex -translate-y-1/2 items-center gap-[12px]", children: [
|
|
20472
|
+
dense && /* @__PURE__ */ jsxRuntime.jsx(
|
|
20473
|
+
STextLink,
|
|
20474
|
+
{
|
|
20475
|
+
size: "sm",
|
|
20476
|
+
icon: innerDense ? "row" : "rowDense",
|
|
20477
|
+
iconRotate: 90,
|
|
20478
|
+
iconColor: "var(--sys-color-fg-quaternary)",
|
|
20479
|
+
label: innerDense ? t.denseOff : t.denseOn,
|
|
20480
|
+
onClick: () => changeDense(!innerDense)
|
|
20481
|
+
}
|
|
20482
|
+
),
|
|
20483
|
+
dense && /* @__PURE__ */ jsxRuntime.jsx(SDivider, { vertical: true, className: "my-[6px]" }),
|
|
20484
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
20485
|
+
SSelect2,
|
|
20486
|
+
{
|
|
20487
|
+
options: rowsPerPageOption,
|
|
20488
|
+
value: internalPagination ? innerRowsPerPage : pagination?.rowsPerPage,
|
|
20489
|
+
valueAsPrimitive: true,
|
|
20490
|
+
onValueChange: (v) => changeRowsPerPage(Number(v)),
|
|
20491
|
+
width: 128
|
|
20492
|
+
}
|
|
20493
|
+
)
|
|
20494
|
+
] })
|
|
20265
20495
|
]
|
|
20266
|
-
}
|
|
20267
|
-
contextMenu == null ? "closed" : `${contextMenu.x},${contextMenu.y}`
|
|
20496
|
+
}
|
|
20268
20497
|
),
|
|
20269
|
-
|
|
20270
|
-
|
|
20271
|
-
|
|
20272
|
-
|
|
20498
|
+
contextMenuOn && typeof document !== "undefined" && reactDom.createPortal(
|
|
20499
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
20500
|
+
RDropdown5__namespace.Root,
|
|
20501
|
+
{
|
|
20502
|
+
modal: false,
|
|
20503
|
+
open: contextMenuOpen,
|
|
20504
|
+
onOpenChange: (open) => {
|
|
20505
|
+
if (!open) setContextMenu((m) => m == null ? null : { ...m, open: false });
|
|
20506
|
+
},
|
|
20507
|
+
children: [
|
|
20508
|
+
/* @__PURE__ */ jsxRuntime.jsx(RDropdown5__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
20509
|
+
"span",
|
|
20510
|
+
{
|
|
20511
|
+
"aria-hidden": true,
|
|
20512
|
+
className: "pointer-events-none fixed block h-0 w-0",
|
|
20513
|
+
style: { left: contextMenu?.x ?? 0, top: contextMenu?.y ?? 0 }
|
|
20514
|
+
}
|
|
20515
|
+
) }),
|
|
20516
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
20517
|
+
RDropdown5__namespace.Content,
|
|
20518
|
+
{
|
|
20519
|
+
align: "start",
|
|
20520
|
+
side: "bottom",
|
|
20521
|
+
sideOffset: CONTEXT_MENU_CURSOR_GAP,
|
|
20522
|
+
alignOffset: CONTEXT_MENU_CURSOR_GAP,
|
|
20523
|
+
collisionPadding: CONTEXT_MENU_VIEWPORT_PADDING,
|
|
20524
|
+
style: contextMenuArmed ? void 0 : { pointerEvents: "none" },
|
|
20525
|
+
className: cn(
|
|
20526
|
+
"z-50 overflow-hidden rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] shadow-normal-sm",
|
|
20527
|
+
"max-w-[var(--radix-dropdown-menu-content-available-width)]",
|
|
20528
|
+
FLOATING_SLIDE_ANIM
|
|
20529
|
+
),
|
|
20530
|
+
children: contextMenuItems?.map((item4) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
20531
|
+
RDropdown5__namespace.Item,
|
|
20532
|
+
{
|
|
20533
|
+
disabled: item4.disabled,
|
|
20534
|
+
onSelect: () => onContextMenuItemClick?.(item4.value, contextMenu?.rows ?? []),
|
|
20535
|
+
className: CONTEXT_MENU_ITEM_CLASS,
|
|
20536
|
+
children: [
|
|
20537
|
+
item4.icon && /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: item4.icon, size: 12 }),
|
|
20538
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 break-words", children: item4.label })
|
|
20539
|
+
]
|
|
20540
|
+
},
|
|
20541
|
+
item4.value
|
|
20542
|
+
))
|
|
20543
|
+
}
|
|
20544
|
+
)
|
|
20545
|
+
]
|
|
20546
|
+
},
|
|
20547
|
+
contextMenu == null ? "closed" : `${contextMenu.x},${contextMenu.y}`
|
|
20548
|
+
),
|
|
20549
|
+
portalContainer ?? document.body
|
|
20550
|
+
)
|
|
20551
|
+
]
|
|
20552
|
+
}
|
|
20553
|
+
)
|
|
20273
20554
|
);
|
|
20274
20555
|
});
|
|
20275
20556
|
var STable2 = STableImpl;
|