sellmate-design-system-react 9.0.0-beta.95 → 9.0.0-beta.98
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 +23 -2
- package/dist/components/SButton/README.md +1 -0
- package/dist/components/SButton/SButton.d.ts +9 -1
- package/dist/components/SSelect/README.md +1 -0
- package/dist/components/SSelect/SSelect.d.ts +8 -0
- package/dist/components/STable/README.md +15 -1
- package/dist/components/STable/STable.d.ts +45 -1
- package/dist/components/STable/index.d.ts +1 -1
- package/dist/components/STreeTable/STreeTable.d.ts +1 -1
- package/dist/index.cjs +399 -206
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +399 -206
- package/dist/index.js.map +1 -1
- package/dist/lib/row-motion.d.ts +56 -0
- package/dist/llms-full.txt +40 -3
- package/dist/llms.txt +23 -2
- package/dist/styles.css +9 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4232,6 +4232,7 @@ var SButton = /* @__PURE__ */ forwardRef(function SButton2({
|
|
|
4232
4232
|
icon,
|
|
4233
4233
|
rightIcon,
|
|
4234
4234
|
label,
|
|
4235
|
+
pill = false,
|
|
4235
4236
|
className,
|
|
4236
4237
|
style,
|
|
4237
4238
|
type = "button",
|
|
@@ -4262,7 +4263,8 @@ var SButton = /* @__PURE__ */ forwardRef(function SButton2({
|
|
|
4262
4263
|
"minHeight": s.height,
|
|
4263
4264
|
"minWidth": iconOnly ? s.iconOnlyWidth : hasLabel ? s.minWidth : void 0,
|
|
4264
4265
|
"padding": iconOnly ? 0 : `0 ${s.paddingX}`,
|
|
4265
|
-
|
|
4266
|
+
// 버튼 전용 pill 반경 토큰이 아직 없어 공용 반경을 쓴다
|
|
4267
|
+
"borderRadius": pill ? "var(--radius-full)" : s.radius,
|
|
4266
4268
|
"gap": s.gap,
|
|
4267
4269
|
"fontSize": s.fontSize,
|
|
4268
4270
|
"fontWeight": s.fontWeight,
|
|
@@ -15657,6 +15659,93 @@ function SCalendarBoard({
|
|
|
15657
15659
|
);
|
|
15658
15660
|
}
|
|
15659
15661
|
|
|
15662
|
+
// src/lib/row-motion.ts
|
|
15663
|
+
var EXPAND_MOTION = { duration: 220, easing: "ease-out" };
|
|
15664
|
+
var COLLAPSE_MOTION = { duration: 140, easing: "ease-in" };
|
|
15665
|
+
function sameKeys(a, b) {
|
|
15666
|
+
return a.size === b.size && [...a].every((key) => b.has(key));
|
|
15667
|
+
}
|
|
15668
|
+
function motionAllowed() {
|
|
15669
|
+
if (typeof window === "undefined" || typeof Element.prototype.animate !== "function")
|
|
15670
|
+
return false;
|
|
15671
|
+
return !window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
|
|
15672
|
+
}
|
|
15673
|
+
function startRowMotion({
|
|
15674
|
+
scrollEl,
|
|
15675
|
+
isInBlock,
|
|
15676
|
+
blockKeys,
|
|
15677
|
+
from,
|
|
15678
|
+
to
|
|
15679
|
+
}) {
|
|
15680
|
+
const spec = to === 1 ? EXPAND_MOTION : COLLAPSE_MOTION;
|
|
15681
|
+
const duration = spec.duration * Math.abs(to - from);
|
|
15682
|
+
if (duration < 1) return null;
|
|
15683
|
+
const trs = [
|
|
15684
|
+
...scrollEl.querySelectorAll("tr[data-row-index], tr[data-expansion-row]")
|
|
15685
|
+
].map((tr) => ({ tr, inBlock: isInBlock(tr), height: tr.getBoundingClientRect().height }));
|
|
15686
|
+
const viewBottom = scrollEl.scrollTop + scrollEl.clientHeight;
|
|
15687
|
+
const openAt = (offset) => from + (to - from) * offset;
|
|
15688
|
+
const translate = (shift2, s) => `translateY(${-shift2 * (1 - s)}px)`;
|
|
15689
|
+
const timing = {
|
|
15690
|
+
duration,
|
|
15691
|
+
easing: spec.easing,
|
|
15692
|
+
// 접힘은 남겨 둔 행이 빠질 때까지 끝 위치를 붙잡는다 — 놓으면 그 사이 한 프레임 제자리로 튄다
|
|
15693
|
+
fill: to === 0 ? "forwards" : "none"
|
|
15694
|
+
};
|
|
15695
|
+
const animations = [];
|
|
15696
|
+
let shift = 0;
|
|
15697
|
+
let blockHeight = 0;
|
|
15698
|
+
let y = 0;
|
|
15699
|
+
trs.forEach(({ tr, inBlock, height }, i) => {
|
|
15700
|
+
if (inBlock && !trs[i - 1]?.inBlock) {
|
|
15701
|
+
blockHeight = 0;
|
|
15702
|
+
for (let j = i; j < trs.length && trs[j].inBlock; j++) blockHeight += trs[j].height;
|
|
15703
|
+
shift += blockHeight;
|
|
15704
|
+
y = 0;
|
|
15705
|
+
}
|
|
15706
|
+
if (shift === 0 || tr.offsetTop - shift > viewBottom) return;
|
|
15707
|
+
if (!inBlock) {
|
|
15708
|
+
animations.push(
|
|
15709
|
+
tr.animate(
|
|
15710
|
+
[{ transform: translate(shift, from) }, { transform: translate(shift, to) }],
|
|
15711
|
+
timing
|
|
15712
|
+
)
|
|
15713
|
+
);
|
|
15714
|
+
return;
|
|
15715
|
+
}
|
|
15716
|
+
const rowY = y;
|
|
15717
|
+
const clipAt = (s) => Math.min(height, Math.max(0, blockHeight * (1 - s) - rowY));
|
|
15718
|
+
const bends = [1 - rowY / blockHeight, 1 - (rowY + height) / blockHeight].map((s) => (s - from) / (to - from)).filter((offset) => offset > 0 && offset < 1);
|
|
15719
|
+
const offsets = [0, ...bends, 1].sort((a, b) => a - b);
|
|
15720
|
+
animations.push(
|
|
15721
|
+
tr.animate(
|
|
15722
|
+
offsets.map((offset) => ({
|
|
15723
|
+
offset,
|
|
15724
|
+
transform: translate(shift, openAt(offset)),
|
|
15725
|
+
clipPath: `inset(${clipAt(openAt(offset))}px 0 0 0)`
|
|
15726
|
+
})),
|
|
15727
|
+
timing
|
|
15728
|
+
)
|
|
15729
|
+
);
|
|
15730
|
+
y += height;
|
|
15731
|
+
});
|
|
15732
|
+
if (animations.length === 0) return null;
|
|
15733
|
+
return {
|
|
15734
|
+
keys: blockKeys,
|
|
15735
|
+
to,
|
|
15736
|
+
done: false,
|
|
15737
|
+
finished: Promise.all(animations.map((animation) => animation.finished)).then(
|
|
15738
|
+
() => true,
|
|
15739
|
+
() => false
|
|
15740
|
+
),
|
|
15741
|
+
openness: () => {
|
|
15742
|
+
const progress = animations[0].effect?.getComputedTiming().progress;
|
|
15743
|
+
return progress == null ? to : openAt(progress);
|
|
15744
|
+
},
|
|
15745
|
+
cancel: () => animations.forEach((animation) => animation.cancel())
|
|
15746
|
+
};
|
|
15747
|
+
}
|
|
15748
|
+
|
|
15660
15749
|
// src/lib/row-metrics.ts
|
|
15661
15750
|
function createRowMetrics(count, estimate) {
|
|
15662
15751
|
const safeCount = Math.max(0, Math.floor(count));
|
|
@@ -16076,6 +16165,7 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
|
|
|
16076
16165
|
onSearchChange,
|
|
16077
16166
|
searchDebounce = DEFAULT_SEARCH_DEBOUNCE,
|
|
16078
16167
|
label,
|
|
16168
|
+
ariaLabel,
|
|
16079
16169
|
labelPosition,
|
|
16080
16170
|
subLabel,
|
|
16081
16171
|
labelWidth,
|
|
@@ -16778,6 +16868,7 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
|
|
|
16778
16868
|
style,
|
|
16779
16869
|
children: [
|
|
16780
16870
|
name && /* @__PURE__ */ jsx("input", { type: "hidden", name, value: selected.join(",") }),
|
|
16871
|
+
!label && ariaLabel && /* @__PURE__ */ jsx("span", { id: `${triggerId}-aria-label`, hidden: true, children: ariaLabel }),
|
|
16781
16872
|
/* @__PURE__ */ jsxs(
|
|
16782
16873
|
"div",
|
|
16783
16874
|
{
|
|
@@ -16786,7 +16877,7 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
|
|
|
16786
16877
|
role: "combobox",
|
|
16787
16878
|
tabIndex: effectiveDisabled ? -1 : 0,
|
|
16788
16879
|
"aria-disabled": effectiveDisabled || void 0,
|
|
16789
|
-
"aria-labelledby": label ? `${fieldLabelId(triggerId)} ${triggerId}` : triggerId,
|
|
16880
|
+
"aria-labelledby": label ? `${fieldLabelId(triggerId)} ${triggerId}` : ariaLabel ? `${triggerId}-aria-label ${triggerId}` : triggerId,
|
|
16790
16881
|
"aria-haspopup": isTree ? "tree" : "listbox",
|
|
16791
16882
|
"aria-expanded": open,
|
|
16792
16883
|
"aria-controls": open ? listboxId : void 0,
|
|
@@ -17394,6 +17485,7 @@ function CheckboxBox({
|
|
|
17394
17485
|
}
|
|
17395
17486
|
);
|
|
17396
17487
|
}
|
|
17488
|
+
var NO_KEYS = /* @__PURE__ */ new Set();
|
|
17397
17489
|
var DEFAULT_ROW_HEIGHT = 44;
|
|
17398
17490
|
var DENSE_ROW_HEIGHT = 32;
|
|
17399
17491
|
var SELECTABLE_COLUMN_WIDTH = 48;
|
|
@@ -17424,6 +17516,11 @@ var CONTEXT_MENU_ITEM_CLASS = cn(
|
|
|
17424
17516
|
"data-[highlighted]:bg-[var(--sys-color-bg-accent)] data-[highlighted]:text-[color:var(--sys-color-fg-inverse)]"
|
|
17425
17517
|
);
|
|
17426
17518
|
var ROW_INTERACTIVE_SELECTOR = 'button, a, input, select, textarea, label, [role="button"], [role="checkbox"], [contenteditable="true"]';
|
|
17519
|
+
function rowBlockHeight(tr) {
|
|
17520
|
+
const next = tr.nextElementSibling;
|
|
17521
|
+
const expansion = next instanceof HTMLElement && next.dataset.expansionRow != null ? next.offsetHeight : 0;
|
|
17522
|
+
return tr.offsetHeight + expansion;
|
|
17523
|
+
}
|
|
17427
17524
|
var colWidthFromDef = (c) => {
|
|
17428
17525
|
if (c.autoWidth) return 0;
|
|
17429
17526
|
if (c.width == null) return DEFAULT_COLUMN_WIDTH;
|
|
@@ -17436,6 +17533,8 @@ var STableImpl = /* @__PURE__ */ forwardRef(function STable({
|
|
|
17436
17533
|
rows = [],
|
|
17437
17534
|
rowKey = "id",
|
|
17438
17535
|
selectable = false,
|
|
17536
|
+
rowSelectLabel,
|
|
17537
|
+
selectAllLabel = "\uC804\uCCB4 \uC120\uD0DD",
|
|
17439
17538
|
dragSelectable = false,
|
|
17440
17539
|
contextMenuItems,
|
|
17441
17540
|
onContextMenuItemClick,
|
|
@@ -17474,6 +17573,11 @@ var STableImpl = /* @__PURE__ */ forwardRef(function STable({
|
|
|
17474
17573
|
tableId,
|
|
17475
17574
|
onRowClick,
|
|
17476
17575
|
onRowDoubleClick,
|
|
17576
|
+
renderExpansion,
|
|
17577
|
+
expansionColumn,
|
|
17578
|
+
expandedKeys,
|
|
17579
|
+
defaultExpandedKeys,
|
|
17580
|
+
onExpandedChange,
|
|
17477
17581
|
className,
|
|
17478
17582
|
style
|
|
17479
17583
|
}, ref) {
|
|
@@ -17488,6 +17592,44 @@ var STableImpl = /* @__PURE__ */ forwardRef(function STable({
|
|
|
17488
17592
|
onDenseChange?.(next);
|
|
17489
17593
|
};
|
|
17490
17594
|
const visibleCols = useMemo(() => columns.filter((c) => c.visible !== false), [columns]);
|
|
17595
|
+
const expansionOn = renderExpansion != null;
|
|
17596
|
+
const [innerExpandedKeys, setInnerExpandedKeys] = useState(
|
|
17597
|
+
() => defaultExpandedKeys ?? []
|
|
17598
|
+
);
|
|
17599
|
+
const currentExpandedKeys = expandedKeys ?? innerExpandedKeys;
|
|
17600
|
+
const expandedSet = useMemo(() => new Set(currentExpandedKeys), [currentExpandedKeys]);
|
|
17601
|
+
const isRowExpanded = (row) => expansionOn && expandedSet.has(row[rowKey]);
|
|
17602
|
+
const [closingKeys, setClosingKeys] = useState(NO_KEYS);
|
|
17603
|
+
const [prevExpandedSet, setPrevExpandedSet] = useState(expandedSet);
|
|
17604
|
+
if (prevExpandedSet !== expandedSet) {
|
|
17605
|
+
setPrevExpandedSet(expandedSet);
|
|
17606
|
+
let nextClosing = NO_KEYS;
|
|
17607
|
+
if (expansionOn && motionAllowed()) {
|
|
17608
|
+
const collapsed = [...prevExpandedSet].filter((key) => !expandedSet.has(key));
|
|
17609
|
+
const opened = [...expandedSet].filter((key) => !prevExpandedSet.has(key));
|
|
17610
|
+
if (collapsed.length > 0 && opened.length === 0) nextClosing = new Set(collapsed);
|
|
17611
|
+
}
|
|
17612
|
+
if (nextClosing !== closingKeys) setClosingKeys(nextClosing);
|
|
17613
|
+
}
|
|
17614
|
+
const shownExpansionSet = useMemo(
|
|
17615
|
+
() => closingKeys.size === 0 ? expandedSet : /* @__PURE__ */ new Set([...expandedSet, ...closingKeys]),
|
|
17616
|
+
[expandedSet, closingKeys]
|
|
17617
|
+
);
|
|
17618
|
+
const toggleExpanded = (row) => {
|
|
17619
|
+
const key = row[rowKey];
|
|
17620
|
+
const next = expandedSet.has(key) ? currentExpandedKeys.filter((k) => k !== key) : [...currentExpandedKeys, key];
|
|
17621
|
+
if (expandedKeys === void 0) setInnerExpandedKeys(next);
|
|
17622
|
+
onExpandedChange?.(next, row);
|
|
17623
|
+
};
|
|
17624
|
+
const expansionColIndex = !expansionOn ? -1 : expansionColumn == null ? 0 : visibleCols.findIndex((c) => c.name === expansionColumn);
|
|
17625
|
+
if (expansionColIndex >= 0) {
|
|
17626
|
+
const col = visibleCols[expansionColIndex];
|
|
17627
|
+
if (col?.renderCell) {
|
|
17628
|
+
throw new Error(
|
|
17629
|
+
`[STable] \uD3BC\uCE68 \uCEEC\uB7FC(${col.name})\uC5D0\uB294 renderCell \uC744 \uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. render \uB97C \uC4F0\uC138\uC694.`
|
|
17630
|
+
);
|
|
17631
|
+
}
|
|
17632
|
+
}
|
|
17491
17633
|
const headerGroupInfo = useMemo(() => {
|
|
17492
17634
|
if (!headerGroups || headerGroups.length === 0) return null;
|
|
17493
17635
|
const indexByName = new Map(visibleCols.map((col, index) => [col.name, index]));
|
|
@@ -17592,6 +17734,7 @@ var STableImpl = /* @__PURE__ */ forwardRef(function STable({
|
|
|
17592
17734
|
metricsRef.current ?? (metricsRef.current = createRowMetrics(0, effectiveRowHeight));
|
|
17593
17735
|
const metrics = metricsRef.current;
|
|
17594
17736
|
const measuredKeyRef = useRef("");
|
|
17737
|
+
const measuredExpansionRef = useRef(shownExpansionSet);
|
|
17595
17738
|
const pendingRowRef = useRef(null);
|
|
17596
17739
|
const pinnedTopRef = useRef(-1);
|
|
17597
17740
|
const lastEstimateRef = useRef(effectiveRowHeight);
|
|
@@ -17605,6 +17748,7 @@ var STableImpl = /* @__PURE__ */ forwardRef(function STable({
|
|
|
17605
17748
|
}
|
|
17606
17749
|
const [scrolledLeft, setScrolledLeft] = useState(false);
|
|
17607
17750
|
const [scrolledRight, setScrolledRight] = useState(false);
|
|
17751
|
+
const [viewportWidth, setViewportWidth] = useState(0);
|
|
17608
17752
|
const setRowCount = useCallback((count) => {
|
|
17609
17753
|
const safe = Math.max(0, Math.floor(Number.isFinite(count) ? count : 0));
|
|
17610
17754
|
lastReachEndRef.current = -1;
|
|
@@ -17630,6 +17774,7 @@ var STableImpl = /* @__PURE__ */ forwardRef(function STable({
|
|
|
17630
17774
|
setHeaderHeight(headerH);
|
|
17631
17775
|
setScrolledLeft(el.scrollLeft > 0);
|
|
17632
17776
|
setScrolledRight(el.scrollLeft + el.clientWidth < el.scrollWidth - 1);
|
|
17777
|
+
setViewportWidth(el.clientWidth);
|
|
17633
17778
|
if (virtualScroll) {
|
|
17634
17779
|
const { start, end } = calcRange(el.scrollTop, el.clientHeight - headerH);
|
|
17635
17780
|
setVsRange((prev) => prev.start === start && prev.end === end ? prev : { start, end });
|
|
@@ -17647,6 +17792,13 @@ var STableImpl = /* @__PURE__ */ forwardRef(function STable({
|
|
|
17647
17792
|
useEffect(() => {
|
|
17648
17793
|
handleScroll();
|
|
17649
17794
|
}, [handleScroll, rowCount, columnWidths, loading2, height]);
|
|
17795
|
+
useEffect(() => {
|
|
17796
|
+
const el = scrollRef.current;
|
|
17797
|
+
if (!expansionOn || !el || typeof ResizeObserver === "undefined") return;
|
|
17798
|
+
const observer = new ResizeObserver(() => handleScroll());
|
|
17799
|
+
observer.observe(el);
|
|
17800
|
+
return () => observer.disconnect();
|
|
17801
|
+
}, [expansionOn, handleScroll]);
|
|
17650
17802
|
const handleScrollRef = useRef(handleScroll);
|
|
17651
17803
|
handleScrollRef.current = handleScroll;
|
|
17652
17804
|
useIsomorphicLayoutEffect(() => {
|
|
@@ -17656,9 +17808,10 @@ var STableImpl = /* @__PURE__ */ forwardRef(function STable({
|
|
|
17656
17808
|
if (!el || m == null) return;
|
|
17657
17809
|
const pending2 = pendingRowRef.current;
|
|
17658
17810
|
const key = `${vsRange.start}:${vsRange.end}:${rowCount}`;
|
|
17659
|
-
const alreadyMeasured = measuredKeyRef.current === key;
|
|
17811
|
+
const alreadyMeasured = measuredKeyRef.current === key && measuredExpansionRef.current === shownExpansionSet;
|
|
17660
17812
|
if (alreadyMeasured && pending2 == null) return;
|
|
17661
17813
|
measuredKeyRef.current = key;
|
|
17814
|
+
measuredExpansionRef.current = shownExpansionSet;
|
|
17662
17815
|
const anchor = vsRange.start;
|
|
17663
17816
|
const anchorBefore = offsetOf(m, anchor);
|
|
17664
17817
|
let changed = false;
|
|
@@ -17666,7 +17819,7 @@ var STableImpl = /* @__PURE__ */ forwardRef(function STable({
|
|
|
17666
17819
|
for (const tr of el.querySelectorAll("tr[data-row-index]")) {
|
|
17667
17820
|
const index = Number(tr.dataset.rowIndex);
|
|
17668
17821
|
if (!Number.isInteger(index)) continue;
|
|
17669
|
-
const h = tr
|
|
17822
|
+
const h = rowBlockHeight(tr);
|
|
17670
17823
|
if (h <= 0) continue;
|
|
17671
17824
|
if (setRowSize(m, index, h)) changed = true;
|
|
17672
17825
|
}
|
|
@@ -17688,6 +17841,54 @@ var STableImpl = /* @__PURE__ */ forwardRef(function STable({
|
|
|
17688
17841
|
if (delta !== 0 && el.scrollTop > 0) el.scrollTop += delta;
|
|
17689
17842
|
handleScrollRef.current();
|
|
17690
17843
|
});
|
|
17844
|
+
const expansionMotionRef = useRef(null);
|
|
17845
|
+
const prevExpansionRef = useRef(null);
|
|
17846
|
+
useIsomorphicLayoutEffect(() => {
|
|
17847
|
+
if (!expansionOn) return;
|
|
17848
|
+
const prev = prevExpansionRef.current;
|
|
17849
|
+
prevExpansionRef.current = { rows, keys: expandedSet };
|
|
17850
|
+
const running = expansionMotionRef.current;
|
|
17851
|
+
if (running?.done) {
|
|
17852
|
+
running.cancel();
|
|
17853
|
+
expansionMotionRef.current = null;
|
|
17854
|
+
}
|
|
17855
|
+
if (!prev || prev.keys === expandedSet) return;
|
|
17856
|
+
const added = new Set([...expandedSet].filter((key) => !prev.keys.has(key)));
|
|
17857
|
+
const removed = new Set([...prev.keys].filter((key) => !expandedSet.has(key)));
|
|
17858
|
+
if (added.size === 0 && removed.size === 0) return;
|
|
17859
|
+
let from = added.size > 0 ? 0 : 1;
|
|
17860
|
+
if (expansionMotionRef.current) {
|
|
17861
|
+
const current = expansionMotionRef.current;
|
|
17862
|
+
const reversing = current.to === 0 && sameKeys(added, current.keys) || current.to === 1 && sameKeys(removed, current.keys);
|
|
17863
|
+
if (reversing) from = current.openness();
|
|
17864
|
+
current.cancel();
|
|
17865
|
+
expansionMotionRef.current = null;
|
|
17866
|
+
}
|
|
17867
|
+
const scrollEl = scrollRef.current;
|
|
17868
|
+
const keys = added.size > 0 ? added : removed;
|
|
17869
|
+
const keyNames = new Set([...keys].map(String));
|
|
17870
|
+
const canAnimate = scrollEl != null && prev.rows === rows && motionAllowed() && (added.size === 0 || removed.size === 0);
|
|
17871
|
+
const motion = canAnimate ? startRowMotion({
|
|
17872
|
+
scrollEl,
|
|
17873
|
+
isInBlock: (tr) => tr.dataset.expansionRow != null && keyNames.has(tr.dataset.expansionKey ?? ""),
|
|
17874
|
+
blockKeys: keys,
|
|
17875
|
+
from,
|
|
17876
|
+
to: added.size > 0 ? 1 : 0
|
|
17877
|
+
}) : null;
|
|
17878
|
+
if (motion) {
|
|
17879
|
+
expansionMotionRef.current = motion;
|
|
17880
|
+
if (motion.to === 0) {
|
|
17881
|
+
void motion.finished.then((completed) => {
|
|
17882
|
+
if (!completed || expansionMotionRef.current !== motion) return;
|
|
17883
|
+
motion.done = true;
|
|
17884
|
+
setClosingKeys(NO_KEYS);
|
|
17885
|
+
});
|
|
17886
|
+
}
|
|
17887
|
+
} else if (closingKeys.size > 0) {
|
|
17888
|
+
setClosingKeys(NO_KEYS);
|
|
17889
|
+
}
|
|
17890
|
+
}, [expandedSet, closingKeys]);
|
|
17891
|
+
useEffect(() => () => expansionMotionRef.current?.cancel(), []);
|
|
17691
17892
|
useEffect(() => {
|
|
17692
17893
|
if (!virtualScroll) return;
|
|
17693
17894
|
cbRef.current.onVirtualUpdate?.({ from: vsRange.start, to: vsRange.end });
|
|
@@ -17744,7 +17945,7 @@ var STableImpl = /* @__PURE__ */ forwardRef(function STable({
|
|
|
17744
17945
|
if (virtualScroll && m != null) return indexAtOffset(m, el.scrollTop);
|
|
17745
17946
|
const top = el.scrollTop;
|
|
17746
17947
|
for (const tr of el.querySelectorAll("tr[data-row-index]")) {
|
|
17747
|
-
if (tr.offsetTop + tr
|
|
17948
|
+
if (tr.offsetTop + rowBlockHeight(tr) > top) return Number(tr.dataset.rowIndex) || 0;
|
|
17748
17949
|
}
|
|
17749
17950
|
return 0;
|
|
17750
17951
|
},
|
|
@@ -18072,7 +18273,8 @@ var STableImpl = /* @__PURE__ */ forwardRef(function STable({
|
|
|
18072
18273
|
{
|
|
18073
18274
|
value: headerCheck,
|
|
18074
18275
|
disabled: !hasSelectableRow,
|
|
18075
|
-
onValueChange: toggleAll
|
|
18276
|
+
onValueChange: toggleAll,
|
|
18277
|
+
ariaLabel: selectAllLabel
|
|
18076
18278
|
}
|
|
18077
18279
|
) })
|
|
18078
18280
|
}
|
|
@@ -18118,7 +18320,8 @@ var STableImpl = /* @__PURE__ */ forwardRef(function STable({
|
|
|
18118
18320
|
{
|
|
18119
18321
|
value: headerCheck,
|
|
18120
18322
|
disabled: !hasSelectableRow,
|
|
18121
|
-
onValueChange: toggleAll
|
|
18323
|
+
onValueChange: toggleAll,
|
|
18324
|
+
ariaLabel: selectAllLabel
|
|
18122
18325
|
}
|
|
18123
18326
|
) }),
|
|
18124
18327
|
/* @__PURE__ */ jsx(
|
|
@@ -18318,112 +18521,168 @@ var STableImpl = /* @__PURE__ */ forwardRef(function STable({
|
|
|
18318
18521
|
const rowLocked = (selectable || dragSelectable) && !canSelectRow(row);
|
|
18319
18522
|
const rowBg = "bg-white";
|
|
18320
18523
|
const rowHover = hoverable && !rowLocked;
|
|
18321
|
-
|
|
18322
|
-
|
|
18323
|
-
|
|
18324
|
-
"
|
|
18325
|
-
|
|
18326
|
-
|
|
18327
|
-
|
|
18328
|
-
|
|
18329
|
-
|
|
18330
|
-
|
|
18331
|
-
|
|
18332
|
-
|
|
18333
|
-
|
|
18334
|
-
|
|
18335
|
-
|
|
18336
|
-
|
|
18337
|
-
(
|
|
18338
|
-
dragSelectOn
|
|
18339
|
-
|
|
18340
|
-
|
|
18341
|
-
|
|
18342
|
-
|
|
18343
|
-
|
|
18344
|
-
"
|
|
18345
|
-
|
|
18346
|
-
|
|
18347
|
-
|
|
18348
|
-
|
|
18524
|
+
const expansionShown = expansionOn && shownExpansionSet.has(row[rowKey]);
|
|
18525
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
18526
|
+
/* @__PURE__ */ jsxs(
|
|
18527
|
+
"tr",
|
|
18528
|
+
{
|
|
18529
|
+
"data-row-index": rowIndex,
|
|
18530
|
+
onClick: onRowClick ? (event) => {
|
|
18531
|
+
const target = event.target;
|
|
18532
|
+
if (target.closest(ROW_INTERACTIVE_SELECTOR)) return;
|
|
18533
|
+
onRowClick(row);
|
|
18534
|
+
} : void 0,
|
|
18535
|
+
onDoubleClick: onRowDoubleClick ? (event) => {
|
|
18536
|
+
const target = event.target;
|
|
18537
|
+
if (target.closest(ROW_INTERACTIVE_SELECTOR)) return;
|
|
18538
|
+
onRowDoubleClick(row);
|
|
18539
|
+
} : void 0,
|
|
18540
|
+
onMouseDown: dragSelectOn ? (event) => startDragSelect(rowIndex, event) : void 0,
|
|
18541
|
+
onMouseEnter: dragSelectOn ? () => extendDragSelect(rowIndex) : void 0,
|
|
18542
|
+
onContextMenu: contextMenuOn ? (event) => openContextMenu(row, event) : void 0,
|
|
18543
|
+
className: cn(
|
|
18544
|
+
"group/table-row",
|
|
18545
|
+
rowHover && "hover:bg-[var(--color-grey-05)]",
|
|
18546
|
+
(onRowClick || onRowDoubleClick) && "cursor-pointer",
|
|
18547
|
+
dragSelectOn && "select-none",
|
|
18548
|
+
rowClassName?.(row)
|
|
18549
|
+
),
|
|
18550
|
+
style: { height: virtualScroll ? effectiveRowHeight : rowH },
|
|
18551
|
+
children: [
|
|
18552
|
+
selectable && /* @__PURE__ */ jsx(
|
|
18553
|
+
"td",
|
|
18554
|
+
{
|
|
18555
|
+
className: cn(
|
|
18556
|
+
// 원본 .td--selected: 48px 고정폭, 항상 left sticky, 체크박스 중앙정렬
|
|
18557
|
+
"sticky left-0 z-[2] border-b border-solid border-[color:var(--cmp-table-border-color)] align-middle",
|
|
18558
|
+
rowBg,
|
|
18559
|
+
rowHover && "group-hover/table-row:bg-[var(--color-grey-05)]",
|
|
18560
|
+
stickyLeft === 0 && scrolledLeft && "shadow-[5px_0_8px_0_rgba(34,34,34,0.1)]"
|
|
18561
|
+
),
|
|
18562
|
+
style: {
|
|
18563
|
+
width: SELECTABLE_COLUMN_WIDTH,
|
|
18564
|
+
minWidth: SELECTABLE_COLUMN_WIDTH,
|
|
18565
|
+
maxWidth: SELECTABLE_COLUMN_WIDTH,
|
|
18566
|
+
// 선택 열도 행의 일부다 — 여기만 희지 않으면 회색 줄이 끊긴다
|
|
18567
|
+
background: rowLocked ? LOCKED_BG : void 0
|
|
18568
|
+
},
|
|
18569
|
+
onClick: (e) => e.stopPropagation(),
|
|
18570
|
+
onDoubleClick: (e) => e.stopPropagation(),
|
|
18571
|
+
onClickCapture: (e) => {
|
|
18572
|
+
shiftPressedRef.current = e.shiftKey;
|
|
18573
|
+
if (e.shiftKey) window.getSelection()?.removeAllRanges();
|
|
18574
|
+
},
|
|
18575
|
+
children: /* @__PURE__ */ jsx("div", { className: "flex select-none items-center justify-center", children: /* @__PURE__ */ jsx(
|
|
18576
|
+
SCheckbox,
|
|
18577
|
+
{
|
|
18578
|
+
value: isSel || !isRowIndeterminate?.(row) ? isSel : null,
|
|
18579
|
+
disabled: !canSelectRow(row),
|
|
18580
|
+
onValueChange: () => toggleRow(row, rowOffset + ri),
|
|
18581
|
+
ariaLabel: rowSelectLabel?.(row) ?? "\uD589 \uC120\uD0DD"
|
|
18582
|
+
}
|
|
18583
|
+
) })
|
|
18584
|
+
}
|
|
18585
|
+
),
|
|
18586
|
+
visibleCols.map((col, i) => {
|
|
18587
|
+
const tdClassName = cn(
|
|
18588
|
+
// 원본 .td: 컬럼 폭에 맞춰 내용 말줄임(overflow hidden + ellipsis) + 행 구분선(border-b)
|
|
18589
|
+
// 셀 배경은 흰색으로 채워 뒤 배경이 비치지 않게 하고, hover 시 행 배경(grey_05)을 따른다.
|
|
18590
|
+
"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)]",
|
|
18349
18591
|
rowBg,
|
|
18350
18592
|
rowHover && "group-hover/table-row:bg-[var(--color-grey-05)]",
|
|
18351
|
-
|
|
18352
|
-
)
|
|
18353
|
-
|
|
18354
|
-
|
|
18355
|
-
|
|
18356
|
-
|
|
18357
|
-
|
|
18358
|
-
|
|
18359
|
-
|
|
18360
|
-
|
|
18361
|
-
|
|
18362
|
-
|
|
18363
|
-
|
|
18364
|
-
|
|
18365
|
-
|
|
18366
|
-
|
|
18367
|
-
|
|
18593
|
+
typeof col.tdClass === "function" ? col.tdClass(row) : col.tdClass
|
|
18594
|
+
);
|
|
18595
|
+
const tdPadX = cellPadXOf(col);
|
|
18596
|
+
const dragEdges = dragSel ? [
|
|
18597
|
+
dragTop && `inset 0 ${DRAG_EDGE_W} 0 0 ${DRAG_EDGE_C}`,
|
|
18598
|
+
dragBottom && `inset 0 ${DRAG_EDGE_NEG_W} 0 0 ${DRAG_EDGE_C}`,
|
|
18599
|
+
i === 0 && `inset ${DRAG_EDGE_W} 0 0 0 ${DRAG_EDGE_C}`,
|
|
18600
|
+
i === visibleCols.length - 1 && `inset ${DRAG_EDGE_NEG_W} 0 0 0 ${DRAG_EDGE_C}`
|
|
18601
|
+
].filter(Boolean) : [];
|
|
18602
|
+
const shadows = [...dragEdges, stickyShadowValue(i)].filter(Boolean);
|
|
18603
|
+
const tdStyle = {
|
|
18604
|
+
paddingLeft: tdPadX,
|
|
18605
|
+
paddingRight: tdPadX,
|
|
18606
|
+
paddingTop: cellPadY,
|
|
18607
|
+
paddingBottom: cellPadY,
|
|
18608
|
+
textAlign: col.align ?? "left",
|
|
18609
|
+
// 인라인이라 hover 배경보다 세다 — 고른 행은 hover 로 흐려지지 않는다.
|
|
18610
|
+
background: dragSel ? DRAG_BG : rowLocked ? LOCKED_BG : void 0,
|
|
18611
|
+
// 클래스의 기본 글자색을 덮는다. 셀이 자기 색을 정한 내용(SIcon 의
|
|
18612
|
+
// color, STag 등)까지는 닿지 않는다 — 그건 소비 앱 몫이다.
|
|
18613
|
+
color: rowLocked ? LOCKED_CONTENT : void 0,
|
|
18614
|
+
boxShadow: shadows.length > 0 ? shadows.join(", ") : void 0,
|
|
18615
|
+
...cellStyle(i)
|
|
18616
|
+
};
|
|
18617
|
+
if (col.renderCell) {
|
|
18618
|
+
const cell = col.renderCell({
|
|
18619
|
+
row,
|
|
18620
|
+
value: cellValue(col, row),
|
|
18621
|
+
column: col,
|
|
18622
|
+
colIndex: i,
|
|
18623
|
+
rowIndex: ri,
|
|
18624
|
+
isSelected: isSel,
|
|
18625
|
+
className: tdClassName,
|
|
18626
|
+
style: tdStyle
|
|
18627
|
+
});
|
|
18628
|
+
if (cell == null || cell === false) return null;
|
|
18629
|
+
return /* @__PURE__ */ jsx(Fragment$1, { children: cell }, col.name);
|
|
18630
|
+
}
|
|
18631
|
+
const content = col.render ? col.render(row, cellValue(col, row)) : cellValue(col, row);
|
|
18632
|
+
if (i === expansionColIndex) {
|
|
18633
|
+
return /* @__PURE__ */ jsx(
|
|
18634
|
+
"td",
|
|
18635
|
+
{
|
|
18636
|
+
className: cn(tdClassName, "cursor-pointer"),
|
|
18637
|
+
style: tdStyle,
|
|
18638
|
+
onClick: (event) => {
|
|
18639
|
+
if (isOwnControl(event.target, event.currentTarget)) return;
|
|
18640
|
+
event.stopPropagation();
|
|
18641
|
+
toggleExpanded(row);
|
|
18642
|
+
},
|
|
18643
|
+
onDoubleClick: (event) => event.stopPropagation(),
|
|
18644
|
+
children: /* @__PURE__ */ jsx(ExpansionToggleCell, { expanded: isRowExpanded(row), children: content })
|
|
18645
|
+
},
|
|
18646
|
+
col.name
|
|
18647
|
+
);
|
|
18648
|
+
}
|
|
18649
|
+
return /* @__PURE__ */ jsx("td", { className: tdClassName, style: tdStyle, children: content }, col.name);
|
|
18650
|
+
})
|
|
18651
|
+
]
|
|
18652
|
+
}
|
|
18653
|
+
),
|
|
18654
|
+
expansionShown && // 상세 영역 — 행이 아니므로 data-row-index 를 달지 않는다 (행 수·선택·실측 대상 밖)
|
|
18655
|
+
/* @__PURE__ */ jsx(
|
|
18656
|
+
"tr",
|
|
18657
|
+
{
|
|
18658
|
+
"data-expansion-row": "",
|
|
18659
|
+
"data-expansion-key": String(row[rowKey]),
|
|
18660
|
+
className: expandedSet.has(row[rowKey]) ? void 0 : "pointer-events-none",
|
|
18661
|
+
children: /* @__PURE__ */ jsx(
|
|
18662
|
+
"td",
|
|
18663
|
+
{
|
|
18664
|
+
colSpan: totalColSpan,
|
|
18665
|
+
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)]",
|
|
18666
|
+
children: /* @__PURE__ */ jsx(
|
|
18667
|
+
"div",
|
|
18368
18668
|
{
|
|
18369
|
-
|
|
18370
|
-
|
|
18371
|
-
|
|
18669
|
+
className: "sticky left-0 box-border min-w-0",
|
|
18670
|
+
style: {
|
|
18671
|
+
// 가로 스크롤이 있어도 보이는 폭에 머문다. 재기 전(0)에는 표 폭을 따른다
|
|
18672
|
+
width: viewportWidth > 0 ? viewportWidth : void 0,
|
|
18673
|
+
paddingLeft: "var(--cmp-table-body-paddingX-wide)",
|
|
18674
|
+
paddingRight: "var(--cmp-table-body-paddingX-wide)",
|
|
18675
|
+
paddingTop: cellPadY,
|
|
18676
|
+
paddingBottom: cellPadY
|
|
18677
|
+
},
|
|
18678
|
+
children: renderExpansion?.(row)
|
|
18372
18679
|
}
|
|
18373
|
-
)
|
|
18374
|
-
}
|
|
18375
|
-
),
|
|
18376
|
-
visibleCols.map((col, i) => {
|
|
18377
|
-
const tdClassName = cn(
|
|
18378
|
-
// 원본 .td: 컬럼 폭에 맞춰 내용 말줄임(overflow hidden + ellipsis) + 행 구분선(border-b)
|
|
18379
|
-
// 셀 배경은 흰색으로 채워 뒤 배경이 비치지 않게 하고, hover 시 행 배경(grey_05)을 따른다.
|
|
18380
|
-
"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)]",
|
|
18381
|
-
rowBg,
|
|
18382
|
-
rowHover && "group-hover/table-row:bg-[var(--color-grey-05)]",
|
|
18383
|
-
typeof col.tdClass === "function" ? col.tdClass(row) : col.tdClass
|
|
18384
|
-
);
|
|
18385
|
-
const tdPadX = cellPadXOf(col);
|
|
18386
|
-
const dragEdges = dragSel ? [
|
|
18387
|
-
dragTop && `inset 0 ${DRAG_EDGE_W} 0 0 ${DRAG_EDGE_C}`,
|
|
18388
|
-
dragBottom && `inset 0 ${DRAG_EDGE_NEG_W} 0 0 ${DRAG_EDGE_C}`,
|
|
18389
|
-
i === 0 && `inset ${DRAG_EDGE_W} 0 0 0 ${DRAG_EDGE_C}`,
|
|
18390
|
-
i === visibleCols.length - 1 && `inset ${DRAG_EDGE_NEG_W} 0 0 0 ${DRAG_EDGE_C}`
|
|
18391
|
-
].filter(Boolean) : [];
|
|
18392
|
-
const shadows = [...dragEdges, stickyShadowValue(i)].filter(Boolean);
|
|
18393
|
-
const tdStyle = {
|
|
18394
|
-
paddingLeft: tdPadX,
|
|
18395
|
-
paddingRight: tdPadX,
|
|
18396
|
-
paddingTop: cellPadY,
|
|
18397
|
-
paddingBottom: cellPadY,
|
|
18398
|
-
textAlign: col.align ?? "left",
|
|
18399
|
-
// 인라인이라 hover 배경보다 세다 — 고른 행은 hover 로 흐려지지 않는다.
|
|
18400
|
-
background: dragSel ? DRAG_BG : rowLocked ? LOCKED_BG : void 0,
|
|
18401
|
-
// 클래스의 기본 글자색을 덮는다. 셀이 자기 색을 정한 내용(SIcon 의
|
|
18402
|
-
// color, STag 등)까지는 닿지 않는다 — 그건 소비 앱 몫이다.
|
|
18403
|
-
color: rowLocked ? LOCKED_CONTENT : void 0,
|
|
18404
|
-
boxShadow: shadows.length > 0 ? shadows.join(", ") : void 0,
|
|
18405
|
-
...cellStyle(i)
|
|
18406
|
-
};
|
|
18407
|
-
if (col.renderCell) {
|
|
18408
|
-
const cell = col.renderCell({
|
|
18409
|
-
row,
|
|
18410
|
-
value: cellValue(col, row),
|
|
18411
|
-
column: col,
|
|
18412
|
-
colIndex: i,
|
|
18413
|
-
rowIndex: ri,
|
|
18414
|
-
isSelected: isSel,
|
|
18415
|
-
className: tdClassName,
|
|
18416
|
-
style: tdStyle
|
|
18417
|
-
});
|
|
18418
|
-
if (cell == null || cell === false) return null;
|
|
18419
|
-
return /* @__PURE__ */ jsx(Fragment$1, { children: cell }, col.name);
|
|
18680
|
+
)
|
|
18420
18681
|
}
|
|
18421
|
-
|
|
18422
|
-
|
|
18423
|
-
|
|
18424
|
-
|
|
18425
|
-
row[rowKey] ?? ri
|
|
18426
|
-
);
|
|
18682
|
+
)
|
|
18683
|
+
}
|
|
18684
|
+
)
|
|
18685
|
+
] }, row[rowKey] ?? ri);
|
|
18427
18686
|
}),
|
|
18428
18687
|
virtualScroll && bottomSpacer > 0 && /* @__PURE__ */ jsx("tr", { "aria-hidden": true, style: { height: bottomSpacer }, children: /* @__PURE__ */ jsx("td", { colSpan: totalColSpan, className: "p-0" }) })
|
|
18429
18688
|
] })
|
|
@@ -18549,6 +18808,26 @@ var STableImpl = /* @__PURE__ */ forwardRef(function STable({
|
|
|
18549
18808
|
);
|
|
18550
18809
|
});
|
|
18551
18810
|
var STable2 = STableImpl;
|
|
18811
|
+
function isOwnControl(target, cell) {
|
|
18812
|
+
if (!(target instanceof Element)) return false;
|
|
18813
|
+
if (target.closest("[data-expansion-toggle]")) return false;
|
|
18814
|
+
const control = target.closest(ROW_INTERACTIVE_SELECTOR);
|
|
18815
|
+
return control != null && cell.contains(control);
|
|
18816
|
+
}
|
|
18817
|
+
function ExpansionToggleCell({ expanded, children }) {
|
|
18818
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-(--cmp-tree-item-contentGap)", children: [
|
|
18819
|
+
/* @__PURE__ */ jsx("span", { "data-expansion-toggle": true, className: "flex shrink-0", children: /* @__PURE__ */ jsx(
|
|
18820
|
+
SGhostButton,
|
|
18821
|
+
{
|
|
18822
|
+
icon: expanded ? "caretDown" : "caretRight",
|
|
18823
|
+
size: "xxs",
|
|
18824
|
+
ariaLabel: expanded ? "collapse row" : "expand row",
|
|
18825
|
+
ariaExpanded: expanded
|
|
18826
|
+
}
|
|
18827
|
+
) }),
|
|
18828
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children })
|
|
18829
|
+
] });
|
|
18830
|
+
}
|
|
18552
18831
|
var COUNT_NULL = "var(--cmp-table-bar-count-null)";
|
|
18553
18832
|
var totalColor = (n) => n > 0 ? "var(--cmp-table-bar-count-total)" : COUNT_NULL;
|
|
18554
18833
|
var selectedColor = (n) => n > 0 ? "var(--color-brilliantblue-75)" : COUNT_NULL;
|
|
@@ -18617,9 +18896,7 @@ var STableBar = /* @__PURE__ */ forwardRef(function STableBar2({ title, total, s
|
|
|
18617
18896
|
}
|
|
18618
18897
|
);
|
|
18619
18898
|
});
|
|
18620
|
-
var
|
|
18621
|
-
var EXPAND_MOTION = { duration: 220, easing: "ease-out" };
|
|
18622
|
-
var COLLAPSE_MOTION = { duration: 140, easing: "ease-in" };
|
|
18899
|
+
var NO_KEYS2 = /* @__PURE__ */ new Set();
|
|
18623
18900
|
function STreeTable({
|
|
18624
18901
|
rows = [],
|
|
18625
18902
|
columns = [],
|
|
@@ -18672,11 +18949,11 @@ function STreeTable({
|
|
|
18672
18949
|
[rows, expandedSet, rowKey, childrenKey]
|
|
18673
18950
|
);
|
|
18674
18951
|
const tableRef = useRef(null);
|
|
18675
|
-
const [closingKeys, setClosingKeys] = useState(
|
|
18952
|
+
const [closingKeys, setClosingKeys] = useState(NO_KEYS2);
|
|
18676
18953
|
const [prevExpand, setPrevExpand] = useState({ rows, expandedSet });
|
|
18677
18954
|
if (prevExpand.rows !== rows || prevExpand.expandedSet !== expandedSet) {
|
|
18678
18955
|
setPrevExpand({ rows, expandedSet });
|
|
18679
|
-
let nextClosing =
|
|
18956
|
+
let nextClosing = NO_KEYS2;
|
|
18680
18957
|
if (prevExpand.rows === rows && motionAllowed()) {
|
|
18681
18958
|
const collapsed = [...prevExpand.expandedSet].filter((key) => !expandedSet.has(key));
|
|
18682
18959
|
const expanded = [...expandedSet].filter((key) => !prevExpand.expandedSet.has(key));
|
|
@@ -18725,11 +19002,15 @@ function STreeTable({
|
|
|
18725
19002
|
motionRef.current = null;
|
|
18726
19003
|
}
|
|
18727
19004
|
const scrollEl = tableRef.current?.getScrollElement();
|
|
19005
|
+
const rowKeys = renderedRows.map(keyOf);
|
|
18728
19006
|
const keys = added.size > 0 ? added : removed;
|
|
18729
19007
|
const canAnimate = scrollEl != null && motionAllowed() && (added.size === 0 || removed.size === 0);
|
|
18730
19008
|
const motion = canAnimate ? startRowMotion({
|
|
18731
19009
|
scrollEl,
|
|
18732
|
-
|
|
19010
|
+
isInBlock: (tr) => {
|
|
19011
|
+
const key = rowKeys[Number(tr.dataset.rowIndex)];
|
|
19012
|
+
return key !== void 0 && keys.has(key);
|
|
19013
|
+
},
|
|
18733
19014
|
blockKeys: keys,
|
|
18734
19015
|
from,
|
|
18735
19016
|
to: added.size > 0 ? 1 : 0
|
|
@@ -18740,11 +19021,11 @@ function STreeTable({
|
|
|
18740
19021
|
void motion.finished.then((completed) => {
|
|
18741
19022
|
if (!completed || motionRef.current !== motion) return;
|
|
18742
19023
|
motion.done = true;
|
|
18743
|
-
setClosingKeys(
|
|
19024
|
+
setClosingKeys(NO_KEYS2);
|
|
18744
19025
|
});
|
|
18745
19026
|
}
|
|
18746
19027
|
} else if (closingKeys.size > 0) {
|
|
18747
|
-
setClosingKeys(
|
|
19028
|
+
setClosingKeys(NO_KEYS2);
|
|
18748
19029
|
}
|
|
18749
19030
|
}, [renderedRows]);
|
|
18750
19031
|
useEffect(() => () => motionRef.current?.cancel(), []);
|
|
@@ -18817,7 +19098,7 @@ function STreeTable({
|
|
|
18817
19098
|
className: cn(className, hasChildren && "cursor-pointer"),
|
|
18818
19099
|
style,
|
|
18819
19100
|
onClick: hasChildren ? (event) => {
|
|
18820
|
-
if (
|
|
19101
|
+
if (isOwnControl2(event.target, event.currentTarget)) return;
|
|
18821
19102
|
event.stopPropagation();
|
|
18822
19103
|
toggleExpanded(row);
|
|
18823
19104
|
} : void 0,
|
|
@@ -18872,96 +19153,8 @@ function flattenRows(nodes, isOpen, childrenOf) {
|
|
|
18872
19153
|
walk(nodes);
|
|
18873
19154
|
return out;
|
|
18874
19155
|
}
|
|
18875
|
-
function sameKeys(a, b) {
|
|
18876
|
-
return a.size === b.size && [...a].every((key) => b.has(key));
|
|
18877
|
-
}
|
|
18878
|
-
function motionAllowed() {
|
|
18879
|
-
if (typeof window === "undefined" || typeof Element.prototype.animate !== "function")
|
|
18880
|
-
return false;
|
|
18881
|
-
return !window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
|
|
18882
|
-
}
|
|
18883
|
-
function startRowMotion({
|
|
18884
|
-
scrollEl,
|
|
18885
|
-
rowKeys,
|
|
18886
|
-
blockKeys,
|
|
18887
|
-
from,
|
|
18888
|
-
to
|
|
18889
|
-
}) {
|
|
18890
|
-
const spec = to === 1 ? EXPAND_MOTION : COLLAPSE_MOTION;
|
|
18891
|
-
const duration = spec.duration * Math.abs(to - from);
|
|
18892
|
-
if (duration < 1) return null;
|
|
18893
|
-
const trs = [...scrollEl.querySelectorAll("tr[data-row-index]")].map((tr) => {
|
|
18894
|
-
const key = rowKeys[Number(tr.dataset.rowIndex)];
|
|
18895
|
-
return {
|
|
18896
|
-
tr,
|
|
18897
|
-
inBlock: key !== void 0 && blockKeys.has(key),
|
|
18898
|
-
height: tr.getBoundingClientRect().height
|
|
18899
|
-
};
|
|
18900
|
-
});
|
|
18901
|
-
const viewBottom = scrollEl.scrollTop + scrollEl.clientHeight;
|
|
18902
|
-
const openAt = (offset) => from + (to - from) * offset;
|
|
18903
|
-
const translate = (shift2, s) => `translateY(${-shift2 * (1 - s)}px)`;
|
|
18904
|
-
const timing = {
|
|
18905
|
-
duration,
|
|
18906
|
-
easing: spec.easing,
|
|
18907
|
-
// 접힘은 남겨 둔 행이 빠질 때까지 끝 위치를 붙잡는다 — 놓으면 그 사이 한 프레임 제자리로 튄다
|
|
18908
|
-
fill: to === 0 ? "forwards" : "none"
|
|
18909
|
-
};
|
|
18910
|
-
const animations = [];
|
|
18911
|
-
let shift = 0;
|
|
18912
|
-
let blockHeight = 0;
|
|
18913
|
-
let y = 0;
|
|
18914
|
-
trs.forEach(({ tr, inBlock, height }, i) => {
|
|
18915
|
-
if (inBlock && !trs[i - 1]?.inBlock) {
|
|
18916
|
-
blockHeight = 0;
|
|
18917
|
-
for (let j = i; j < trs.length && trs[j].inBlock; j++) blockHeight += trs[j].height;
|
|
18918
|
-
shift += blockHeight;
|
|
18919
|
-
y = 0;
|
|
18920
|
-
}
|
|
18921
|
-
if (shift === 0 || tr.offsetTop - shift > viewBottom) return;
|
|
18922
|
-
if (!inBlock) {
|
|
18923
|
-
animations.push(
|
|
18924
|
-
tr.animate(
|
|
18925
|
-
[{ transform: translate(shift, from) }, { transform: translate(shift, to) }],
|
|
18926
|
-
timing
|
|
18927
|
-
)
|
|
18928
|
-
);
|
|
18929
|
-
return;
|
|
18930
|
-
}
|
|
18931
|
-
const rowY = y;
|
|
18932
|
-
const clipAt = (s) => Math.min(height, Math.max(0, blockHeight * (1 - s) - rowY));
|
|
18933
|
-
const bends = [1 - rowY / blockHeight, 1 - (rowY + height) / blockHeight].map((s) => (s - from) / (to - from)).filter((offset) => offset > 0 && offset < 1);
|
|
18934
|
-
const offsets = [0, ...bends, 1].sort((a, b) => a - b);
|
|
18935
|
-
animations.push(
|
|
18936
|
-
tr.animate(
|
|
18937
|
-
offsets.map((offset) => ({
|
|
18938
|
-
offset,
|
|
18939
|
-
transform: translate(shift, openAt(offset)),
|
|
18940
|
-
clipPath: `inset(${clipAt(openAt(offset))}px 0 0 0)`
|
|
18941
|
-
})),
|
|
18942
|
-
timing
|
|
18943
|
-
)
|
|
18944
|
-
);
|
|
18945
|
-
y += height;
|
|
18946
|
-
});
|
|
18947
|
-
if (animations.length === 0) return null;
|
|
18948
|
-
return {
|
|
18949
|
-
keys: blockKeys,
|
|
18950
|
-
to,
|
|
18951
|
-
done: false,
|
|
18952
|
-
finished: Promise.all(animations.map((animation) => animation.finished)).then(
|
|
18953
|
-
() => true,
|
|
18954
|
-
() => false
|
|
18955
|
-
),
|
|
18956
|
-
openness: () => {
|
|
18957
|
-
const progress = animations[0].effect?.getComputedTiming().progress;
|
|
18958
|
-
return progress == null ? to : openAt(progress);
|
|
18959
|
-
},
|
|
18960
|
-
cancel: () => animations.forEach((animation) => animation.cancel())
|
|
18961
|
-
};
|
|
18962
|
-
}
|
|
18963
19156
|
var OWN_CONTROL_SELECTOR = 'a, button, input, select, textarea, label, [role="button"], [role="checkbox"], [contenteditable="true"]';
|
|
18964
|
-
function
|
|
19157
|
+
function isOwnControl2(target, cell) {
|
|
18965
19158
|
if (!(target instanceof Element)) return false;
|
|
18966
19159
|
if (target.closest("[data-tree-toggle]")) return false;
|
|
18967
19160
|
const control = target.closest(OWN_CONTROL_SELECTOR);
|